天天看點

mockito單元測試示例_Mockito模拟示例

mockito單元測試示例

Mockito mocking framework provides different ways to mock a class. Let’s look at different methods through which we can mock a class and stub its behaviors.

Mockito模拟架構提供了模拟類的不同方法。 讓我們看一下可以模拟類并存根其行為的不同方法。

Mockito模拟方法 (Mockito mock method)

We can use Mockito class mock() method to create a mock object of a given class or interface. This is the simplest way to mock an object.

我們可以使用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);
	}
	
}
           

We are using JUnit 5 to write test cases in conjunction with Mockito to mock objects.

我們使用JUnit 5與Mockito一起編寫測試用例來模拟對象。

Mockito @模拟注解 (Mockito @Mock Annotation)

We can mock an object using @Mock annotation too. It’s useful when we want to use the mocked object at multiple places because we avoid calling mock() method multiple times. The code becomes more readable and we can specify mock object name that will be useful in case of errors.

我們也可以使用@Mock注釋來模拟對象。 當我們想在多個地方使用模拟對象時,這很有用,因為我們避免了多次調用mock()方法。 代碼變得更具可讀性,我們可以指定模拟對象名稱,以防出現錯誤。

When using @Mock annotation, we have to make sure that we call

MockitoAnnotations.initMocks(this)

to initialize the mocked object. We can do this in testing framework setup methods that are executed before the tests.

使用@Mock批注時,我們必須確定調用

MockitoAnnotations.initMocks(this)

來初始化

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批注 (Mockito @InjectMocks Annotation)

When we want to inject a mocked object into another mocked object, we can use @InjectMocks annotation. @InjectMock creates the mock object of the class and injects the mocks that are marked with the annotations @Mock into it.

當我們要将一個模拟對象注入另一個模拟對象時,可以使用@InjectMocks批注。 @InjectMock建立類的模拟對象,并将帶有注解@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() for partial mocking)

If we want to mock only specific behaviors and call the real methods for unstubbed behaviors, then we can create a spy object using Mockito spy() method.

如果我們隻想模拟特定的行為,并為未受幹擾的行為調用真實的方法,則可以使用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 @間諜注釋 (Mockito @Spy Annotation)

We can use @Spy annotation to spy on an object. Let’s look at a simple example.

我們可以使用@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;
	}
}
           

Note that the @Spy annotation tries to call the no-args constructor to initialized the mocked object. If your class doesn’t have it then you will get the following error.

請注意,@ Spy注釋會嘗試調用no-args 構造函數以初始化模拟對象。 如果您的班級沒有它,那麼您将收到以下錯誤。

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)
           

Also, note that Mockito cannot instantiate inner classes, local classes, abstract classes, and interfaces. So it’s always a good idea to provide an instance to spy on. Otherwise real methods might not get called and silently ignored.

另外,請注意,Mockito無法執行個體化内部類,局部類,抽象類和接口。 是以,提供一個執行個體進行監視始終是一個好主意。 否則,實際的方法可能不會被調用并被靜默忽略。

For example, if you specify a spy object as below:

例如,如果您指定一個間諜對象,如下所示:

@Spy
List<String> spyList;
           

You will notice that when you call

add()

or

get()

methods, real methods are not getting called. If you specify the spy object like below, then everything will work fine.

您會注意到,當您調用

add()

get()

方法時,不會調用實際方法。 如果您指定如下所示的間諜對象,那麼一切都會正常進行。

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

摘要 (Summary)

Mockito mocking framework allows us to create mock object easily through different methods and annotations. We can also inject a mock object into another mock object, this is a very useful feature.

Mockito模拟架構允許我們通過不同的方法和注釋輕松建立模拟對象。 我們還可以将一個模拟對象注入另一個模拟對象,這是一個非常有用的功能。

GitHub Repository. GitHub存儲庫中檢視更多Mockito示例。

翻譯自: https://www.journaldev.com/21866/mockito-mock-examples

mockito單元測試示例