2012-03-21 61 views
25

我正在嘗試爲其有幾個標記爲@Autowired的字段編寫單元測試。鑑於Spring自動解析這些字段的具體實現,我很難弄清楚如何在測試運行期間將我的Mock對象(通過EasyMock創建)作爲依賴關係。在課堂中使用@Autowired意味着在該課程中缺乏setter。有沒有辦法讓我插入我的模擬對象,而無需在課堂上創建額外的setter?使用Junit和EasyMock測試一個具有自動掛接符號的類嗎?

這裏是什麼,我試圖完成一個例子:

public class SomeClassUnderTest implements SomeOtherClass{ 

@Autowired 
private SomeType someType; 

@Autowired 
private SomeOtherType someOtherType; 

@Override 
public SomeReturnType someMethodIWouldLikeToTest(){ 
//Uses someType and someOtherType and returns SomeReturnType 
} 

} 

下面是我手工製作我的測試類我撞到牆前:

public class MyTestClassForSomeClassUnderTest{ 
    private SomeType someType; 
    private SomeOtherType someOtherType; 

    @Before 
    public void testSetUp(){ 
    SomeClassUnderTest someClassToTest = new SomeClassUnderTest(); 
    someType = EasyMock.createMock(SomeType.class); 
    someOtherType = EasyMock.createMock(SomeOtherType.class); 
    //How to set dependencies???? 
    } 

    @Test 
    public void TestSomeMethodIWouldLikeToTest(){ 
    //?????? 
    } 

} 

這將是巨大的,得到推向正確的方向。

由於

回答

34

ReflectionTestUtils使用,例如可以反射地直接依賴注入領域

ReflectionTestUtils.setField(testInstance, "fieldName", fieldValue); 

有人會說,這是最好的包裝可見setter方法添加到類,無論如何,僅由測試中使用。或者,使用自動裝配構造函數而不是自動裝配字段,並將測試依賴注入到該構造函數中。

+0

謝謝你的提示。 – 2012-03-21 18:06:07

+1

http://stackoverflow.com/questions/16426323/injecting-into-autowired-variable-during-testing – Dan 2015-02-13 00:17:05

+0

EasyMock支持從Mockito 3.2版本的類似註釋模擬注入。看到我的答案。 – krm 2015-12-08 17:13:52

6

儘管可以通過反射來設置這些字段,但這樣做會阻止您的開發工具找到這些字段的用法,並且使您很難在將來重構SomeClassToTest

最好爲這些字段添加公共setter,並將@Autowired註釋放在這些字段上。這不僅避免了反射,而且還闡明瞭類的外部接口,並確保您的單元測試僅使用此接口。我看到SomeClassToTest已經實現了SomeOtherClass接口,並且我認爲SomeClassToTest的客戶端只使用這個接口,所以在使SomeClassToTest上的設置者公開時幾乎沒有危險。

更好的是,使用構造函數注入並使字段最終。您仍然可以在構造函數參數上使用@Autowired

1

我不推薦已被接受的答案,即使用自己的反射(沒有模擬框架)。

由於EasyMock 3.2的版本,您可以使用註釋來定義模擬並將它們注入到被測試的類中。完整描述如何做到這一點可以EasyMock的官方文檔中找到: http://easymock.org/user-guide.html#mocking-annotations

下面是從上述網站的例子:

import static org.easymock.EasyMock.*; 
import org.easymock.EasyMockRunner; 
import org.easymock.TestSubject; 
import org.easymock.Mock; 
import org.junit.Test; 
import org.junit.runner.RunWith; 

@RunWith(EasyMockRunner.class) 
public class ExampleTest { 

    @TestSubject 
    private ClassUnderTest classUnderTest = new ClassUnderTest(); // 2 

    @Mock 
    private Collaborator mock; // 1 

    @Test 
    public void testRemoveNonExistingDocument() { 
    replay(mock); 
    classUnderTest.removeDocument("Does not exist"); 
    } 
}