在另一个 bean 的构造函数中插入 bean 的存根方法

Stubbing methods of injected beans in another bean's constructors

我使用构造函数注入测试了一个 Spring bean。注入的 bean 在测试用例中被定义为 @MockBean 并且还定义了适当的存根:当调用模拟 bean 的某个方法时,它应该 return 一个模拟对象。

当我启动测试用例时,我得到一个 NullPointerException,因为存根不起作用 – 方法 returns 总是 null.

这里是要测试的对象的构造函数:

@Autowired
public MyBeanToTest(msTemplate jmsTemplate) throws JMSException {
    this.jmsTemplate = jmsTemplate;
    this.cf = this.jmsTemplate.getConnectionFactory(); // cf is always null
    cf.createSession(); // NPE
}

这是测试用例:

@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 );
        ...
    }
}

我假设调用构造函数时定义的存根尚未激活。 知道如何让它发挥作用吗?

您必须使用静态存根,这样它才能存在并在创建上下文之前进行配置。

另一种更简洁的方法是不在构造函数中调用任何内容,而是根据需要使用 cf.createSession(); 创建会话(它仍然可以是单例)。

另一种方法是根本不使用@MockBean,而只是自己创建GegugProcessingSoapServices

你的假设是正确的。最好的办法是“手动”创建 bean,而不是让 Spring 自己调用构造函数。为此,将 @Configuration class 添加到具有相应 @Bean 方法的测试中。


未经测试的例子:

@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);
            …
        }
    }
    
}

@AutoWired 不适用于正在测试的 class。它不会将 bean 带入构造函数。

解决方案可以使用 Mockito @InjectMock,或者自己创建 class 并在构造函数中使用模拟(这通常是一个好习惯):

MyBeanToTest myBeanToTest = new MyBeanToTest(connectionFactory)

我建议不要模拟而是存根 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()  {
        ...
    }
}