Java 单元测试中的请求范围bean管理

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

关于单元测试中的请求范围管理有很多问题,主要的答案是不要测试范围管理,因为它是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());
    }

}
我想测试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...
}