Reputation: 9724
The following classes reference each other crating a circular dependency:
@AllArgsConstructor
@Component
public class A {
private B b;
public String doSomething() {
return "Result: " + b.doSomethingElse();
}
}
@Componenet
public class B {
private A a;
@Autowired
public B(@Lazy final A a) {
this.a = a;
}
public String doSomethingElse() {
return a.toString();
}
}
I need to test class A
and make sure the actual implementation of class B
gets invoked:
@RunWith(MockitoJUnitRunner.class)
public class ATest {
@InjectMocks
private A a;
@Spy
private B b;
@Test
public void testDoSomething() {
final String result = a.doSomething();
assertNotNull(result);
}
}
@Spy
doesn't work and I always get the following error:
Unable to initialize @Spy annotated field 'b'.
Please ensure that the type 'B' has a no-arg constructor.
org.mockito.exceptions.base.MockitoException: Unable to initialize @Spy annotated field 'b'.
Please ensure that the type 'B' has a no-arg constructor.
I could use @Mock
... but then I need to mock the expected result, whereas I need to invoke the actual implementation (that's why I'm using @Spy
).
Is there any way to workaround this? Thank you very much :-)
Upvotes: 0
Views: 161
Reputation: 265131
Do what Spring would do for a @Lazy
dependency: don't inject the dependency directly, but a proxy instance which allows setting the dependency lazily. You can avoid some problems by depending on interfaces and not concrete classes.
class LazyA extends A {
private A realA;
public LazyA() { this(null); }
public void setRealA(final A realA) {
this.realA = realA;
}
public String doSomething() {
return realA.doSomething();
}
}
public class ATest {
@Test
public void testDoSomething() {
final LazyA lazyA = new LazyA();
final B b = new B(lazyA);
final A a = new A(b);
lazyA.setRealA(a);
final String result = a.doSomething();
assertNotNull(result);
}
}
Better yet: don't write code with circular dependencies.
Upvotes: 0