当前位置: 首页 > 知识库问答 >
问题:

初始化模拟对象-MockIto

陶成化
2023-03-14

有许多方法可以使用mockito初始化模拟对象。其中什么是最好的方法?

1.

 public class SampleBaseTestCase {

   @Before public void initMocks() {
       MockitoAnnotations.initMocks(this);
   }
@RunWith(MockitoJUnitRunner.class)
mock(XXX.class);

建议我有没有比这些更好的方法...

共有2个答案

欧阳炜
2023-03-14

现在(从V1.10.7开始)有了第四种实例化模拟的方法,它是使用一个名为mockitorule的JUnit4规则。

@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寻找用@Rule注释的TestRule的子类,并使用它们包装运行程序提供的测试语句。这样做的结果是,您可以提取@Before方法、@After方法,甚至try...catch包装器到规则中。您甚至可以像ExpectedException那样从测试中与这些交互。

MockitoRule的行为几乎与MockitoJUnitRunner完全相同,只是您可以使用任何其他运行程序,例如Parameterized(它允许测试构造函数接受参数,以便测试可以多次运行),或者Robolectric的测试运行程序(因此它的类加载器可以为Android原生类提供Java替代)。这使得它在最近的JUnit和Mockito版本中使用更加灵活。

总而言之:

  • mockito.mock():没有批注支持或使用验证的直接调用。
  • mockitoannotations.initmocks(this):批注支持,没有使用验证。
  • MockitoJUnitRunner:批注支持和使用验证,但必须使用该运行程序。
  • mockitorule:任何JUnit运行程序的批注支持和使用验证。

另请参见:JUnit@rule如何工作?

苏振国
2023-03-14

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

JUnit4.5运行程序初始化用Mock注释的模拟,因此不需要显式使用mockitoAnnotations.initMocks(Object)。在每个测试方法之前初始化模拟。

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

第二个解决方案(带有mockitojunitrunner)是更经典的,也是我最喜欢的。代码更简单。使用runner提供了自动验证框架使用的巨大优势(由@David Wallace在本答案中描述)。

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

@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));
    }
}

优点:代码最小

缺点:黑魔法。IMO这主要归功于@InjectMocks注释。有了这个注解“您松了代码的痛苦”(参见@brice的伟大评论)

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

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...)

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

我的命令是一种妥协。将@mock批注与@runwith(MockitoJUnitRunner.class)一起使用,但不要使用@injectMocks:

@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));
    }
}

优点:您清楚地演示了api是如何工作的(我的articleManager是如何实例化的)。没有样板代码。

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

 类似资料:
  • 问题内容: 有很多方法可以使用MockIto初始化模拟对象。其中最好的方法是什么? 1。 2。 [编辑] 3。 如果有其他方法可以建议我… 问题答案: 对于模拟初始化,使用或是严格等效的解决方案。从MockitoJUnitRunner的javadoc中: 当你已经在测试用例上配置了特定的运行器时,可以使用第一个解决方案(带有)。 第二个解决方案(带有)更经典,也是我的最爱。代码更简单。使用转轮提供

  • 问题内容: 我在用Java工作。 我通常会这样设置一些对象: 问题是:在此示例中是否等于,按原样我可以假定对未初始化的对象进行空检查将是准确的? 问题答案: 正确,未显式初始化的引用类型的静态成员和实例成员都由Java 设置为。相同的规则适用于数组成员。 根据Java语言规范的第4.12.5节: 变量的初始值 程序中的每个变量在使用值之前都必须具有一个值: 每个类变量,实例变量或数组组件在创建时均

  • 问题内容: 我想问一下Java初始化的格式。 我目前所知道的是: 等等 现在,在main类中,我想初始化一个,我不知道该怎么做? 问题答案: 首先,文件是对象类型,与int和double不同,它们是原始类型。我不确定您对Java有多熟悉,但是要创建一个对象,请使用该对象的构造函数。 File具有一个构造函数,该构造函数接收该文件在计算机上的位置字符串。

  • 前面一节的 Fruit 类有两个实变量,分别表述水果的类型和状态.直到为这个类写了一个定制的inspect方法,我们方才了解它不会对一个缺乏属性的水果做出合理的解释.幸运的是,Ruby提供了一种允许实变量总是被初始化的方法. initalize方法 当Ruby创建一个新对象时,它总是会寻找一个名为 initialize 的方法并执行它.因此,我们可以简单通过一个initialize方法向实变量中加

  • 我在使用Mockito进行单元测试初始化对象时遇到了一些困难 这是我的测试代码 要测试的代码 RecTangleService、CircleService和SquareService用注释我尝试了很多选项,最终得出结论。我没有得到我错在哪里。我试着在网上搜索了很多地方,但找不到任何帮助。