9

Here's my test case for a Spring Controller

@RunWith(SpringRunner.class)
@WebMvcTest(value = MyController.class)
public class MyControllerTest {

    @MockBean
    private MyService myService;
}

So this is a unit test specifically for the methods in MyController. But when I run the test, Spring appears to begin instantiating OtherController and all of it's dependencies.

I have tried updating the above as

@RunWith(SpringRunner.class)
@WebMvcTest(value = MyController.class, excludeFilters = @ComponentScan.Filter(value= OtherController.class, type = FilterType.ANNOTATION))


   public class MyControllerTest {

...
}

But spring still appears to wire it. Here's the error thrown by Spring as it tries to instantiate OtherController when I run the above test specifically.

2017-01-06 12:09:46.207  WARN 18092 --- [           main] o.s.w.c.s.GenericWebApplicationContext   : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'otherController' defined in file [C:\..OtherController.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'getOtherService' defined in com.my.myApplication: Unsatisfied dependency expressed through method 'getOtherService' parameter 0org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'getOtherService' defined in com.myOrg.MyServiceApplication: Unsatisfied dependency expressed through method 'getPositionService' parameter 0

What could be causing this?

user6123723
  • 10,546
  • 18
  • 67
  • 109
  • 2
    I know it's been a while, have you resolved this ? Can you show MyController and OtherController ? – alexbt Mar 03 '17 at 17:08

1 Answers1

5

Chances are that you are triggering the bean scanning by accident via a @Componentscan or the likes.

For instance, as explained in this answer, Spring may be detecting your "production" @SpringBootApplication Application class, with all the component scans it brings about. If so make sure you "overwrite" your "production" Application class with your "test" one putting...

@SpringBootApplication
public class Application {
    public static void main(String[] args) throws Exception {
        SpringApplication.run(Application.class, args);
    }
}

...in a location that would override the "Production" Application.

For instance, if your IDE doesn't get messed by class name clashes:

"production" -> src/main/java/com/mycompany/Application.java
             -> src/main/java/com/mycompany/controllers/MyController.java
"test"       -> src/test/java/com/mycompany/Application.java
             -> src/test/java/com/mycompany/controllers/MyControllerTest.java

As an alternative I also have found that in my case this works as well (i.e. placing the Application in the test controllers folder)

"production" -> src/main/java/com/mycompany/Application.java
             -> src/main/java/com/mycompany/controllers/MyController.java
"test"       -> src/test/java/com/mycompany/controllers/Application.java
             -> src/test/java/com/mycompany/controllers/MyControllerTest.java
Antonio
  • 1,178
  • 14
  • 14
  • I'm having the same issue, but unfortunately, this solution doesn't work for me. The `@SpringBootApplication` annotation comes with `@ComponentScan` if I remove `@ComponentScan` every test started giving 404. – Ivan Vilanculo Nov 06 '20 at 16:02
  • The point is not preventing Spring from doing a ComponentScan, which is probably wanted. Instead, it is about letting scanning the test dirs, not the production ones. If it detects `@ComponentScan` in the right (test) base class, it will scan all the components in the corresponding folder and subfolders (test packages and subpackages). From the [docs](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/ComponentScan.html) _If specific packages are not defined, scanning will occur from the package of the class that declares this annotation._ – Antonio Nov 07 '20 at 20:26
  • I don't have `@ComponentScan` anywhere in my code, I've created another question that is more aligned with my case. Would you mind to check it out? https://stackoverflow.com/questions/64724771/webmvctest-attempts-to-load-every-application-controller – Ivan Vilanculo Nov 07 '20 at 21:11
  • have you tried to put a "copy" of your Application.java file under a completely different root folder, parallel to /main? This was the takeaway: the Application.java class can trigger the discovery of all classes under its filesystem, so you should instruct Spring to look at a place other than your /main folder tree, (at your /test folder tree instead)... – Antonio Nov 08 '20 at 01:53
  • Yes I have tried to to copy it to the test folder as you suggested here. – Ivan Vilanculo Nov 08 '20 at 06:18
  • 1
    Maybe your test suite is still looking at the /main folder (as well as the /test one) when running the tests? If you remove the `@SpringBootApplication` from your "main" Application class, do the test go fine? I know you said that the app won't load and return a 404, but do the tests complete correctly? – Antonio Nov 09 '20 at 21:33
  • Yes that's true – Ivan Vilanculo Nov 10 '20 at 06:13
  • I've been able to solve it, it was the `@ControllerAdvise` annotation that I had on my controller that was creating the issue. Thanks. – Ivan Vilanculo Nov 10 '20 at 06:23