情景描述
- 使用@WebMvcTest(Controller.class)做单元测试
- 然后运行测试发现报错
java.lang.IllegalStateException: Failed to load ApplicationContext
- 导致错误的原因是:没有办法创建service的Bean-->org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'tw.demo.todomvc.service.TaskService'
- 测试写法:
@RunWith(SpringRunner.class)
@WebMvcTest(TaskController.class)
public class DemoApplicationUnitTests {
@Autowired
private MockMvc mockMvc;
@Test
public void test_get_one_task_when_id_exist() throws Exception {
Task task = new Task();
task.setId(1);
when(taskRepository.exists(1)).thenReturn(true);
when(taskRepository.findOne(1)).thenReturn(task);
mockMvc.perform(get("/tasks/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id",is(1)))
.andExpect(jsonPath("$.text",is("zhangpei")))
.andExpect(jsonPath("$.completed",is(0)));
}
}
问题分析
- Q1:为什么会导致service无法创建Bean?
- A1:那可能是没有扫描到这个service,首先去检查是不是service有没有加注解@Service,其次检查controller中是否自动注入service,发现都做了。
- Q2:那既然都做了为什么还是没办法创建service bean?
- A2:说明做自动扫描和自动装配的工具不存在。我们通常使用注解进行bean的自动扫描和装配,也就是所谓的配置。那就是注解使用的有问题。
Q3:注解没有做到扫描和装配的功能,那么我使用的注解有什么作用,又缺少了什么注解呢?
-
A3:首先因为官网使用的是@WebMvcTest注解,作用:
1.自动装配和扫描对应的controller bean(请注意:因为这个注解有参数,参数是controller的类,因此他只会扫描这个controller类)
2.自动装配MockMvc也就是只把参数的controller实例启动起来。(不会启动整个服务)赋给MockMvc这一小部分的服务器。
- note - 只扫描注解@Controller,@ControllerAdvice,@JsonComponent,Filter,WebMvcConfigurer和HandlerMethodArgumentResolver的beans,其他常规的@Component beans将不会被扫描.
这就解释了,我们的servie是不会被自动扫描并且创建对应的bean的,因此报错。
Q4:那既然确定了注解不没有办法扫描并且装配bean,那么我们该如何解决这个问题呢?
-
A4:查找网上的资料发现,一般这个注解扫描不到的地方都要使用@MockBean将其mock掉。
Often @WebMvcTest will be limited to a single controller and used in combination with @MockBean to provide mock implementations for required collaborators.
因此,扫描不到的service需要被mock掉才行。
- Q5:那么实际问题就来了,我只需要mock的是repository,还要测试service,该如何做单元测试呢?
- A5:那么我们绝对不能自动注入MockMvc,因为我们不能Mock掉整个service因此一定会出现service找不到bean,因此我们不能使用webMvcTest注解,我们可直接使用MockMvc做测试。不启动服务直接测试接口function
反思
- 其实webMvcTest之前我已经在上面栽过一次了,这次又出现问题,可以说明我研究东西不够全面,并且上次过了,并没有完完全的把每个步骤都了解清楚,急于求成,发现一个点之后就感觉研究到此为止了。还是做事太着急了,急着完成某个东西,因此会忽略目标以外的东西。
action
- 要求自己todoList专门建一列用来记那些没时间当时解决但是却被发现和想要解决的问题。然后平时一下班就开始清todoList。周末必须把这一周的todoList全部清光。