Martyn
Martyn

Reputation: 6385

Spring controller testing with dependencies failing

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

Answers (1)

Danylo Rosiichuk
Danylo Rosiichuk

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

Related Questions