2016-03-17 55 views
1

我正在爲使用Mockito的彈簧應用程序編寫單元測試,以下是服務類的單元測試。Mockito初始化構造器內的實例變量時出錯

服務類:

@Service 
class MyServiceImpl implements MyService{ 
    @Autowired 
    private ExternalService externalService; 

    MyServiceImpl() { 
     int value = externalService.getValues(); 
    } 


} 

正如你可以看到我使用初始化從名爲ExternalService服務類,這是自動裝配Autowired的方法構造函數中的一個實例變量。

測試類:

public class LotteryServiceImplTest { 
    @InjectMocks 
    private MyServiceImpl myService; 

    @Mock 
    private ExternalService externalService; 

    @Before 
    public void init() { 
     MockitoAnnotations.initMocks(this); 
    } 

    @Test 
    public void testGetLotteryResult() { 
     //test specific code 
    } 
} 

當我運行測試它給出了一個錯誤:

org.mockito.exceptions.base.MockitoException: 
    Cannot instantiate @InjectMocks field named 'value' of type 'MyServiceImpl'. 
    You haven't provided the instance at field declaration so I tried to construct the instance. 
    However the constructor or the initialization block threw an exception : null 

我怎麼能注入測試對象之前創建模擬服務當測試對象的構造取決於模擬?

回答

1

問題在於你在MyServiceImpl類中注入和使用ExternalService依賴關係的方式。 @Autowired由BeanPostProcessor()處理,該BeanPostProcessor()在Bean實例化後運行。因此,只有在構造函數運行後才初始化externalService引用的值。所以你不能在你的構造函數中使用它,因爲那時它仍然是空的;

您可以通過移動此行來解決此問題int value = externalService.getValues();從構造函數到商業方法。

如果你想在啓動時初始化一次值,你可以使用一個@PostConstruct初始化回調的像這樣

@Service 
class MyServiceImpl implements MyService{ 
    @Autowired 
    private ExternalService externalService; 
    private int value; 

    MyServiceImpl() { 

    } 

    @PostConstruct 
    public void initValue(){ 
     value = externalService.getValues(); 
    } 
} 
1

你試圖實例MyServiceImpl類和自動裝配externalService變量是以下行絕對空在MyServiceImpl構造

int value = externalService.getValues(); 

爲了要的Mockito創建一個模擬它調用根據您的文章沒有任何參數的構造函數。所以結果將是NullPointerException

執行此初始化的最佳位置之一是在@Before帶註釋的方法中,您可以使用setter方法調用externalService.getValues()並設置value實例變量。