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();
}
}
java spring-mvc spring-test-mvc
|
show 3 more comments
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();
}
}
java spring-mvc spring-test-mvc
I am assuming there is a Spring context somewhere for the application that wires HellowService into the HelloController. How is the Spring context loaded in test execution?
– John Camerin
Nov 22 '18 at 18:51
Wouldn't that beMockMvc
?
– Martyn
Nov 22 '18 at 19:18
1
Maybe, if you had @Autowired the service to the controller, by adding that annotation to either the constructor or the property? I don't think SPring will autowire things for you without an explicit declaration, either in the code via an annotation, or via an XML context configuration file...
– moilejter
Nov 22 '18 at 19:21
1
No, Spring doesn't need any Autowired annotation if you only have one constructor. It autowires dependencies in that constructor by default. So your code is totally fine. If you want to test the whole thing, and not just the web layer with a mocked service layer, then don't use WebMvcTest. Use this: docs.spring.io/spring-boot/docs/current/reference/htmlsingle/…
– JB Nizet
Nov 22 '18 at 20:05
1
@JBNizet You're right :-) - looks like a feature that was added to Spring in 4.3: baeldung.com/constructor-injection-in-spring
– moilejter
Nov 22 '18 at 20:12
|
show 3 more comments
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();
}
}
java spring-mvc spring-test-mvc
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();
}
}
java spring-mvc spring-test-mvc
java spring-mvc spring-test-mvc
edited Nov 22 '18 at 19:52
Martyn
asked Nov 22 '18 at 18:43
MartynMartyn
1,56571763
1,56571763
I am assuming there is a Spring context somewhere for the application that wires HellowService into the HelloController. How is the Spring context loaded in test execution?
– John Camerin
Nov 22 '18 at 18:51
Wouldn't that beMockMvc
?
– Martyn
Nov 22 '18 at 19:18
1
Maybe, if you had @Autowired the service to the controller, by adding that annotation to either the constructor or the property? I don't think SPring will autowire things for you without an explicit declaration, either in the code via an annotation, or via an XML context configuration file...
– moilejter
Nov 22 '18 at 19:21
1
No, Spring doesn't need any Autowired annotation if you only have one constructor. It autowires dependencies in that constructor by default. So your code is totally fine. If you want to test the whole thing, and not just the web layer with a mocked service layer, then don't use WebMvcTest. Use this: docs.spring.io/spring-boot/docs/current/reference/htmlsingle/…
– JB Nizet
Nov 22 '18 at 20:05
1
@JBNizet You're right :-) - looks like a feature that was added to Spring in 4.3: baeldung.com/constructor-injection-in-spring
– moilejter
Nov 22 '18 at 20:12
|
show 3 more comments
I am assuming there is a Spring context somewhere for the application that wires HellowService into the HelloController. How is the Spring context loaded in test execution?
– John Camerin
Nov 22 '18 at 18:51
Wouldn't that beMockMvc
?
– Martyn
Nov 22 '18 at 19:18
1
Maybe, if you had @Autowired the service to the controller, by adding that annotation to either the constructor or the property? I don't think SPring will autowire things for you without an explicit declaration, either in the code via an annotation, or via an XML context configuration file...
– moilejter
Nov 22 '18 at 19:21
1
No, Spring doesn't need any Autowired annotation if you only have one constructor. It autowires dependencies in that constructor by default. So your code is totally fine. If you want to test the whole thing, and not just the web layer with a mocked service layer, then don't use WebMvcTest. Use this: docs.spring.io/spring-boot/docs/current/reference/htmlsingle/…
– JB Nizet
Nov 22 '18 at 20:05
1
@JBNizet You're right :-) - looks like a feature that was added to Spring in 4.3: baeldung.com/constructor-injection-in-spring
– moilejter
Nov 22 '18 at 20:12
I am assuming there is a Spring context somewhere for the application that wires HellowService into the HelloController. How is the Spring context loaded in test execution?
– John Camerin
Nov 22 '18 at 18:51
I am assuming there is a Spring context somewhere for the application that wires HellowService into the HelloController. How is the Spring context loaded in test execution?
– John Camerin
Nov 22 '18 at 18:51
Wouldn't that be
MockMvc
?– Martyn
Nov 22 '18 at 19:18
Wouldn't that be
MockMvc
?– Martyn
Nov 22 '18 at 19:18
1
1
Maybe, if you had @Autowired the service to the controller, by adding that annotation to either the constructor or the property? I don't think SPring will autowire things for you without an explicit declaration, either in the code via an annotation, or via an XML context configuration file...
– moilejter
Nov 22 '18 at 19:21
Maybe, if you had @Autowired the service to the controller, by adding that annotation to either the constructor or the property? I don't think SPring will autowire things for you without an explicit declaration, either in the code via an annotation, or via an XML context configuration file...
– moilejter
Nov 22 '18 at 19:21
1
1
No, Spring doesn't need any Autowired annotation if you only have one constructor. It autowires dependencies in that constructor by default. So your code is totally fine. If you want to test the whole thing, and not just the web layer with a mocked service layer, then don't use WebMvcTest. Use this: docs.spring.io/spring-boot/docs/current/reference/htmlsingle/…
– JB Nizet
Nov 22 '18 at 20:05
No, Spring doesn't need any Autowired annotation if you only have one constructor. It autowires dependencies in that constructor by default. So your code is totally fine. If you want to test the whole thing, and not just the web layer with a mocked service layer, then don't use WebMvcTest. Use this: docs.spring.io/spring-boot/docs/current/reference/htmlsingle/…
– JB Nizet
Nov 22 '18 at 20:05
1
1
@JBNizet You're right :-) - looks like a feature that was added to Spring in 4.3: baeldung.com/constructor-injection-in-spring
– moilejter
Nov 22 '18 at 20:12
@JBNizet You're right :-) - looks like a feature that was added to Spring in 4.3: baeldung.com/constructor-injection-in-spring
– moilejter
Nov 22 '18 at 20:12
|
show 3 more comments
1 Answer
1
active
oldest
votes
@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.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53436637%2fspring-controller-testing-with-dependencies-failing%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
@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.
add a comment |
@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.
add a comment |
@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.
@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.
answered Nov 22 '18 at 20:35
Danylo RosiichukDanylo Rosiichuk
1494
1494
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53436637%2fspring-controller-testing-with-dependencies-failing%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
I am assuming there is a Spring context somewhere for the application that wires HellowService into the HelloController. How is the Spring context loaded in test execution?
– John Camerin
Nov 22 '18 at 18:51
Wouldn't that be
MockMvc
?– Martyn
Nov 22 '18 at 19:18
1
Maybe, if you had @Autowired the service to the controller, by adding that annotation to either the constructor or the property? I don't think SPring will autowire things for you without an explicit declaration, either in the code via an annotation, or via an XML context configuration file...
– moilejter
Nov 22 '18 at 19:21
1
No, Spring doesn't need any Autowired annotation if you only have one constructor. It autowires dependencies in that constructor by default. So your code is totally fine. If you want to test the whole thing, and not just the web layer with a mocked service layer, then don't use WebMvcTest. Use this: docs.spring.io/spring-boot/docs/current/reference/htmlsingle/…
– JB Nizet
Nov 22 '18 at 20:05
1
@JBNizet You're right :-) - looks like a feature that was added to Spring in 4.3: baeldung.com/constructor-injection-in-spring
– moilejter
Nov 22 '18 at 20:12