2017-03-07 104 views
3

情況和問題:在Spring Boot中,如何將一個或多個模擬類/ bean注入應用程序以進行集成測試?在StackOverflow上有幾個答案,但是他們專注於Spring Boot 1.4之前的情況,或者只是不適合我。使用模擬服務/組件進行Spring Boot集成測試

背景是,在下面的代碼中,設置的實現依賴於第三方服務器和其他外部系統。 Settings的功能已經在單元測試中進行過測試,因此對於完整的集成測試,我想模擬對這些服務器或系統的依賴關係,並提供虛擬值。

MockBean將忽略所有現有的bean定義並提供一個虛擬對象,但該對象在其他注入此類的類中不提供方法行爲。在測試之前使用@Before方法設置行爲不會影響注入的對象,或者不會注入其他應用程序服務(如AuthenticationService)。

我的問題:如何將我的bean注入應用程序上下文? 我的測試:

package ch.swaechter.testapp; 

import ch.swaechter.testapp.utils.settings.Settings; 
import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.mockito.Mockito; 
import org.springframework.boot.test.context.SpringBootTest; 
import org.springframework.boot.test.mock.mockito.MockBean; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Primary; 
import org.springframework.test.context.junit4.SpringRunner; 

@TestConfiguration 
@RunWith(SpringRunner.class) 
@SpringBootTest(classes = {MyApplication.class}) 
public class MyApplicationTests { 

    @MockBean 
    private Settings settings; 

    @Before 
    public void before() { 
     Mockito.when(settings.getApplicationSecret()).thenReturn("Application Secret"); 
    } 

    @Test 
    public void contextLoads() { 
     String applicationsecret = settings.getApplicationSecret(); 
     System.out.println("Application secret: " + applicationsecret); 
    } 
} 

而且吼叫應該用嘲笑的類,但沒有收到此嘲笑類服務:

package ch.swaechter.testapp; 

import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.stereotype.Service; 

@Service 
public class AuthenticationServiceImpl implements AuthenticationService { 

    private final Settings settings; 

    @Autowired 
    public AuthenticationServiceImpl(Settings settings) { 
     this.settings = settings; 
    } 

    @Override 
    public boolean loginUser(String token) { 
     // Use the application secret to check the token signature 
     // But here settings.getApplicationSecret() will return null (Instead of Application Secret as specified in the mock)! 
     return false; 
    } 
} 
+1

如果您需要調用bean然後用'@ testconfiguration'註釋類並創建模擬服務,那麼將'@ Before'的方法移動到'@ Before'的方法中,因爲Spring測試不會調用'@ Bean',謝謝您的支持 – rajadilipkolli

+0

回答!這將適用於contextLoads測試中的設置對象(值爲「應用程序密鑰」)。但是對於自動裝配設置的應用程序中的所有其他組件,將使用缺少方法定義的默認模擬對象。任何想法也注入嘲弄的對象? – swaechter

回答

0

當你用註釋一@MockBean場,春天將創建模仿註釋類,並使用它來自動裝載應用程序上下文的所有bean。

您必須創建嘲笑自己與

Settings settings = Mockito.mock(Settings.class); 

這將創建第二個模擬,導致了上述問題。

解決方案:

@MockBean 
private Settings settings; 

@Before 
public void before() { 
Mockito.when(settings.getApplicationSecret()).thenReturn("Application Secret"); 
} 

@Test 
public void contextLoads() { 
    String applicationsecret = settings.getApplicationSecret(); 
    System.out.println("Application secret: " + applicationsecret); 
} 
+0

可悲的是,這並沒有解決我的問題,所以我只是更新我的問題,以更好的方式反映我的問題。 – swaechter

6

看起來你正在使用設置對象指定的嘲笑行爲之前。 您必須在配置設置期間運行

Mockito.when(settings.getApplicationSecret()).thenReturn("Application Secret"); 

。爲了防止您可以創建特殊配置類來進行測試。

@RunWith(SpringRunner.class) 
@SpringBootTest(classes = {MyApplication.class, MyApplicationTest.TestConfig.class}) 
public class MyApplicationTest { 

    private static final String SECRET = "Application Secret"; 

    @TestConfiguration 
    public static class TestConfig { 
     @Bean 
     @Primary 
     public Settings settingsBean(){ 
      Settings settings = Mockito.mock(Settings.class); 
      Mockito.when(settings.getApplicationSecret()).thenReturn(SECRET); 
      Mockito.doReturn(SECRET).when(settings).getApplicationSecret(); 
      return settings; 
     } 

    } 

..... 

} 

此外,我會建議你使用下一個符號來表示嘲諷:

Mockito.doReturn(SECRET).when(settings).getApplicationSecret(); 

它將無法運行設置:: getApplicationSecret

+1

非常感謝,解決了我的問題! – swaechter

0

您可以使用構造函數注入在你的測試:

@Test 
public void consumeService() { 
    AuthenticationService authenticationService = new AuthenticationServiceImpl(settings); 

    Boolean logedIn authenticationService.loginUser("token"); 

} 

這將ma確保使用模擬的實例。

+0

我很抱歉,但這並不能解決我的問題。我的問題是/被嘲笑的實例不被用作依賴注入中的對象。手動創建這些服務會使依賴注入類型過時。 – swaechter

相關問題