2012-04-17 73 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... 
}