I have been searching for a while and I can't find a solution for this. I need to mock a class that is used in the @PostConstruct of another class. My classes are like this:
@Component
class A {
private final B b;
private String s;
public A(B b) {this.b = b;}
@PostConstruct
public void postConstruct() {
s = b.get().getString().toUpperCase();
}
}
@Component
class B {
private final C c;
public B(C c) {this.c = c;}
public C get() {return c;}
}
@Component
class C {
public C() throws Exception {throw new Exception();}
String getString() {return "C";}
}
Now I create the test that fails because the constructor of C
fails:
@SpringBootTest
class DemoApplicationTests {
@Autowired A a;
@Test
public void canLoadContext() {
assertThat(a).isNotNull();
}
}
So I try to mock the C
class:
@SpringBootTest
class DemoApplicationTests {
@MockBean
static C c;
@Autowired
A a;
@BeforeEach
public void beforeEach() {
when(c.getString())
.thenReturn("C_mocked");
}
@Test
public void canLoadContext() {
assertThat(a).isNotNull();
}
}
But this way it fails with a NPE in the line s = b.get().getString().toUpperCase();
because the C
object in b
is not the same that I have mocked with @MockBean
. When getString()
is called, it returns null
and we get a NPE when calling .toUpperCase()
.
I have also tried to overwrite the mock like this:
@Configuration
@AutoConfigureBefore
static class TestContext {
@Primary
public C c() {
return when(mock(C.class).getString())
.thenReturn("C_mocked").getMock();
}
}
But in this case I get this error:
No qualifying bean of type 'com.example.demo.A' available: expected at least 1 bean which qualifies as autowire candidate.
Could please somebody help out with this?
CodePudding user response:
I don't know how to mark it as duplicate. But please take a look of this https://stackoverflow.com/a/58517289/11538031
CodePudding user response:
The solution remains like this:
@Component
class A {
private final B b;
private String s;
public A(B b) {this.b = b;}
@PostConstruct
public void postConstruct() {
s = b.get().getString().toUpperCase();
}
}
@Component
class B {
private final C c;
public B(C c) {this.c = c;}
public C get() {return c;}
}
@Component
class C {
public C() throws Exception {throw new Exception();}
String getString() {return "C";}
}
@SpringBootTest
class DemoApplicationTests {
@Autowired
A a;
@Test
public void canLoadContext() {
assertThat(a).isNotNull();
}
@TestConfiguration
public static class TestContext {
@Bean
@Primary
public C c() {
return when(mock(C.class).getString())
.thenReturn("C_mocked").getMock();
}
}
}