我有一个 Spring Boot 1.4.2 应用程序。在启动期间使用的一些代码如下所示:
@Component
class SystemTypeDetector{
public enum SystemType{ TYPE_A, TYPE_B, TYPE_C }
public SystemType getSystemType(){ return ... }
}
@Component
public class SomeOtherComponent{
@Autowired
private SystemTypeDetector systemTypeDetector;
@PostConstruct
public void startup(){
switch(systemTypeDetector.getSystemType()){ // <-- NPE here in test
case TYPE_A: ...
case TYPE_B: ...
case TYPE_C: ...
}
}
}
有一个组件确定系统类型。该组件在从其他组件启动期间使用。在生产中一切正常。
现在我想使用 Spring 1.4 的 @MockBean
添加一些集成测试。
测试看起来像这样:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyWebApplication.class, webEnvironment = RANDOM_PORT)
public class IntegrationTestNrOne {
@MockBean
private SystemTypeDetector systemTypeDetectorMock;
@Before
public void initMock(){
Mockito.when(systemTypeDetectorMock.getSystemType()).thenReturn(TYPE_C);
}
@Test
public void testNrOne(){
// ...
}
}
基本上模拟工作正常。使用了我的 systemTypeDetectorMock,如果我调用 getSystemType
-> TYPE_C
返回。
问题 是应用程序没有启动。目前弹簧工作顺序似乎是:
- 创建所有模拟(没有配置所有方法返回 null)
- 开始申请
- 调用@Before-methods(配置模拟的地方)
- 开始测试
我的问题是应用程序以未初始化的模拟开始。因此调用 getSystemType()
返回空值。
我的问题是:如何在应用程序启动 之前 配置模拟?
编辑: 如果有人遇到同样的问题,一种 解决方法 是使用 @MockBean(answer = CALLS_REAL_METHODS)
。这调用了真正的组件,在我的例子中系统启动了。启动后,我可以更改模拟行为。
原文由 Marcel 发布,翻译遵循 CC BY-SA 4.0 许可协议
在这种情况下,您需要以我们在引入
@MockBean
之前使用的方式配置模拟 - 通过手动指定@Primary
bean 将替换上下文中的原始 bean。因为
@TestConfiguration
类是一个静态内部类,它只会被这个测试自动选中。您将放入@Before
的完整模拟行为必须移至初始化 bean 的方法。