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



单元测试中有很多关于请求范围管理的问题,主要答案是不测试范围管理,因为它是 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 替换请求范围,那么在这两个测试中,我会收到相同的 MyServiceMyComponent 实例,因此例如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...
}

最新更新