2014-01-10 72 views
9

的Java類(稱爲ServiceCaller)我要測試的多個嘲笑了這一點:如何注入相同的接口

@Autowired @Qualifier(value="serviceA") 
SomeService serviceA; 

@Autowired @Qualifier(value="serviceB") 
SomeService serviceB; 

(有一個doWork()方法,將檢查的條件,並呼籲A或B) 。

如何將每個服務的模擬注入相應的變量?

Junit有這樣的:

@InjectMocks ServiceCaller classUnderTest = new ServiceCaller(); 

@Mock SomeService mockServiceA; 
@Mock SomeService mockServiceB; 

然而,當我跑我的測試,以檢查服務A/B正確的情況下叫,我得到空指針作爲模擬尚未注入。

顯然它是因爲在同一個接口上的多個依賴關係(SomeService)。有沒有一種方法可以在聲明模擬服務時指定限定符?還是我需要爲依賴關係設置setter並設置舊式的方式?

回答

11

它應該足以給您的嘲笑serviceA和serviceB命名。來自Mockito documentation

Property setter injection; mocks將首先通過類型來解析,然後, 如果存在多個屬性相同的類型,則通過匹配 屬性名稱和模擬名稱。

在您的例子:

@InjectMocks ServiceCaller classUnderTest; 

@Mock SomeService serviceA; 
@Mock SomeService serviceB; 

請注意,這是沒有必要使用@InjectMocks時手動創建類的實例。不過我個人更喜歡使用構造函數注入依賴關係。它使得在測試中注入模擬變得更加容易(只需使用模擬調用構造函數 - 沒有反射工具或@InjectMocks(這很有用,但隱藏了某些方面))。另外使用TDD它清楚地顯示了被測試類需要什麼依賴關係,並且IDE還可以生成構造函數存根。

Spring框架完全支持構造器注入:

@Bean 
public class ServiceCaller { 
    private final SomeService serviceA; 
    private final SomeService serviceB; 

    @Autowired 
    public ServiceCaller(@Qualifier("serviceA") SomeService serviceA, 
         @Qualifier("serviceB") SomeService serviceB) { ... } 

    ... 
} 

該代碼可以進行測試:

@Mock SomeService serviceA; 
@Mock SomeService serviceB; 

//in a setup or test method 
ServiceCaller classUnderTest = new ServiceCaller(serviceA, serviceB); 
+0

太棒了!希望它可以像這樣簡單並且有效。謝謝Szpak! – shuttsy

+0

在你寫的最後一行代碼中: @InjectMocks ServiceCaller classUnderTest; – Vjeetje

+0

是的,但請閱讀我的答案中的文字,以瞭解爲什麼我通常更願意明確地在測試中調用構造函數。 –

1

可以用 「名」 屬性來定義您的實例是這樣的:

@Mock(name="serviceA") SomeService serviceA; 
@Mock(name="serviceB") SomeService serviceB; 
+0

您是否可以提供任何進一步的詳細信息來解釋您的答案如何增加接受的答案尚未提供的任何價值? –

+0

沒有其他特殊的價值,但另一種方式 – osiris256