Mockito 教程
Mockito是一个基于Java的模拟框架,与其他测试框架如JUnit和TestNG一起使用。它内部使用Java反射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的Mock创建
Mockito框架允许我们使用@Mock注解或mock()静态方法创建模拟对象。
Mockito的mock()方法
下面的例子展示了mock()方法的使用。
package com.Olivia.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.Olivia.AddService;
import com.Olivia.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注解
以下示例展示了@Mock注解的用法。
package com.Olivia.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.Olivia.AddService;
import com.Olivia.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()函数时,给模拟类添加行为。这意味着当调用模拟对象(addService)的add方法并传入(num1, num2)参数时,它将返回存储在expected变量中的值。我们的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框架会跟踪所有方法调用及其传递给模拟对象的参数。Mockito的verify()方法用于验证某个方法是否以指定的参数进行调用。我们还可以指定调用次数的逻辑,比如确切的调用次数、至少指定的调用次数、少于指定的调用次数等。我们可以使用VerificationModeFactory来处理调用次数的逻辑。Mockito的verify()方法用于验证某个方法是否以正确的参数进行调用。它不像assert方法那样检查方法调用的结果。下面的示例展示了verify()方法的使用方式:
package com.Olivia.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对具体类进行存根化。
使用 when() – thenReturn() 函数,我们可以对具体/实现类和集合的单个元素进行存根操作。未存根的元素将包含空值。
package com.Olivia.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 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,我们可以通过使用when()-theReturn()函数来定义行为,或者可以调用真实的实现。
package com.Olivia.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));
}
}
结论
Mockito是用于Java单元测试的流行的模拟框架。我们可以很容易地使用Mockito对依赖进行模拟。Mockito的编码风格流畅且类似于JUnit和TestNG框架,所以学习曲线很小。
您可以从我们的GitHub仓库下载完整的项目代码。