Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@Spy @InjectMocks dependency A->spy(B)->C not injected correctly when using constructor dependency injection #1516

Open
Arnaud-Nauwynck opened this issue Oct 10, 2018 · 0 comments · May be fixed by #1711

Comments

@Arnaud-Nauwynck
Copy link

Arnaud-Nauwynck commented Oct 10, 2018

I am trying to do a test on class A, with a dependency A->B to be spied, and a transitive dependency B->C

This code is typical in a spring application, when A is a high-level service, C is a low-level one (like a Repository), and B is simply a helper service class that delegate most calls to C

To use @Spy on instance of B, requires to mock C, and inject C into B...
a typical test code should be

   @RunWith(MockitoJUnitRunner.class)
   class Test {
        @InjectMocks A a;
	@Spy @InjectMocks  B b; 
        @Spy C c;

       @Test  public void testA() { .. }
}

This generally works fine with standard spring injections for code like

   @Component // or @Service, @Controller, ..
   public class B {
      @Autowired // or @Inject
      private C c;
   }

... BUT fails when using Constructor dependency injection for fields !!!
This is absurd since constructor injection is precisely a best practice for enforcing code stability regarding test

   @Component
   public class B {
      private final C c;
      public B(C c) { this.c = c;  }
   }

There are many strange situations, while testing different combinations of annotations on real class (@Inject, @Autowired..), and @Spy, @InjectMocks in test class

Either
case 1/ spy NOT injected in a.b ... so causing NPE in spy execution
case 2/ spy NOT injected in b.c ... but injected in a.b ... so causing NPE in spy execution
case 3/ MockitoException Unable to initialize @Spy annotated field 'b', Please ensure that the type 'CtorB' has a no-arg constructor

Notice also that the final desired scenario would be to use lombok generated full constructor.. but it also fails !!

	@InjectMocks 
	A a; // ERROR.. a.b == null
	
	@Spy @InjectMocks
	B b; // b instanciated, but not injected into a !!!

	@Spy
	C c;

    // with..
    @AllArgsConstructor(onConstructor_={@Inject}) // equivalent of :  @Inject public A(B b) { this.b = b; }
    public class A {
	private final B b;
    }
   // or also 
   @AllArgsConstructor
   public class A {
	private final B b;
   }

I have joined a full maven test project that reproduce many of these scenarios
test-mockito.zip

You can also browse it (up-to-date) here.

arnor2000 pushed a commit to arnor2000/mockito that referenced this issue May 9, 2019
…be injected into other @InjectMock
arnor2000 pushed a commit to arnor2000/mockito that referenced this issue May 9, 2019
Allows @SPY with @Injectmocks to be injected into other @Injectmocks
arnor2000 added a commit to arnor2000/mockito that referenced this issue May 10, 2019
Allows Spies with @Injectmocks to be injected into other @Injectmocks
arnor2000 added a commit to arnor2000/mockito that referenced this issue May 10, 2019
Allows Spies with @Injectmocks to be injected into other @Injectmocks
arnor2000 added a commit to arnor2000/mockito that referenced this issue May 10, 2019
Allows Spies with @Injectmocks to be injected into other @Injectmocks
arnor2000 added a commit to arnor2000/mockito that referenced this issue May 13, 2019
Allows Spies with @Injectmocks to be injected into other @Injectmocks
arnor2000 added a commit to arnor2000/mockito that referenced this issue Mar 5, 2020
Allows Spies with @Injectmocks to be injected into other @Injectmocks
arnor2000 added a commit to arnor2000/mockito that referenced this issue Oct 12, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants