我有一个测试实用程序,我需要每个测试方法有一个新的实例(以防止测试之间的状态泄漏)。到目前为止,我使用的是范围“原型(prototype)”,但现在我希望能够将该实用程序连接到另一个测试实用程序,并且每个测试的连接实例应相同。
这似乎是一个标准问题,所以我想知道是否有“测试方法”范围或类似的东西?
这是测试类和测试实用程序的结构:
@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTest {
@Autowired
private TestDriver driver;
@Autowired
private TestStateProvider state;
// ... state
// ... methods
}
@Component
@Scope("prototype") // not right because MyTest and TestStateProvider get separate instances
public class TestDriver {
// ...
}
@Component
public class TestStateProvider {
@Autowired
private TestDriver driver;
// ...
}
我知道我可以使用 @Scope("singleton")
和 @DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
但这刷新超出了我的需要 -每个测试一个新的 TestDriver 实例就足够了。此外,这种方法很容易出错,因为使用 TestDriver
的所有测试都需要知道它们还需要 @DirtiesContext
注释。所以我正在寻找更好的解决方案。
最佳答案
实现 testMethod
范围实际上非常容易:
public class TestMethodScope implements Scope {
public static final String NAME = "testMethod";
private Map<String, Object> scopedObjects = new HashMap<>();
private Map<String, Runnable> destructionCallbacks = new HashMap<>();
@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
if (!scopedObjects.containsKey(name)) {
scopedObjects.put(name, objectFactory.getObject());
}
return scopedObjects.get(name);
}
@Override
public void registerDestructionCallback(String name, Runnable callback) {
destructionCallbacks.put(name, callback);
}
@Override
public Object remove(String name) {
throw new UnsupportedOperationException();
}
@Override
public String getConversationId() {
return null;
}
@Override
public Object resolveContextualObject(String key) {
return null;
}
public static class TestExecutionListener implements org.springframework.test.context.TestExecutionListener {
@Override
public void afterTestMethod(TestContext testContext) throws Exception {
ConfigurableApplicationContext applicationContext = (ConfigurableApplicationContext) testContext
.getApplicationContext();
TestMethodScope scope = (TestMethodScope) applicationContext.getBeanFactory().getRegisteredScope(NAME);
scope.destructionCallbacks.values().forEach(callback -> callback.run());
scope.destructionCallbacks.clear();
scope.scopedObjects.clear();
}
}
@Component
public static class ScopeRegistration implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException {
factory.registerScope(NAME, new TestMethodScope());
}
}
}
只需注册测试执行监听器,所有 @Scope("testMethod")
注解类型的每个测试都会有一个实例:
@RunWith(SpringRunner.class)
@SpringBootTest
@TestExecutionListeners(listeners = TestMethodScope.TestExecutionListener.class,
mergeMode = MergeMode.MERGE_WITH_DEFAULTS)
public class MyTest {
@Autowired
// ... types annotated with @Scope("testMethod")
}
关于java - Spring bean 范围为 "one object per test method",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56342167/