单元测试中有很多关于请求范围管理的问题,主要答案是不测试范围管理,因为它是 Spring 框架任务,它应该注意它正常工作。因此,例如,建议将请求范围替换为 XML 配置文件中的线程或原型类型范围。
对于大多数测试来说,它就足够了,没有关于未注册"请求"范围的投诉,并且测试运行良好。但我确实有一个案例,这还不够。
考虑以下情况:
@Component
@Scope("request")
public class MyService {
@Autowired
private MyComponent component;
public void doSomething(String param) {
component.doTheThing(param);
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:my-scope-tweaks.xml"})
public class MyServiceTest {
@Autowired
private MyService service;
@Autowired
private MyComponent component;
@Test
public void test1() {
service.doSomething("aaa");
assertEquals("AAA", component.getTheThing());
}
@Test
public void test1() {
service.doSomething("bbb");
assertEquals("BBB", component.getTheThing());
}
}
我想测试我的服务,它是请求范围的。 MyComponent
也是请求范围。
备选案文A
如果我用 SimpleThreadScope
替换请求范围,那么在这两个测试中,我会收到相同的 MyService
和 MyComponent
实例,因此例如test2()
可能会从MyComponent
收到不好的结果,因为它可能在内部包含一些来自以前test1()
的内部"垃圾"
备选案文B
如果我用原型范围替换请求范围 - 我会得到我的测试方法像MyService
一样接收不同的MyComponent
实例的情况 - 所以我无法对它们执行任何断言。
所以我需要的是与测试方法相关的请求作用域,其中所有请求范围的 bean 仅在test1()
方法期间保留,然后被销毁,因此在接下来的test2()
内它们将再次被重新创建。
可能吗?
这可能不是你要找的,但是为什么你首先使用Spring来管理你的测试类呢? 这对我来说似乎有点矫枉过正。 对于单元测试,不需要 DI 容器。 只需模拟依赖项,并专注于正在测试的组件或服务的封装功能。
但是,在使用场注入时,您将无法做到这一点。 需要转换为构造函数或方法注入。
通过使用 @DirtiesContext
注释方法,可以为单元测试中的每个方法接收新的上下文。 这允许您在应用程序上下文中为一个单元测试操作 bean,而不会让它影响其他单元测试。
文档
您的示例用@DirtiesContext
注释:
@Component
@Scope("request")
public class MyService {
@Autowired
private MyComponent component;
public void doSomething(String param) {
component.doTheThing(param);
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:my-scope-tweaks.xml"})
public class MyServiceTest {
@Autowired
private MyService service;
@Autowired
private MyComponent component;
@Test
@DirtiesContext
public void test1() {
service.doSomething("aaa");
assertEquals("AAA", component.getTheThing());
}
@Test
@DirtiesContext
public void test2() {
service.doSomething("bbb");
assertEquals("BBB", component.getTheThing());
}
}
如果类中的所有测试方法都需要新的上下文,您也可以按如下方式对类进行注释:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:my-scope-tweaks.xml"})
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
public class MyServiceTest {
//Tests Here...
}