回顾
在前文Spring Boot下编写Controller层单元测试(一)中,我们用Spring MVC框架写了一个最简单的REST接口,其中没有涉及业务逻辑。
在本文中我将继续深入,将业务逻辑加入到项目中,并展示如何进行测试。
增加Service层代码
首先定义一个接口,在我们简单项目中是否定义接口其实并不重要,但这依然是个好习惯。
public interface IDemoService {
List<Demo> findAll();
}
增加DemoService实现层代码
@Service
public class DemoService implements IDemoService{
@Override
public List<Demo> findAll() {
return null;
}
}
Controller层调用业务逻辑
接下来我们要在Controller层调用demoService
@Controller
@RequestMapping("demos")
public class DemoController {
private IDemoService demoService;
@Autowired
public DemoController(IDemoService demoService) {
this.demoService = demoService;
}
@GetMapping
public ResponseEntity<List> searchDemo() {
List<Demo> demoList = demoService.findAll();
return new ResponseEntity<>(demoList, HttpStatus.OK);
}
}
修改单元测试
修改完业务代码之后直接运行原来的测试代码,会发现抛出NullPointException
这是因为测试的searchDemo()
方法需要调用demoService
对象,而在我们的测试类中没有创建demoService
对象。
@RunWith(MockitoJUnitRunner.class)
public class MockDemoControllerTest {
private MockMvc mockMvc;
@InjectMocks
private DemoController demoController;
@Mock // 创建一个模拟的demoService对象
private DemoService demoService;
@Before
public void setUp() throws Exception {
mockMvc = MockMvcBuilders.standaloneSetup(demoController).build();
}
@Test
public void should_get_demos() throws Exception {
mockMvc.perform(get("/demos"))
.andExpect(status().isOk());
}
}
修改的测试代码很简单,只增加了@Mock private DemoService demoService
。
执行修改后的测试代码,将会看到我们的测试结果再次变绿。
发生了什么
相比较与前一个版本,发生了什么改变呢?
首先我们测试的类DemoController
多了一个依赖的对象demoService
,并且在测试的方法中还需要调用demoService
的findAll()
方法。但在原来的测试中,demoController
对象中并没有找到所的demoService
对象。
为什么增加@Mock private DemoService demoService
之后就可以正常运行了?
关键要看使用@InjectMocks
与@Mock
这两个注解后发生了什么。
@InjectMocks与@Mock
private DemoService demoService1 = new DemoService();
/**
* 可以简单的理解为 增加这个注解后
* 执行了 private DemoService demoService2 = new DemoService();
*/
@Mock
private DemoService demoService2;
/**
* @InjectMocks注解可以理解为
* 执行了 private DemoController demoController = new DemoController(demoService2);
*/
@InjectMocks
private DemoController demoController;
也就是说,MockitoJUnitRunner
执行器在运行前会检测到使用@InjectMocks
和@Mock
的成员变量,并自动为其创建对象。
总结
本文在创建REST接口的基础上增加了业务逻辑,更加贴近实际生产环境。针对代码结构改变,相应改变了测试代码,解决待测试代码的依赖问题。
解释了测试代码中用到的两个注解作用,但没有对其深入展开。
下一篇我将继续介绍如何测试Controller代码,并介绍一下其他的测试用法。