本文重点将讲述如何在单元测试中, mock 某个service的请求。
测试环境中,我们经常会有这样的场景,不希望在服务A执行单测的过程中调用某个服务B,比如说服务B根本没有测试环境,或者服务B测试环境不一定能跑的通。
举个简单的例子,我们在服务A中调用服务B的请求来发送钉钉消息,单测中执行的时候,是不想真正触发发送钉钉消息到钉钉群里。
当然,这种情况也有其他方式来玩,比如单独建个钉钉测试群,来接收单测环境的信息,或者干脆就配置一个错误的钉钉token。
抛开上面的方式不谈,我们今天就讲讲如何在单测环境中mock发送钉钉消息的服务。
还是之前的那个mockito-demo的工程,我们在工程中新增了两个service: DemoService,DingTalkService,两个service服务的代码如下:
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Service
@AllArgsConstructor
@Slf4j
public class DemoService {
private final DingTalkService dingTalkService;
public void service() {
log.info("use DemoService call service function!");
dingTalkService.send2DingDing("hello world");
}
}
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class DingTalkService {
public void send2DingDing(String content) {
log.info("send content to dingding success!");
}
}
DemoService中对外提供了service的方法,调用DemoServcie提供的service的方法,首先会控制台打印一条日志,然后调用发送钉钉消息的服务DingTalkService提供的send2Dingding的方法来执行发送消息到钉钉群,调用DingTalkService提供的send2Dingding的方法,为了模拟效果,我们也打印了一条send content to dingding success的日志,用这个日志来代表send2Dingding的方法实际上是执行了。
接下来,我们建立一个单元测试类 DemoServiceTest,还是老样子,我们在打开的DemoService中,使用快捷键的方式来创建单元测试类,mac下是 cmd + shift + T,Windows下是ctrl + shift + T,DemoServiceTest的代码如下:
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doNothing;
import com.example.demo.extensions.CaptureSystemOutput;
import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import lombok.SneakyThrows;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
@SpringBootTest
@CaptureSystemOutput
class DemoServiceTest {
@Resource DemoService demoService;
@MockBean DingTalkService dingTalkService;
@SneakyThrows
@BeforeEach
void initMock() {
doNothing().when(dingTalkService).send2DingDing(anyString());
}
@Test
void service(@NotNull CaptureSystemOutput.OutputCapture outputCapture) {
demoService.service();
assertTrue(outputCapture.toString().contains("use DemoService call service function"));
assertFalse(outputCapture.toString().contains("send content to dingding success"));
}
}
复制完代码,记得执行下 ./gradlew spotlessApply 格式化下代码
单测中,通过MockBean的方式,把DingTalkService给mock掉了,在调用DingTalkService的send2Dingding的方法时,什么都不做。
这样,打印的日志中,也就只有DemoService的service方法的日志,而没有DingTalkService的send2Dingding方法执行的内部日志,说明DingTalkService我们已经mock成功了。