【问题标题】:How to mock an exception when creating an instance of a new class using Mockito使用 Mockito 创建新类的实例时如何模拟异常
【发布时间】:2013-03-26 21:06:45
【问题描述】:

在一个方法中,我捕获了一个我想模拟的异常。

我知道如何使用 mock.doSomething() 模拟对象以引发异常,但是当类创建自身的新实例时,我需要引发远程异常。

transient Bicycle bike = null;

public Bicycle getBicycle() {
    if (bike == null) {
        try {
            bike = new Bicycle(this);
        } catch (RemoteException ex) {
            System.out.println("No bikes found");
        }
    }
    return bike;
}

我希望能够模拟 try 块中的所有内容,但我不明白您如何模拟新类的创建,具体如下:

bike = new Bicycle(this);

我尝试了许多不同的 Mockito 测试,例如:

Bicycle b = mock(Bicycle.class);
Mockito.doThrow(new RemoteException()).when(b = new Bicycle());

虽然我理解这将不会起作用,但我想做类似的事情。

我已阅读 Mockito 文档,但没有发现任何有用的信息:

http://site.mockito.org/mockito/docs/current/org/mockito/Mockito.html

【问题讨论】:

标签: java junit mocking mockito


【解决方案1】:

您通常不会模拟构造函数。您可以使用PowerMock 之类的工具,但我通常建议您不要这样做。

目前,如果您想控制在构造新的Bicycle 时会发生什么,您的代码实际上是不可测试的。构造Bicycle 实际上是一个复杂的操作吗?也许你想要一个 BicycleFactory,它可以作为依赖项传递到你的类中,例如 - 然后你可以模拟 BicycleFactory.createBicycle 或任何你称之为的东西。

构造函数就像静态方法——当你使用它们时,你会紧紧地绑定到你正在调用的特定代码;如果没有像 PowerMock 这样的方法,就没有干净的方法来注入其他行为。

【讨论】:

  • 我想我没有说清楚,但 Bicycle 是另一个类的实例,而不是这个方法当前所在的那个。该方法检索实例,但如果它是 null 我想创建一个新的。我不确定这是否会改变什么?
  • @JohnVasiliou:不,一点也不。你仍然在调用构造函数——这基本上不是你可以在测试中简单地模拟出来的东西。
  • 现实世界中有很多情况下,直接实例化依赖项是正确的做法。举一个这样的例子,考虑一个需要通过电子邮件发送通知的业务服务类;在 Java 中,众所周知的电子邮件 API 是 Apache Commons Email,您通常在其中实例化 Email 子类(通常为 SimpleEmail),调用一些 setter/adders,最后调用 send() 方法。它简单、面向对象、并且易于进行单元测试。
  • @Rogério:那么您将如何对其进行单元测试?我希望在该示例中有两个类:一个代表电子邮件本身(不会被伪造),另一个代表能够发送电子邮件的电子邮件 service - 这将被伪装出来。
  • @JonSkeet 您可以使用 PowerMock 按照我对此问题的回答中所示的方式为业务服务类编写单元测试。也可以使用 JMockit API(我开发的)编写更短、更简单的测试;如果你愿意,我可以在这里显示代码。请注意,您描述的电子邮件 API 与 Spring framework 中的类似,具有值对象类 SimpleMailMessage 和无状态 MailSender 服务接口。就个人而言,我更喜欢 Apache API,它更简单,更面向对象。
【解决方案2】:

在这种情况下,您可以使用 Mockito 扩展程序 PowerMock。它允许模拟构造函数(参见https://code.google.com/p/powermock/wiki/MockConstructor)。

在这种情况下,您可以编写如下测试:

@RunWith(PowerMockRunner.class)
@PrepareForTest({ClassUnderTest.class, Bicycle.class})
public class ConstructorMockingTest
{
    @Test
    public void getBicycle()
    {
        ClassUnderTest tested = new ClassUnderTest();
        whenNew(Bicycle.class).withArguments(tested).thenThrow(new RemoteException());

        Bicycle bicycle = tested.getBicycle();

        assertNull(bicycle);
    }
}

更多示例请访问:https://code.google.com/p/powermock/source/browse/trunk/modules/module-test/mockito/junit4/src/test/java/samples/powermockito/junit4/whennew/WhenNewTest.java

【讨论】:

    【解决方案3】:

    您的getBicycle() 现在至少做了两件事。它检索(“获取”)Bicycle,并创建Bicycle。理想情况下,一个方法或类应该只做一件事,并且做得很好。

    将对象的创建放在单独的方法 createBicycle() 或单独的 BicycleFactory 中并模拟它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-24
      • 1970-01-01
      • 2021-09-08
      • 2015-07-19
      • 2023-02-26
      • 2010-11-27
      • 2017-10-17
      • 2018-12-11
      相关资源
      最近更新 更多