I test a Spring bean using constructor injection. The injected bean is defined as @MockBean
in the testcase and also the appropriate stub is defined: when a certain method of the mocked bean is called, then it should return a mocked object.
When I start the testcase I get a NullPointerException
, because the stubbing does not work – the method returns always null
.
Here is the constructor of the object to test:
@Autowired
public MyBeanToTest(msTemplate jmsTemplate) throws JMSException {
this.jmsTemplate = jmsTemplate;
this.cf = this.jmsTemplate.getConnectionFactory(); // cf is always null
cf.createSession(); // NPE
}
Here is the testcase:
@SpringBootTest
public class MyTestClass {
@Autowired
MyBeanToTest myBeanToTest;
@MockBean
private JmsTemplate jmsTemplate;
@Mock
private static ConnectionFactory connectionFactory;
@Test
public void testSomething() {
...
when( jmsTemplate.getConnectionFactory() ).thenReturn( connectionFactory );
...
}
}
I assume the defined stubbing is not active yet when the constructor is called. Any idea how can I make it work?
CodePudding user response:
You would have to use static stub so it would exist and be configured prior creation of the context.
Another, cleaner approach, is to NOT to call anything in the constructor, but to create your session with cf.createSession();
on demand (it still can be singleton).
Yet another approach is to NOT to use @MockBean at all, and just create GegugProcessingSoapServices
yourself.
CodePudding user response:
Your assumption is correct. Your best bet is to create the bean ‘by hand’ instead of letting Spring call the constructor all by itself. To this end, add a @Configuration
class to your test that has the corresponping @Bean
method.
Untested example:
@SpringBootTest
public class MyTestClass {
@Configuration
static class MyTestClassConfiguration {
@Bean
MyBeanToTest myBeanToTest(jmsTemplate jmsTemplate) {
// Too bad that this is not within the test…
when(jmsTemplate.getConnectionFactory())
.thenReturn(connectionFactory);
…
}
}
}
CodePudding user response:
I would suggest not to mock but to stub the JmsTemplate
bean.
@SpringBootTest
public class MyTestClass {
@Autowired
MyBeanToTest myBeanToTest;
@Autowired
private JmsTemplate jmsTemplate;
@Mock
private static ConnectionFactory connectionFactory;
@TestConfiguration
static class Config {
@Bean
public JmsTemplate jmsTemplate() {
return new JmsTemplate() {
public ConnectionFactory getConnectionFactory() {
return connectionFactory;
}
}
}
}
@Test
public void testSomething() {
...
}
}
CodePudding user response:
@AutoWired
is not intended for use for class under test. It won't take the bean into the constructor .
The solution can be possible to use Mockito @InjectMock
, or to create the class yourself and use a mock in the constructor (this is generally a good practice):
MyBeanToTest myBeanToTest = new MyBeanToTest(connectionFactory)