Spring Boot集成Togglz测试时出现Could not find FeatureManager错误
问题根源
单元测试时Togglz的FeatureContext无法获取到FeatureManager,核心原因是:
- 运行时Spring Boot会自动初始化Togglz上下文,但单元测试(尤其是非集成测试场景)中,完整的Web上下文或Togglz初始化逻辑未触发;
- 你的
FeatureOptions.isActive()直接依赖全局的FeatureContext.getFeatureManager(),测试环境下该上下文未被正确绑定。
解决方案
方案1:移除对FeatureContext的直接依赖(推荐)
既然控制器已经通过构造方法注入了FeatureManager,直接用它判断特性开关即可,完全绕开全局上下文的依赖:
修改控制器代码:
public class MyController { private final FeatureManager featureManager; public MyController(FeatureManager featureManager) { this.featureManager = featureManager; } public ResponseEntity<MyResponse> tempDriver(@RequestBody MyTempDriverRequest request) { // 直接用注入的featureManager判断特性状态 if (featureManager.isActive(FeatureOptions.TEMP_DRIVER)) { if (request.getTempDriver().equals("")) { request.getTempDriver().setCountry("GB"); } } // ...后续逻辑 } }
同时简化FeatureOptions枚举,去掉依赖全局上下文的方法:
public enum FeatureOptions implements Feature { @Label("Temporary driver") TEMP_DRIVER; }
这种方式的优势:
- 符合Spring依赖注入的设计原则,代码耦合度更低;
- 测试时只需Mock或注入
FeatureManager即可,无需处理全局上下文的初始化问题。
方案2:在单元测试中手动初始化Togglz上下文
如果必须保留FeatureOptions.isActive()的实现,需要在测试类中手动绑定FeatureManager到FeatureContext:
场景A:集成测试(使用@SpringBootTest)
确保测试类加载Togglz配置,并在测试前绑定上下文:
@SpringBootTest @ContextConfiguration(classes = {TogglzConfiguration.class, MyController.class}) public class MtaControllerTest { @Autowired private FeatureManager featureManager; @BeforeEach void setUp() { // 将Spring管理的FeatureManager绑定到全局上下文 FeatureContext.setFeatureManager(featureManager); } // 测试方法编写... }
场景B:纯单元测试(使用Mockito)
不启动Spring上下文,手动创建或MockFeatureManager并绑定:
@RunWith(MockitoJUnitRunner.class) public class MtaControllerTest { @Mock private FeatureManager featureManager; @InjectMocks private MyController myController; @BeforeEach void setUp() { // 方式1:手动创建FeatureManager并绑定 FeatureManager testFeatureManager = new DefaultFeatureManager( new TogglzConfiguration(), new InMemoryStateRepository() ); // 根据测试需求设置特性状态 testFeatureManager.setFeatureState(new FeatureState(FeatureOptions.TEMP_DRIVER, true)); FeatureContext.setFeatureManager(testFeatureManager); // 方式2:用Mockito Mock特性判断逻辑 // when(featureManager.isActive(FeatureOptions.TEMP_DRIVER)).thenReturn(true); } // 测试方法编写... }
额外注意事项
- 确认
TogglzConfiguration上的@Configuration注解生效,且所在包在Spring的扫描路径内; - 测试环境可通过
@TestPropertySource指定单独的配置文件,确保Togglz特性开关符合测试预期; - 尽量避免在非Spring管理的代码中直接调用
FeatureContext.getFeatureManager(),依赖注入的方式更利于测试和维护。
内容的提问来源于stack exchange,提问作者runnerpaul
相关产品推荐
相关产品推荐

