2011-10-18 101 views
6

我的問題與Injecting Mockito mocks into a Spring bean中提出的問題非常相似。事實上,我相信那裏可以接受的答案可能對我有用。然而,我有一個問題的答案,然後一些進一步的解釋,如果答案沒有實際上我的答案。Spring + Mockito測試注入

所以我跟着上述帖子中的鏈接到了Springockito網站。我改變了我的test-config.xml將包括類似如下的內容:

<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:mockito="http://www.mockito.org/spring/mockito" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
    http://www.mockito.org/spring/mockito http://www.mockito.org/spring/mockito.xsd"> 

... 

    <mockito:mock id="accountService" class="org.kubek2k.account.DefaultAccountService" /> 
... 
</beans> 

似乎是壞了目前www.mockito.org重定向,所以我找到了XSD代碼爲https://bitbucket.org/kubek2k/springockito/raw/16143b32095b/src/main/resources/spring/mockito.xsd,並改變了XSI的最後一項:的schemaLocation指向到這個bitbucket鏈接。

運行mvn test然後產生以下錯誤(添加新行以提高可讀性):

Caused by: org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: 
    Line 43 in XML document from class path resource [spring/test-context.xml] is invalid; 
    nested exception is org.xml.sax.SAXParseException; lineNumber: 43; columnNumber: 91; 
    The prefix "mockito" for element "mockito:mock" is not bound. 

所以關於Springockito的問題是:是否有可能再包括這個?我錯過了什麼?現在

,到進一步的解釋...

我有它的實現我想要測試接口:

public interface MobileService { 
    public Login login(Login login); 
    public User getUser(String accessCode, Date birthDate); 
} 

實施包含一個DAO是春天@Autowire S IN我:

@Service 
public class MobileServiceImpl implements MobileService { 
    private MobileDao mobileDao; 

    @Autowired 
    public void setMobileDao(MobileDao mobileDao) { 
     this.mobileDao = mobileDao; 
    } 
} 

我不想改變我的接口包括setMobileDao方法,因爲那將是添加的代碼只是爲了支持我的單位測試。我試圖嘲笑DAO,因爲這裏的實際SUT是ServiceImpl。我怎樣才能做到這一點?

回答

9

你不想測試你的接口:它根本不包含任何代碼。你想測試你的實現。所以制定者是可用的。只需使用它:

@Test 
public void testLogin() { 
    MobileServiceImpl toTest = new MobileServiceImpl(); 
    toTest.setMobileDao(mockMobileDao); 
    // TODO call the login method and check that it works as expected. 
} 

不需要一個春天的上下文。只需實例化POJO服務,手動注入模擬依賴項,然後測試要測試的方法。

+1

@Mike我同意,只是測試實施。 **單元**測試的春天背景沒有意義。順便說一下,Mockito提供了一些簡單的依賴注入機制,結合了'@ Mock'和'@InjectMocks'註釋。你應該看到他們各自的[javadoc](http://docs.mockito.googlecode.com/hg/latest/org/mockito/Mockito.html)。 – Brice

0

有三個選項來設置你的模擬道:

  1. 測試實施 - 這給出了通過setDao方法的模擬接縫。 (如JB的回答)
  2. 將setDao方法添加到接口 - 不需要,因爲您不想添加代碼來支持您的測試。
  3. 向impl類中添加構造函數以接受dao - 與#2相同的原因不需要。

如果你想做#3,你需要添加一個構造函數給接受MobileDao的MobileService。

public MobileServiceImpl(MobileDao mobileDao) { 
    this.mobileDao = mobileDao; 
} 

那麼你的測試將是這樣的:

import static org.mockito.Mockito.verify; 
import static org.mockito.Mockito.*; 

import java.util.Date; 

import org.junit.Before; 
import org.junit.Test; 

public class MobileServiceImplTest { 

    private MobileService systemUnderTest; 

    private MobileDao mobileDao; 

    @Before 
    public void setup() { 
     mobileDao = mock(MobileDao.class); 
     systemUnderTest = new MobileServiceImpl(mobileDao); 
    } 

    @Test 
    public void testGetUser() { 
     //if you need to, configure mock behavior here. 
     //i.e. when(mobileDao.someMethod(someObject)).thenReturn(someResponse); 
     systemUnderTest.getUser("accessCode", new Date()); 

     verify(mobileDao).getUser("JeffAtwood"); 
    } 
} 

請注意,所以我創建了一個接受字符串一個的getUser方法,你還沒有給我們提供了MobileDao的細節。

爲了使測試通過,你MobileServiceImpl將只需要這個:

mobileDao.getUser("JeffAtwood"); 
+0

就像在接口中添加一個'setMobileDao',添加另一個ctor來傳遞DAO對象將會改變代碼以支持單元測試。根據@ jb-nizet的回答,如果我改變我的測試不使用接口而是使用實現,那麼我已經可以訪問'setMobileDao'方法。 – Mike

+0

瞭解到您不想向代碼添加任何內容來支持測試。測試impl而不是界面是我過去做過的事情;)只是想給出另一種選擇。 –

0

問題看起來像你的classpath中不包含實際springockito罐子 - 你不必更改URL的 - 這些都是隻有春天在內部使用的令牌 - 它們沒有被解析 - 你需要的是在classpath上有足夠新的Spring發行版和springockito。

庫巴(上述LIB :)的作者)

0

我有同樣的問題,我通過他們根據維基但驗證XML拋出錯誤想要使用springockito。所以當我嘗試去xsd應該是的地方,那沒有。所以我讀了這個,並得到這個工作:

xmlns:mockito="http://www.mockito.org/spring/mockito" 
xsi:schemaLocation="http://www.mockito.org/spring/mockito 
    https://bitbucket.org/kubek2k/springockito/raw/16143b32095b/src/main/resources/spring/mockito.xsd"> 

但是,當我看着這個環節,有不好的感覺。在我看來,這不是永久穩定的鏈接(你必須檢查我是否有錯)

+0

似乎現在鏈接已損壞。有人有新的嗎? – schoenk

1

在與Springockito XSD問題掙扎後,我發現了一個更簡單的解決方案。讓春天注入模擬您使用工廠方法,即在applicationContext.xml中的地說:

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> 

    <bean class="org.mockito.Mockito" factory-method="mock"> 
    <constructor-arg value="com.gerrydevstory.mycoolbank.AccountsDAO"/> 
    </bean> 

    <bean class="com.gerrydevstory.mycoolbank.BankingService"/> 

</beans> 

其中AccountsDAO豆注入BankingService類。相應的JUnit測試用例是:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration("/BankingServiceTest.xml") 
public class BankingServiceTest { 

    @Autowired private BankingService bankingService; 
    @Autowired private AccountsDAO mockAccountsDAO; 

    @Test 
    public void testTransfer() throws Exception { 
    // Setup 2 accounts 
    Account acc1 = new Account(); 
    acc1.setBalance(800.00); 
    Account acc2 = new Account(); 
    acc2.setBalance(200.00); 

    // Tell mock DAO to return above accounts when 1011 or 2041 is queried respectively 
    when(mockAccountsDAO.findById(1011)).thenReturn(acc1); 
    when(mockAccountsDAO.findById(2041)).thenReturn(acc2); 

    // Invoke the method to test 
    bankingService.transfer(1011, 2041, 500.00); 

    // Verify the money has been transferred 
    assertEquals(300.00, acc1.getBalance(), 0.001); 
    assertEquals(700.00, acc2.getBalance(), 0.001); 
    } 
} 

我個人覺得這非常優雅,容易理解。有關更多詳細信息,請參閱original blog post