Mockito教程
Mockito是基于Java的模拟框架,可与其他测试框架(例如JUnit和TestNG)结合使用。
它在内部使用Java Reflection API,并允许创建服务对象。
模拟对象返回伪数据,并避免外部依赖关系。
它通过模拟外部依赖项简化了测试的开发,并将模拟应用于要测试的代码。
Mockito教程
对于Mockito教程,我们将使用JUnit 5并创建一些模拟服务。
Mockito Maven依赖关系
要在项目中实现基于Mockito的测试用例,请将以下依赖项添加到项目的pom.xml文件中:
<dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>2.19.0</version> <scope>test</scope> </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-junit-jupiter</artifactId> <version>2.19.0</version> <scope>test</scope> </dependency>
注意,对于JUnit 5,mockito-junit-jupiter
是必需的,如果您使用的是其他测试框架,例如JUnit 4或者TestNG,则可以删除此依赖项,而仅包括mockito-core
依赖项。
Mockito模拟创作
Mockito框架允许我们使用@Mock批注或者static方法mock()创建模拟对象。
Mockito mock()方法
下面的示例演示了mock()方法的用法:
package com.theitroad.mockito; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.when; import org.junit.jupiter.api.Test; import org.mockito.Mockito; import com.theitroad.AddService; import com.theitroad.CalcService; public class CalcService1Test { @Test void testCalc() { System.out.println("**--- Test testCalc executed ---**"); AddService addService; CalcService calcService; addService = Mockito.mock(AddService.class); calcService = new CalcService(addService); int num1 = 11; int num2 = 12; int expected = 23; when(addService.add(num1, num2)).thenReturn(expected); int actual = calcService.calc(num1, num2); assertEquals(expected, actual); } }
在上面的示例中,我们正在测试CalcService。
Mockito.mock()方法用于创建AddService类的模拟对象。
Mockito模拟注解
下面的示例显示@Mock注释的用法。
package com.theitroad.mockito; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.when; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import com.theitroad.AddService; import com.theitroad.CalcService; public class CalcService2Test { CalcService calcService; @Mock AddService addService; @BeforeEach public void setup() { MockitoAnnotations.initMocks(this); } @Test public void testCalc() { System.out.println("**--- Test testCalc executed ---**"); calcService = new CalcService(addService); int num1 = 11; int num2 = 12; int expected = 23; when(addService.add(num1, num2)).thenReturn(expected); int actual = calcService.calc(num1, num2); assertEquals(expected, actual); } }
注意,我们需要调用MockitoAnnotations.initMocks(this);
来初始化用@ Mock,@ Spy,@ Captor或者@InjectMocks注释的对象。
Mockito行为验证
为了向模拟类when()
和thenReturn()
函数添加行为。
这意味着当使用(num1,num2)参数为添加方法调用模拟对象(addService)时,它将返回存储在预期变量中的值。
我们的CalcService类如下所示:
public class CalcService { private AddService addService; public CalcService(AddService addService) { this.addService = addService; } public int calc(int num1, int num2) { System.out.println("**--- CalcService calc executed ---**"); return addService.add(num1, num2); } }
CalcService依赖于AddService类。
它使用AddService类的add方法执行其操作。
由于我们只想对CalcService类进行单元测试,因此我们必须模拟AddService实例。
AddService如下所示:
public interface AddService { public int add(int num1, int num2); }
public class AddServiceImpl implements AddService { @Override public int add(int num1, int num2) { System.out.println("**--- AddServiceImpl add executed ---**"); return num1 + num2; } }
Mockito验证互动
Mockito框架跟踪对模拟对象的所有方法调用及其参数。
模拟对象上的Mockitoverify()
方法验证使用特定参数调用的方法。
我们还可以指定调用逻辑的数量,例如确切的次数,至少指定的次数,小于指定的次数等。
我们可以将" VerificationModeFactory"用于调用次数逻辑。
Mockito verify()方法检查是否使用正确的参数调用了一个方法。
它不会检查类似assert方法的方法调用的结果。
下面的示例演示了verify()方法的用法:
package com.theitroad.mockito; import static org.mockito.Mockito.verify; import java.util.List; import org.junit.jupiter.api.Test; import org.mockito.Mockito; import org.mockito.internal.verification.VerificationModeFactory; public class VerifyInteractionTest { @Test public void testMethod() { @SuppressWarnings("unchecked") List<String> mockedList = Mockito.mock(List.class); mockedList.add("first-element"); mockedList.add("second-element"); mockedList.add("third-element"); mockedList.add("third-element"); mockedList.clear(); verify(mockedList).add("first-element"); verify(mockedList).add("second-element"); verify(mockedList, VerificationModeFactory.times(2)).add("third-element"); verify(mockedList).clear(); } }
Mockito Stub具体程序
使用when()– thenReturn()函数,我们可以对具体/实现类以及集合的单个元素进行存根。
非存根元素将其中包含null。
package com.theitroad.mockito; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.util.ArrayList; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; public class MockSingleElementTest { @SuppressWarnings("unchecked") @Test public void testMethod() { ArrayList<String> mockedList = mock(ArrayList.class); when(mockedList.get(0)).thenReturn("first-element"); System.out.println(mockedList.get(0)); assertEquals("first-element", mockedList.get(0)); //"null" gets printed as get(1) is not stubbed System.out.println(mockedList.get(1)); } }
Mockito Spy
调用 Spy对象的方法时,除非定义了预定义的行为,否则将调用real方法。
使用 Spy,我们可以通过when()-theReturn()函数定义行为,或者可以调用实际实现。
package com.theitroad.mockito; 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 MockitoSpyTest { @Test public void testMethod() { List<String> list = new ArrayList<>(); List<String> listSpy = spy(list); listSpy.add("first-element"); System.out.println(listSpy.get(0)); assertEquals("first-element", listSpy.get(0)); when(listSpy.get(0)).thenReturn("second-element"); System.out.println(listSpy.get(0)); assertEquals("second-element", listSpy.get(0)); } }