Home > front end >  Stubbing methods of injected beans in another bean's constructors
Stubbing methods of injected beans in another bean's constructors

Time:09-17

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)

  • Related