Spring bean范围“每个测试方法一个对象”

时间:2019-05-28 12:21:13

标签: java spring spring-boot dependency-injection spring-test

我有一个测试实用程序,需要为每个测试方法提供一个新实例(以防止状态在测试之间泄漏)。到目前为止,我使用的是“原型”范围,但现在我希望能够将该实用程序连接到另一个测试实用程序中,并且每个测试的连接实例应该相同。

这似乎是一个标准问题,所以我想知道是否存在“测试方法”范围或类似的东西?

这是测试类和测试实用程序的结构:

@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注释。所以我正在寻找更好的解决方案。

2 个答案:

答案 0 :(得分:0)

前段时间我遇到了同样的问题,并提出了以下解决方案:

  1. 使用假人
  2. 我编写了一些方法来创建特定的模仿设置,以向每个模仿添加行为。

因此,使用以下方法和bean定义创建一个TestConfiguration类。

    private MockSettings createResetAfterMockSettings() {
        return MockReset.withSettings(MockReset.AFTER);
    }

    private <T> T mockClass(Class<T> classToMock) {
        return mock(classToMock, createResetAfterMockSettings());
    }

您的bean定义将如下所示:

@Bean
public TestDriver testDriver() {
    return mockClass(TestDriver .class);
}

MockReset.AFTER用于在运行测试方法后重置模拟。

最后将TestExecutionListeners添加到您的Test类:

@TestExecutionListeners({ResetMocksTestExecutionListener.class})

答案 1 :(得分:0)

实现.react-autosuggest__container { position: relative; } .react-autosuggest__input { width: 240px; height: 30px; padding: 10px 20px; font-family: Helvetica, sans-serif; font-weight: 300; font-size: 16px; border: 1px solid #aaa; border-radius: 4px; } .react-autosuggest__input:focus { outline: none; } .react-autosuggest__container--open .react-autosuggest__input { border-bottom-left-radius: 0; border-bottom-right-radius: 0; } .react-autosuggest__suggestions-container { position: absolute; top: 51px; width: 280px; margin: 0; padding: 0; list-style-type: none; border: 1px solid #aaa; background-color: #fff; font-family: Helvetica, sans-serif; font-weight: 300; font-size: 16px; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; z-index: 2; } .react-autosuggest__suggestion { cursor: pointer; padding: 10px 20px; } .react-autosuggest__suggestion--focused { background-color: #ddd; } 范围实际上很容易:

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")