- **单元测试常用 -- Mock 框架**
- **Mockito 框架**
- **常用注解**
- **示例代码**
- **PowerMock 框架**
- **Mock 入参对象**
- **Mock 方法内部 new 出来的对象**
- **Mock 普通对象的 final 方法**
- **Mock 普通对象的静态方法、私有方法**
- **踩坑指南**
@Mock:功能类似于 Spring 的注解 @Autowied,但不会真的注入单例,而是表示这个类要被 mock。
@InjectMocks:表示将该类里面被 Mock 注解的类进行注入。
@RunWith(MockitoJUnitRunner.class)
示例代码import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.powermock.api.mockito.PowerMockito;
// Runwith 用来提供测试环境,@Mock 以及 @InjectMocks 注解需要在一定的环境下才能生效
@RunWith(MockitoJUnitRunner.class)
public class TestMockito {
// InjectMocks 注解。
// 功能:不仅会 PerformService,同时 PerformService 里面如果含有 Mock 的类,Mockito 框架会帮我们进行自动注入
@InjectMocks
PerformService performService;
// Mock 注解。
// 功能:mock CalculatorService
@Mock
CalculatorService calculatorService;
@Test
public void testPerformService() {
createMock();
Assert.assertEquals(10, performService.perform(2,3));
}
private void createMock() {
// 使用 Mockito 框架提供的 when 方法
// 功能:当该方法被调用时,直接返回预定的值
Mockito.when(calculatorService.add(Mockito.anyInt(), Mockito.anyInt())).thenReturn(5);
}
}
正常情况下,我们使用 Mockito framework 就可以完成简单的 mock,但要实现更加高级的 mock 例如 mock 静态、final、私有方法等,Mockito framework 就不太够用了,这个时候就需要使用 PowerMockito。
PowerMock 框架PowerMock 有两个重要的注解:
@RunWith(PowerMockRunner.class)
@PrepareForTest({xxx.class})
如果测试用例中没有使用注解@PrepareForTest,那么可以不添加@RunWith(PowerMockRunner.class)。
Mock 入参对象使用方法:Mock 参数传递对象,这个没什么好说的,直接 PowerMockito.mock(xxx.class) 即可。
Student.java:
@Data
public class Student {
private int age;
private String name;
}
测试目标代码:HelloWorld.java
public class HelloWorld {
private static final int TWENTY = 20;
public boolean isAgeEquals20(Student student) {
return student.getAge() == TWENTY;
}
}
测试用例代码:HelloWorldTest.java
import com.bytedance.entity.Student;
import org.junit.Assert;
import org.junit.Test;
import org.powermock.api.mockito.PowerMockito;
public class HelloWorldTest {
@Test
public void testIsHelloWorld() {
Student s = PowerMockito.mock(Student.class);
try {
HelloWorld hello = new HelloWorld();
PowerMockito.when(s.getAge()).thenReturn(20);
Assert.assertTrue(hello.isAgeEquals20(s));
} catch (Exception e) {
e.printStackTrace();
}
}
}
Mock 方法内部 new 出来的对象
测试目标代码:
public class HelloWorld {
private static final int THIRTY = 30;
public boolean isAgeEquals30(int age, String name) {
Student student = new Student(age, name);
return student.getAge() == THIRTY;
}
}
测试用例代码:
import com.bytedance.entity.Student;
import org.junit.Assert;
import org.junit.Test;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
public class HelloWorldTest {
@Test
@PrepareForTest(HelloWorld.class)
public void testIsAgeEquals30() {
Student s = PowerMockito.mock(Student.class);
try {
HelloWorld hello = new HelloWorld();
PowerMockito.whenNew(Student.class).withArguments(30, "123").thenReturn(s);
PowerMockito.when(s.getAge()).thenReturn(30);
Assert.assertTrue(hello.isAgeEquals30(30, "123"));
} catch (Exception e) {
e.printStackTrace();
}
}
}
说明:当使用 PowerMockito.whenNew 方法时,必须加注解 @PrepareForTest 和 @RunWith。
注解 @PrepareForTest 里写的类是需要 mock 的 new 对象代码所在的类。
Mock 普通对象的 final 方法测试目标代码:
public class ClassDependency {
public final boolean isRight() {
return true;
}
}
public class Demo {
public boolean callFinal(ClassDependency refer) {
return refer.isRight();
}
}
测试用例:
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
public class DemoTest {
@Test
@PrepareForTest(ClassDependency.class)
public void testCallFinal() {
ClassDependency refer = PowerMockito.mock(ClassDependency.class);
PowerMockito.when(refer.isRight()).thenReturn(false);
Demo demo = new Demo();
Assert.assertFalse(demo.callFinal(refer));
}
}
说明:当需要 mock final 方法的时候,必须加注解 @PrepareForTest 和 @RunWith。
注解 @PrepareForTest 里写的类是 final 方法所在的类。
Mock 普通对象的静态方法、私有方法操作与 Mock final 方法一致,不再演示。
踩坑指南报错提示:
Also, this error might show up because:
- you stub either of: final/private/equals()/hashCode() methods. Those methods cannot be stubbed/verified. Mocking methods declared on non-public parent classes is not supported.
- inside when() you don’t call method on mock but on some other object.
根据提示我们知道,PowerMock 不可以 stub/verify final/private/equals()/hashCode() 方法。
某一踩坑代码如下所示:
HelloWorld.java
public class HelloWorld {
public boolean isHelloWorld(String s) {
return "Hello World!".equals(s);
}
}
HelloWorldTest.java
import org.junit.Assert;
import org.junit.Test;
import org.powermock.api.mockito.PowerMockito;
public class HelloWorldTest {
@Test
public void testIsHelloWorld() {
String s = PowerMockito.mock(String.class);
HelloWorld hello = new HelloWorld();
PowerMockito.when("Hello World!".equals(s)).thenReturn(true);
Assert.assertTrue(hello.isHelloWorld(s));
}
}
控制台错误提示:
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
Those methods *cannot* be stubbed/verified.
Mocking methods declared on non-public parent classes is not supported.
2. inside when() you don't call method on mock but on some other object.
at com.bytedance.powermock.HelloWorldTest.testIsHelloWorld(HelloWorldTest.java:22)
防踩坑指南:
不能 Mock equals() 和 hashCode() 方法。



