使用场景
当我们需要在单元测试中测试一些很难构造数据的方法时。例如微服务场景下,我们需要调用其他微服务来实现自身的功能,而又不希望对其他微服务造成影响。或者,在使用Spring时,我们都是通过IOC容器来创建对象的。在这种场景下,为了方便模拟实际的场景,我们需要使用mock工具来帮助我们在单元测试中测试我们的方法。
使用方法
在这里我采用maven工程来演示JMockit的使用
- 引入JMockit与Junit5的依赖,以及JMockit的代理插件
<dependencies>
<dependency>
<groupId>org.jmockit</groupId>
<artifactId>jmockit</artifactId>
<version>${jmockit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
...
<dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<argLine>
-javaagent:"${settings.localRepository}"/org/jmockit/jmockit/${jmockit.version}/jmockit-${jmockit.version}.jar
</argLine>
</configuration>
</plugin>
</plugins>
</build>
- 假设我们目前有一个DemoService与一个DemoDao。大概的代码如下:
public interface DemoDao {
List<Entity> queryAll();
int insert(Entity entity);
}
//注解表示是一个Bean对象,通过IOC容器创建(Spring)
@Service
public class DemoService {
private final DemoDao demoDao;
public DemoService(DemoDao demoDao) {
this.demoDao = demoDao;
}
public List<Entity> queryAll() {
return demoDao.queryAll();
}
}
在这种情境下,如果我们需真正模拟数据库操作,存在两个问题:
(1)我们在做测试的过程中,不希望测试数据污染数据库,仅仅是为了测试功能是否可用;同时在提交CI过程时,也无法连接数据库测试;
(2)在测试过程中,我们希望对单功能测试,不希望dao层的逻辑扩散到service层;因此,我们希望直接能够获取到dao层的结果;
基于以上两个问题,我们才引入了JMockit测试。
3. 编写针对DemoService的单元测试
class DemoServiceTest {
@Tested
private DemoService demoService;
@Injectable
private DemoDao demoDao;
@Test
void findAllLabel() {
new Expectations() {{
demoDao.queryAll();
result = Collections.singletonList(new Entity());
}};
Assertions.assertEquals(1, demoService.queryAll().size());
}
}
解释:
(1) @Tested表示:该测试类需要测试被Tested注解的对象;
(2)@Injectable表示:被测试的类需要依赖的对象;这样,由JMockit框架帮我们“注入”了一个对象,用于构造一个模拟的service对象;
(3)在demoService.queryAll()中,我们会调用到demoDao.queryAll()。这一步我们并不希望它执行,而是使用我们期望的一个值来代替它的返回结果(result = xxx)。这样,在"回放"(外层调用demoService.queryAll())时,就会用这里result的结果来替代真实的调用。这样,屏蔽了dao层对service的影响。
注意:如果需要模拟静态方法的返回,需要这样写:
new Expectaions(StaticClass.class) {{
StaticClass.func();
result = null;
}};