Java 如何在使用Mockito创建新类的实例时模拟异常

Java 如何在使用Mockito创建新类的实例时模拟异常,java,junit,mocking,mockito,Java,Junit,Mocking,Mockito,在一个方法中,我捕获了一个异常,我想模拟它 我知道如何使用mock.doSomething()模拟对象以引发异常,但我需要在类生成自身的新实例时引发远程异常 transient Bicycle bike = null; public Bicycle getBicycle() { if (bike == null) { try { bike = new Bicycle(this); } catch (RemoteException

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

我知道如何使用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文档,但没有发现任何有用的内容:


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

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

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

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


将对象的创建放在一个单独的方法
createBicycle()
或单独的
BicycleFactory
中,并对其进行模拟。

在这种情况下,您可以使用Mockito扩展PowerMock。它允许对构造函数进行模拟(请参阅)

在本例中,您将编写类似以下测试的内容:

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

更多示例可以在以下位置找到:

我想我还没有说清楚,但是Bicycle是另一个类的实例,而不是该方法当前所在的类。该方法检索实例,但如果它为null,我想创建一个新实例。我不确定这是否会改变什么?@JohnVasiliou:不,一点也不。你仍然在调用构造函数——这根本不是你可以在测试中简单模仿的东西。在现实世界中,直接实例化依赖项是正确的做法。对于一个这样的例子,考虑一个业务服务类,它需要通过电子邮件发送通知;在Java中,一个众所周知的电子邮件API是,您通常在其中实例化
email
子类(通常是
SimpleEmail
),调用几个setter/adder,最后调用
send()
方法。它简单、面向对象、易于单元测试。@Rogério:那么您将如何进行单元测试呢?在这个示例中,我希望有两个类:一个表示电子邮件本身(不会伪造),另一个表示能够发送电子邮件的电子邮件服务,这是伪造的。@JonSkeet您可以使用PowerMock,按照我对这个问题的回答中所示的方式,为业务服务类编写一个单元测试。还可以使用JMockitAPI(我开发的)编写一个更短、更简单的测试;如果你愿意,我可以在这里显示代码。请注意,您描述的电子邮件API与中的类似,具有值对象类
SimpleEmailMessage
和无状态
MailSender
服务接口。就个人而言,我更喜欢Apache API,它更简单、更面向对象。可能与@ChristofferHammarström重复这绝对不是重复。我写了前一个问题,我正在寻找两个不同的答案。