Java 单元测试中的请求范围bean管理
关于单元测试中的请求范围管理有很多问题,主要的答案是不要测试范围管理,因为它是Spring框架任务,应该注意它是否正常工作。例如,建议在XML配置文件中将请求范围替换为线程或原型类型范围 对于大多数测试来说,没有关于未注册请求范围的投诉,测试运行良好。但我确实有一个案例是不够的 考虑以下情况:Java 单元测试中的请求范围bean管理,java,spring,unit-testing,junit,scope,Java,Spring,Unit Testing,Junit,Scope,关于单元测试中的请求范围管理有很多问题,主要的答案是不要测试范围管理,因为它是Spring框架任务,应该注意它是否正常工作。例如,建议在XML配置文件中将请求范围替换为线程或原型类型范围 对于大多数测试来说,没有关于未注册请求范围的投诉,测试运行良好。但我确实有一个案例是不够的 考虑以下情况: @Component @Scope("request") public class MyService { @Autowired private MyComponent componen
@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());
}
}
我想测试MyService,它是请求范围的。MyComponent也是请求范围
变体A
如果我将请求范围替换为SimpleThreadScope,那么在这两个测试中,我将收到相同的MyService和MyComponent实例,因此例如test2可能会收到MyComponent的错误结果,因为它可能在内部包含以前test1中的一些内部垃圾
变体B
如果我将请求范围替换为原型范围(prototype scope)——我的测试方法会像MyService一样接收MyComponent的不同实例——因此我无法对它们执行任何断言
所以我需要的是一种与测试方法相关的请求作用域,其中所有请求作用域bean仅在test1方法期间保留,然后被销毁,因此在下一个test2中,它们将被重新创建
可能吗?这可能不是您想要的,但是为什么您首先要使用Spring来管理您的测试类呢?这对我来说似乎太过分了。对于单元测试,您不应该需要DI容器。只需模拟依赖项,并将重点放在正在测试的组件或服务的封装功能上
但是,在使用场注入时,您将无法做到这一点。您需要转换为构造函数或方法注入。通过使用@DirtiesContext注释方法,可以为单元测试中的每个方法接收新上下文。这允许您在一个单元测试的应用程序上下文中操作bean,而不会影响其他单元测试 您的示例用@DirtiesContext注释: 如果类中的所有测试方法都需要一个新的上下文,那么也可以按如下方式注释该类:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:my-scope-tweaks.xml"})
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
public class MyServiceTest {
//Tests Here...
}
这是我目前正在做的一种集成测试。对于小型单元测试,我不使用DI,但在这种情况下——它的规模大得多,而且出现了许多注入——为了更好地解释,这个例子被简化了——因此,手动重做Spring通常所做的所有工作将是一种过分的做法……我明白您现在所说的了。然而,在注入组件的过程中仍然会有代码的味道。您希望Spring为每个测试重新注入它,但这不会发生,即使使用prototype作用域变量B。Spring只会注入对象一次。要想做你想做的事情,你必须有一个上下文的副本,并且每次都向Spring请求你需要的对象。另外,您是否可以通过MyService对象访问需要断言的状态,而不需要组件的单独副本?您是对的,通过MyService和prototype访问MyComponent对我来说是可行的,因此我不需要在测试类中另外@Autowire它。@Ryan您可以使用javax.inject.Provider来解决这个问题。前任:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:my-scope-tweaks.xml"})
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
public class MyServiceTest {
//Tests Here...
}