2011-10-18 104 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