首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >初始化模拟对象- MockIto

初始化模拟对象- MockIto
EN

Stack Overflow用户
提问于 2013-03-19 16:49:22
回答 8查看 255.9K关注 0票数 151

使用MockIto初始化模拟对象的方法有很多种。这些方法中最好的方法是什么?

1.

代码语言:javascript
复制
 public class SampleBaseTestCase {

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

代码语言:javascript
复制
@RunWith(MockitoJUnitRunner.class)

代码语言:javascript
复制
mock(XXX.class);

建议我,如果有比这些更好的方法...

EN

回答 8

Stack Overflow用户

回答已采纳

发布于 2013-03-19 16:53:41

对于模拟的初始化,使用运行器或MockitoAnnotations.initMocks是严格等价的解决方案。在MockitoJUnitRunner的javadoc中:

JUnit 4.5 runner初始化使用模拟注释的模拟,因此不需要显式使用MockitoAnnotations.initMocks(对象)。Mock在每个测试方法之前被初始化。

当您已经在测试用例上配置了特定的运行器(例如,SpringJUnit4ClassRunner)时,可以使用第一个解决方案(使用MockitoAnnotations.initMocks)。

第二种解决方案(使用MockitoJUnitRunner)更经典,也是我最喜欢的。代码更简单。使用runner提供了的巨大优势(由@David Wallacethis answer中描述)。

这两种解决方案都允许在测试方法之间共享模拟(和间谍)。再加上@InjectMocks,它们可以非常快速地编写单元测试。减少了样板模拟代码,测试更容易阅读。例如:

代码语言:javascript
复制
@RunWith(MockitoJUnitRunner.class)
public class ArticleManagerTest {

    @Mock private ArticleCalculator calculator;
    @Mock(name = "database") private ArticleDatabase dbMock;
    @Spy private UserProvider userProvider = new ConsumerUserProvider();

    @InjectMocks private ArticleManager manager;

    @Test public void shouldDoSomething() {
        manager.initiateArticle();
        verify(database).addListener(any(ArticleListener.class));
    }

    @Test public void shouldDoSomethingElse() {
        manager.finishArticle();
        verify(database).removeListener(any(ArticleListener.class));
    }
}

优点:代码很少

缺点:黑魔法。这主要是由于@InjectMocks注解造成的。有了这个注解,“你就轻松了代码的痛苦”(参见@Brice的精彩评论)

第三个解决方案是在每个测试方法上创建您的模拟。正如@mlk在其答案中所解释,它允许进行“自包含测试”。

代码语言:javascript
复制
public class ArticleManagerTest {

    @Test public void shouldDoSomething() {
        // given
        ArticleCalculator calculator = mock(ArticleCalculator.class);
        ArticleDatabase database = mock(ArticleDatabase.class);
        UserProvider userProvider = spy(new ConsumerUserProvider());
        ArticleManager manager = new ArticleManager(calculator, 
                                                    userProvider, 
                                                    database);

        // when 
        manager.initiateArticle();

        // then 
        verify(database).addListener(any(ArticleListener.class));
    }

    @Test public void shouldDoSomethingElse() {
        // given
        ArticleCalculator calculator = mock(ArticleCalculator.class);
        ArticleDatabase database = mock(ArticleDatabase.class);
        UserProvider userProvider = spy(new ConsumerUserProvider());
        ArticleManager manager = new ArticleManager(calculator, 
                                                    userProvider, 
                                                    database);

        // when 
        manager.finishArticle();

        // then
        verify(database).removeListener(any(ArticleListener.class));
    }
}

优点:您清楚地演示了api是如何工作的(BDD...)

缺点:有更多的样板代码。( mocks创建)

My建议是一种折衷方案。对@RunWith(MockitoJUnitRunner.class)使用@Mock注释,但不要使用@InjectMocks

代码语言:javascript
复制
@RunWith(MockitoJUnitRunner.class)
public class ArticleManagerTest {

    @Mock private ArticleCalculator calculator;
    @Mock private ArticleDatabase database;
    @Spy private UserProvider userProvider = new ConsumerUserProvider();

    @Test public void shouldDoSomething() {
        // given
        ArticleManager manager = new ArticleManager(calculator, 
                                                    userProvider, 
                                                    database);

        // when 
        manager.initiateArticle();

        // then 
        verify(database).addListener(any(ArticleListener.class));
    }

    @Test public void shouldDoSomethingElse() {
        // given
        ArticleManager manager = new ArticleManager(calculator, 
                                                    userProvider, 
                                                    database);

        // when 
        manager.finishArticle();

        // then 
        verify(database).removeListener(any(ArticleListener.class));
    }
}

优点:你清楚地演示了你的应用编程接口是如何工作的(我的ArticleManager是如何实例化的)。没有样板代码。

缺点:测试不是自包含的,更少的代码痛苦

票数 173
EN

Stack Overflow用户

发布于 2015-07-23 07:56:38

现在(从v1.10.7开始)有了第四种实例化mock的方法,那就是使用一个名为MockitoRule的JUnit4规则。

代码语言:javascript
复制
@RunWith(JUnit4.class)   // or a different runner of your choice
public class YourTest
  @Rule public MockitoRule rule = MockitoJUnit.rule();
  @Mock public YourMock yourMock;

  @Test public void yourTestMethod() { /* ... */ }
}

JUnit查找subclasses of TestRule annotated with @Rule,并使用它们包装Runner提供的测试语句。这样做的结果是,您可以将@Before方法、@After方法甚至try...catch包装器提取到规则中。您甚至可以在测试中与它们进行交互,就像ExpectedException所做的那样。

MockitoRule的行为和MockitoJUnitRunner几乎完全一样,除了你可以使用任何其他的运行器,比如Parameterized (它允许你的测试构造函数接受参数,这样你的测试就可以多次运行),或者Robolectric的测试运行器(所以它的类加载器可以为Android原生类提供Java替代)。这使得它在最新的JUnit和Mockito版本中的使用更加灵活。

总而言之:

没有批注支持或用法validation.

  • MockitoAnnotations.initMocks(this):批注支持
  • Mockito.mock():直接调用,没有用法validation.
  • MockitoJUnitRunner:批注支持和用法验证,但您必须将runner.
  • MockitoRule:批注支持和用法验证用于任何JUnit运行器。

另请参阅:How JUnit @Rule works?

票数 32
EN

Stack Overflow用户

发布于 2013-03-19 17:48:13

有一种很好的方法可以做到这一点。

  • 如果是单元测试,你可以这样做:

@RunWith(MockitoJUnitRunner.class)公共类MyUnitTest { @Mock private MyFirstMock myFirstMock;@Mock private MySecondMock mySecondMock;@Spy private MySpiedClass mySpiedClass = new MySpiedClass();//它将根据反射将2个模拟和间谍对象注入到此对象// @InjectMock的java文档很好地解释了它如何以及何时进行注入@InjectMocks MyClassToTest myClassToTest;@Test public void testSomething() {}}

  • 编辑:如果是集成测试,您可以这样做(不打算在Spring中以这种方式使用。只要展示一下你可以用不同的Runner初始化mock):

@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("aplicationContext.xml")公共类MyIntegrationTest { @Mock private MyFirstMock myFirstMock;@Mock private MySecondMock mySecondMock;@Spy private MySpiedClass mySpiedClass = MySpiedClass();//它将根据反射将2个模拟和间谍对象注入到此对象// @InjectMock的java文档很好地解释了它如何以及何时进行注入@InjectMocks MyClassToTest myClassToTest;@在公共空setUp()之前抛出异常{ MockitoAnnotations.initMocks(this);}@测试公共空testSomething() {} }

票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15494926

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档