Reputation: 6385
I have the following controller class:
@Controller
public class HelloController {
private final HelloService service;
public HelloController(HelloService service) {
this.service = service;
}
@RequestMapping("/hello")
public @ResponseBody String greeting() {
return service.greet();
}
}
As you can see, it accepts a dependency. This all runs fine in the server. However, when testing, it fails:
@RunWith(SpringRunner.class)
@WebMvcTest(HelloController.class)
public class WebLayerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void shouldReturnDefaultMessage() throws Exception {
this.mockMvc.perform(get("/hello")).andDo(print()).andExpect(status().isOk())
.andExpect(content().string(containsString("Hello World")));
}
}
Below is the output of the log file in target/surefire-reports/
-------------------------------------------------------------------------------
Test set: biz.martyn.footy.WebLayerTest
-------------------------------------------------------------------------------
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 2.278 s <<< FAILURE! - in biz.martyn.footy.WebLayerTest
shouldReturnDefaultMessage(biz.martyn.footy.WebLayerTest) Time elapsed: 0.005 s <<< ERROR!
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'helloController' defined in file [/home/martyn/eclipse-workspace/Footy/target/classes/biz/martyn/footy/controller/HelloController.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'biz.martyn.footy.service.HelloService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'biz.martyn.footy.service.HelloService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
I understand that @MockBean
allows me to create a mock of the dependency, but in cases where I don't care to mock it? Here, I'm happy here for the real dependency instance to be used as normal. Or, is it because I'm only testing the web layer that it doesn't instantiate the controller as it would when running the full app?
UPDATE
I also tried @Autowired
injection rather than constructor. My app works, so the dependency is brought into the controller, but the test fails. Below is the updated controller:
@Controller
public class HelloController {
@Autowired
private HelloService service;
@RequestMapping("/hello")
public @ResponseBody String greeting() {
return service.greet();
}
}
Upvotes: 0
Views: 1727
Reputation: 219
@WebMvcTest
will disable full auto-configuration and instead apply only configuration relevant to MVC tests (i.e. @Controller
, @ControllerAdvice
, @JsonComponent
, Converter/GenericConverter, Filter, WebMvcConfigurer and HandlerMethodArgumentResolver beans but not @Component
, @Service
or @Repository
beans, so you have to use @MockBean
to satisfy the dependency.
Upvotes: 1