2013-04-15 38 views
2

鑑於傳統應用程序有1500個spring.xmls。我想寫一個服務的單元測試。我深深地依賴於地獄。我必須接受應用程序,沒有出路。在糾結的春天背景下進行單元測試

所以我們使用spring-3.something和mockito-1.9,我想要測試服務的好方法。較新的代碼大量使用@Autowired註釋。

這個服務間接地使用了我實際上想在測試中使用的〜25個助手(工廠方法等)以及我對這個測試不感興趣的〜25個對象。

我目前嘗試以上述方式設置上下文,但我對@Mock,@InjectMocks,@Autowired的影響感到困惑。

我的測試如下。我需要幫助才能正確設置它。

問題:

  • 是什麼@InjectMocks的實際效果?
  • 我該如何決定(技術上)哪些自動佈線的豆子真的被使用,哪些被mock取代?
  • 我知道,我濫用嘲諷獲得假貨。是否有一種更簡單的方法來獲得單線的假貨?
  • * 請注意,我想明白這一點,因爲我有這樣的服務... *

這裏的負載是我的示例:

@ContextConfiguration(locations = { 
    "classpath:/some/path/MainTestConfig.spring.xml" 
}) 
@RunWith(SpringJUnit4ClassRunner.class) 
public class SampleTest { 

    // ***   Uninteresting Dependencies to be mocked  *** // 
    @Mock Mock1 mock1; 
    @Mock Mock2 mock2; 

    /** Service under test */ 
    @Autowired 
    SomeService service; 

    // ***   Tightly coupled helpers to be used    *** // 
    @Autowired Helper1 helper1 
    @Autowired Helper2 helpr2 

    @Before 
    public void setup() { 
     MockitoAnnotations.initMocks(SampleTest.class); 
    } 

    @Test 
    public void testSample() { 

     // prepare dummy context 
     SomeContext context = new Context(); 

     // define expected result 
     int expectedValue = 42; 

     //execute method under test, record result 
     Result actualResult = service.execute(context); 

     //make assertions on result 
     assertTrue(actualResult.getSomething()==expectedValue); 
    } 

} 
+0

我不明白爲什麼你會有'mock1'和'mock2'這些在你的測試中似乎沒有關係,因爲它們是不相關的。此外,助手似乎不被使用,在測試中得到驗證。如果一切都是春天連線,爲什麼你想要它。我相信你實際上應該嘲笑緊密耦合的幫手,並驗證相互作用。最終你也可以把這個測試寫成一個大功能/特性測試,即不是單元測試,也不是集成測試,因此它會被放置在其他一些軟件包中以顯示你的同事的不同之處。 – Brice

+0

順便問一下你是否嘗試過Spring 3中的註釋配置?如果你只需要注入一些依賴關係,這可能會很有用,並且這也可以用於mock(如果添加另一個maven依賴關係,則不需要使用springockito)。 – Brice

回答

4

我想發佈這個作爲一個單獨的答案,因爲這應該更好地解決您關於@Mock,@Autowired和@InjectMocks的實際問題。

@Mock:這標誌着當調用MockitoAnnotations.initMocks(this)時應該創建爲模擬的字段(使用mock(MyClass.class))。

@Autowired:標記一個字段,該字段應由Spring使用實現類/接口的bean進行分配。

@InjectMocks:標記應當由被的Mockito創建時MockitoAnnoations.initMocks(this)被稱爲場。它創建該類的一個實例,並將@Mock -annotated字段注入到此實例中。 (請參閱評論中對此聲明的更正)。

分析:

@InjectMocks不使用Spring上下文和@Autowired兼容,因爲InjectMock創建它不使用Spring實例的類的新實例。您需要使用Springockito。 (延遲更新)Springockito將允許您將模擬注入到Spring上下文中,從而將這些模擬用作Autowired候選項。它允許Mocks和Spys。在測試的同一個字段上使用ReplaceWithMockAutowired是一般慣例(如wiki上的示例所示)。

+0

**該語句不正確**:「... ...」InjectMock'創建了一個不使用Spring實例的類的新實例「。實際的Mockito行爲是,如果該字段在mockito注入時已經有一個,它將永遠不會創建一個實例。雖然我承認文檔不清楚:['InjectMocks' Javadoc](http://docs.mockito.googlecode.com/hg/latest/org/mockito/InjectMocks.html)。所以可以在spring管理bean中注入mock,**但是**我不推薦它,因爲它在測試設置中增加了很多複雜性。 – Brice

+0

@Brice所以你是說如果你在測試的同一個字段中加入'@ Autowired'和'@InjectMocks'(需要Autowired來獲取Spring bean),那麼Spring bean將被使用,它將被更新注入測試中的嘲笑? –

+0

是的。 – Brice

2

第一個問題,你需要加載spring上下文做這個測試?通常當我有Spring項目時,我有一個UNIT測試每個類不會加載上下文文件。我將有一個不同的CONTEXT測試來加載上下文文件並驗證它是否正確加載。如果你正在做真正的單元測試,我會建議不加載上下文。如果被測試的類使用@Autowired來分配依賴關係(因此沒有setter),請使用Spring的ReflectionTestUtils來指定這些字段。

+0

好吧,我測試的單位是服務+其幫助者。要做到這一點,我需要設置*一些*上下文的助手和假人無所事事。手動設置這個上下文對於50個類是不可行的,所以我想在可能的情況下重用現有的spring配置,並在可行的地方注入mock。看來我沒有得到「InjectMocks」呢...... – Bastl

+0

順便說一句:什麼是「真正的」單元測試?你認爲什麼是單位?我懷疑用「班級」或「方法」替換單元。我的單位是服務+助手。超越邊界的一切都將被嘲笑/僞造。 – Bastl

+0

「真正的」單元測試是您的測試只接觸ONE類(單元)的地方。所有其他類/依賴都被模擬。除了被測試的類外,我允許的唯一具體類是數據傳輸對象(DTO),它們只是數據持有者(字段,獲取者,設置者)。 –