웹사이트 검색

Mockito 모의 예제


Mockito 조롱 프레임워크는 클래스를 조롱하는 다양한 방법을 제공합니다. 클래스를 조롱하고 동작을 스텁할 수 있는 다양한 방법을 살펴보겠습니다.

Mockito 모의 방법

Mockito 클래스 mock() 메서드를 사용하여 주어진 클래스 또는 인터페이스의 목 객체를 만들 수 있습니다. 이것은 객체를 조롱하는 가장 간단한 방법입니다.

package com.journaldev.mockito.mock;

import java.util.List;

import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;

public class MockitoMockMethodExample {

	@SuppressWarnings("unchecked")
	@Test
	public void test() {
		// using Mockito.mock() method
		List<String> mockList = mock(List.class);
		when(mockList.size()).thenReturn(5);
		assertTrue(mockList.size()==5);
	}
	
}

우리는 JUnit 5를 사용하여 Mockito와 함께 테스트 케이스를 작성하여 객체를 조롱합니다.

Mockito @Mock 주석

@Mock 주석을 사용하여 객체를 조롱할 수 있으며, 조롱된 객체를 초기화하기 위해 MockitoAnnotations.initMocks(this)를 호출해야 합니다. 테스트 전에 실행되는 프레임워크 설정 메서드를 테스트할 때 이 작업을 수행할 수 있습니다.

package com.journaldev.mockito.mock;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

public class MockitoMockAnnotationExample {

	@Mock
	List<String> mockList;
	
	@BeforeEach
	public void setup() {
		//if we don't call below, we will get NullPointerException
		MockitoAnnotations.initMocks(this);
	}
	
	@SuppressWarnings("unchecked")
	@Test
	public void test() {
		when(mockList.get(0)).thenReturn("JournalDev");
		assertEquals("JournalDev", mockList.get(0));
	}
	
}

Mockito @InjectMocks 주석

조롱된 객체를 다른 조롱된 객체에 주입하고 싶을 때 @Mock을 사용할 수 있습니다.

package com.journaldev.mockito.mock;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

public class MockitoInjectMockAnnotationExample {

	@Mock
	List<String> mockList;
	
	//@InjectMock creates an instance of the class and 
	//injects the mocks that are marked with the annotations @Mock into it.
	@InjectMocks
	Fruits mockFruits;
	
	@BeforeEach
	public void setup() {
		//if we don't call below, we will get NullPointerException
		MockitoAnnotations.initMocks(this);
	}
	
	@SuppressWarnings("unchecked")
	@Test
	public void test() {
		when(mockList.get(0)).thenReturn("Apple");
		when(mockList.size()).thenReturn(1);
		assertEquals("Apple", mockList.get(0));
		assertEquals(1, mockList.size());
		
		//mockFruits names is using mockList, below asserts confirm it
		assertEquals("Apple", mockFruits.getNames().get(0));
		assertEquals(1, mockFruits.getNames().size());	
		
		mockList.add(1, "Mango");
		//below will print null because mockList.get(1) is not stubbed
		System.out.println(mockList.get(1));
	}
	
}

class Fruits{
	private List<String> names;

	public List<String> getNames() {
		return names;
	}

	public void setNames(List<String> names) {
		this.names = names;
	}
	
}

부분 조롱을 위한 Mockito spy()

특정 동작만 조롱하고 스텁되지 않은 동작에 대한 실제 메서드를 호출하려는 경우 Mockito spy() 메서드를 사용하여 스파이 개체를 만들 수 있습니다.

package com.journaldev.mockito.mock;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;

import java.util.ArrayList;
import java.util.List;

import org.junit.jupiter.api.Test;

public class MockitoSpyMethodExample {

	@Test
	public void test() {
		List<String> list = new ArrayList<>();
		List<String> spyOnList = spy(list);
		
		when(spyOnList.size()).thenReturn(10);
		assertEquals(10, spyOnList.size());
		
		//calling real methods since below methods are not stubbed
		spyOnList.add("Pankaj");
		spyOnList.add("Meghna");
		assertEquals("Pankaj", spyOnList.get(0));
		assertEquals("Meghna", spyOnList.get(1));
	}
	
}

Mockito @Spy 주석

객체를 감시하기 위해 @Spy 주석을 사용할 수 있습니다. 간단한 예를 살펴보겠습니다.

package com.journaldev.mockito.mock;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;

public class MockitoSpyAnnotationExample {

	@Spy
	Utils mockUtils;
	
	@BeforeEach
	public void setup() {
		MockitoAnnotations.initMocks(this);
	}
	
	@Test
	public void test() {
		when(mockUtils.process(1, 1)).thenReturn(5);
		//mocked method
		assertEquals(5, mockUtils.process(1, 1));
		//real method called since it's not stubbed
		assertEquals(20, mockUtils.process(19, 1));
		
	}
	
}

class Utils{
	public int process(int x, int y) {
		System.out.println("Input Params = "+x+","+y);
		return x+y;
	}
}

모의 개체를 초기화하는 생성자에 유의하십시오. 클래스에 없는 경우 다음 오류가 발생합니다.

org.mockito.exceptions.base.MockitoException: Unable to initialize @Spy annotated field 'mockUtils'.
Please ensure that the type 'Utils' has a no-arg constructor.
	at com.journaldev.mockito.mock.MockitoSpyAnnotationExample.setup(MockitoSpyAnnotationExample.java:18)

또한 Mockito는 내부 클래스, 로컬 클래스, 추상 클래스 및 인터페이스를 인스턴스화할 수 없습니다. 따라서 항상 감시할 인스턴스를 제공하는 것이 좋습니다. 그렇지 않으면 실제 메서드가 호출되지 않고 자동으로 무시될 수 있습니다. 예를 들어 아래와 같이 스파이 개체를 지정하는 경우:

@Spy
List<String> spyList;

add() 또는 get() 메서드를 호출할 때 실제 메서드가 호출되지 않는다는 것을 알 수 있습니다. 아래와 같이 스파이 개체를 지정하면 모든 것이 잘 작동합니다.

@Spy
List<String> spyList = new ArrayList<>();

요약

Mockito 조롱 프레임워크를 사용하면 다양한 방법과 주석을 통해 쉽게 목 객체를 만들 수 있습니다. 모의 객체를 다른 모의 객체에 주입할 수도 있는데, 이것은 매우 유용한 기능입니다.

GitHub 리포지토리에서 더 많은 Mockito 예제를 볼 수 있습니다.