2012-04-17 72 views
1

单元测试中有很多关于请求作用域管理的问题,主要答案是不测试作用域管理,因为它是Spring框架的一项任务,应该注意它的正常工作。所以建议,例如,将XML请求范围替换为XML配置文件中的线程或原型类型范围。单元测试中的请求作用域Bean管理

对于大多数测试来说,没有关于未注册“请求”范围和测试运行良好的投诉。但我确实有一个案例不足。

考虑以下情况:

@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请求范围,然后由这两个测试中,我会接受的MyServiceMyComponent同一个实例,因此,例如test2()可以从MyComponent得到不好的结果,因为它可以在内部包含从一些内部的“垃圾”以前test1()

方案B

如果我有原型范围替换请求范围 - 我会得到我的地方测试方法receivin的情况下g MyComponent的不同实例与MyService不同 - 因此我无法对它们执行任何断言。

所以我需要的是一种与测试方法相关的请求范围,其中所有请求范围的bean只保留在test1()方法中,然后被销毁,所以在下一个test2()中,它们将再次被新创建。

可能吗?

回答

0

这可能不是你要找的,但你为什么首先使用Spring来管理你的测试类?这对我来说似乎有点矫枉过正。对于单元测试,你不应该需要一个DI容器。只是嘲笑依赖关系,并关注您正在测试的组件或服务的封装功能。

虽然在使用字段注入时您将无法做到这一点。您需要转换为构造函数或方法注入。

+0

目前我正在进行的一种集成测试。对于小的单元测试,我不使用DI,但在这种情况下 - 它的更大和更多的注入出现(示例被简化,以更好地解释) - 所以它是矫枉过正的重做所有工作手动春天通常做的... – Laimoncijus 2012-04-17 16:40:20

+1

I看看你现在在说什么。但是,如何注入'Component'仍然存在代码异味。您希望Spring为每次测试重新注入它,但即使在原型范围(变体B)中也不会发生。 Spring只会注入一次对象。要做你想做的事情,你必须为每个需要的对象实际拥有一个'Context'和_ask_ Spring的副本。另外,你是否可以通过'MyService'对象访问需要声明的状态,而不是需要单独的'Component'副本? – 2012-04-17 20:17:05

+0

你是对的,通过'MyService'通过原型访问'MyComponent'会为我做这件事,所以我不需要另外在我的测试类中使用'@ Autowire'。 – Laimoncijus 2012-04-18 12:01:21

0

通过使用@DirtiesContext注释方法,可以在单元测试中接收每种方法的新上下文。这使您可以在应用程序上下文中操作一个单元测试中的bean,而不会影响其他单元测试。

Documentation

你的榜样标注有@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... 
}