2012-02-09 152 views
14

我試圖寫的測試類以下方法春天值注入的Mockito

public class CustomServiceImpl implements CustomService { 
    @Value("#{myProp['custom.url']}") 
    private String url; 
    @Autowire 
    private DataService dataService; 

我使用這個類中的方法之一注入url值。 爲了測試這一點,我已經寫了一個JUnit類

@RunWith(MockitoJUnitRunner.class) 
@ContextConfiguration(locations = { "classpath:applicationContext-test.xml" }) 
public CustomServiceTest{ 
    private CustomService customService; 
    @Mock 
    private DataService dataService; 
    @Before 
    public void setup() { 
     customService = new CustomServiceImpl(); 
     Setter.set(customService, "dataService", dataService); 
    }  
    ... 
} 

public class Setter { 
    public static void set(Object obj, String fieldName, Object value) throws Exception { 
     Field field = obj.getClass().getDeclaredField(fieldName); 
     field.setAccessible(true); 
     field.set(obj, value); 
    } 
} 

在的applicationContext-的test.xml我加載使用

<util:properties id="myProp" location="myProp.properties"/> 

但是URL值的屬性文件未在CustomService得到加載在運行測試。 我想知道是否有這樣做完成。

謝謝

+4

如果你正在模擬'CustomService',那麼如何使用'CustomServiceImpl'?這沒有意義。 – skaffman 2012-02-09 11:26:51

+0

我正在使用CustomeServiceImpl。更新了代碼。我怎樣才能嘲笑需要從屬性文件中讀取的url的值? – rohit 2012-02-09 13:43:46

+1

就像現在這樣,你沒有使用Spring來設置customService值,你使用下面的代碼在setup()方法中手動設置值:'customService = new CustomServiceImpl();' – DwB 2012-02-09 13:54:00

回答

3

您可以自動裝入增變器(setter),而不僅僅是註釋專用字段。然後你也可以使用你的測試類中的setter。不需要公開,私有包將會像Spring一樣可以訪問它,但除此之外,只有你的測試可以進入(或者同一包中的其他代碼)。

@Value("#{myProp['custom.url']}") 
String setUrl(final String url) { 
    this.url = url; 
} 

我不是自動裝配不同的風扇(相比,我的代碼庫)只是用於測試,但是測試下改變類,從測試的替代,簡直就是邪惡的。

+0

你知道這是否也適用於'@ Resource'註釋? – OscarRyz 2014-12-12 19:37:37

1

你不應該嘲笑你試圖測試的東西。這是毫無意義的,因爲你不會觸摸任何你想要測試的代碼。而是從上下文中獲取CustomerServiceImpl的實例。

+0

不要犯單元測試的基本罪。 – 2013-09-19 20:05:51

12

我同意@skaffman的評論。

除了你的測試使用MockitoJUnitRunner,因此它不會尋找任何春天的東西,這唯一的目的是初始化Mockito嘲笑。 ContextConfiguration不足以用彈簧將東西接線。從技術上講,如果你想要與彈簧相關的東西,你可以使用下面的跑步者:SpringJUnit4ClassRunner

另外,當你正在寫一個單元測試你可能想重新考慮使用彈簧。在單元測試中使用彈簧接線是錯誤的。但是,如果你正在寫一個集成測試那麼你爲什麼在那裏使用Mockito,它沒有任何意義(正如skaffman所說的)!

編輯:現在在你的代碼中你直接設置CustomerServiceImpl在你之前的塊,這也沒有任何意義。春天根本沒有參與!

@Before 
public void setup() { 
    customService = new CustomServiceImpl(); 
    Setter.set(customService, "dataService", dataService); 
} 

編輯2:如果你想要寫一個單元測試CustomerServiceImpl,則避免春天的東西,直接注入屬性的值。您也可以使用Mockito將DataService模擬straigth注入測試的實例。

@RunWith(MockitoJUnitRunner.class) 
public CustomServiceImplTest{ 
    @InjectMocks private CustomServiceImpl customService; 
    @Mock private DataService dataService; 

    @Before void inject_url() { customerServiceImpl.url = "http://..."; } 

    @Test public void customerService_should_delegate_to_dataService() { ... } 
} 

正如你可能我使用到url領域的直接訪問已經注意到,本場可包可見。這是一個測試解決方法,以實際注入URL值,因爲Mockito只注入嘲笑。

+0

「重新考慮使用spring」意味着重新考慮使用Spring配置文件爲_this test_執行依賴注入,對嗎?你並不是建議他放棄在他的申請中使用Spring。 – jhericks 2012-02-09 21:19:38

+4

@jhericks不,我的意思是在單元測試中刪除與Spring相關的代碼。我通常在這方面有一個難題:我不鼓勵在任何**單元測試**中使用膠水代碼,例如Sprin。 **單元測試**的目的是單獨測試生產代碼(這裏是'CustomerServiceImpl')。這實際上似乎是問題作者的意圖。如果出於某種原因需要彈簧,那麼它開始是一個**綜合測試**,它在測試中沒有相同的含義。 – Brice 2012-02-09 22:25:33

+0

編輯2解決了我的問題,謝謝! – 2017-10-26 08:18:11

31
import org.springframework.test.util.ReflectionTestUtils; 

@RunWith(MockitoJUnitRunner.class) 
public CustomServiceTest{ 

@InjectMock 
private CustomServiceImpl customService; 

@Mock 
private DataService dataService; 

@Before 
public void setup() { 
    ReflectionTestUtils.setField(customService, "url", "http://someurl"); 
}  
... 
} 
+0

你能用幾句話解釋一下你的解決方案嗎? – Magnilex 2015-04-21 16:47:59

+0

來自Rohit的問題可能有其他問題,但在尋找解決方案時,這個解決方案正是我想要的,謝謝Robert – mikeapr4 2015-07-08 15:04:28

+0

簡單而有效,我喜歡它! – 2015-07-09 13:52:53

1

我有一個字符串列表從屬性文件讀取。 @Before模塊中使用的ReflectionTestUtils類setField方法幫助我在測試執行之前設置這些值。即使對於依賴於Common DaoSupport類的我的dao圖層,它也是完美的。

@Before 
public void setList() { 
    List<String> mockedList = new ArrayList<>(); 
    mockedSimList.add("CMS"); 
    mockedSimList.add("SDP"); 
    ReflectionTestUtils.setField(mockedController, "ActualListInController", 
      mockedList); 
}