How to mock an exception when creating an instance

2019-06-19 01:04发布

问题:

Within a method, I have an exception being caught which I want to mock.

I know how to mock an object to throw an exception using mock.doSomething(), but I need to throw a remote exception when a class makes a new instance of itself.

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

I want to be able to mock everything in the try block, but I don't understand how you mock the creation of a new class, the following line to be specific:

bike = new Bicycle(this);

I have tried many different Mockito tests, such as:

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

Although I understand this will and is not working, I want to do something similar.

I have read the Mockito docs and haven't found anything useful:

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

回答1:

You can use a Mockito extension, PowerMock, in cases like this. It allows constructors to be mocked (see https://code.google.com/p/powermock/wiki/MockConstructor).

In this case, you would write something like the following test:

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

More examples can be found at: https://code.google.com/p/powermock/source/browse/trunk/modules/module-test/mockito/junit4/src/test/java/samples/powermockito/junit4/whennew/WhenNewTest.java



回答2:

You don't generally mock constructors. You can do with tools like PowerMock, but I'd generally suggest you don't.

Currently, your code isn't actually testable, if you want to control what happens when a new Bicycle is constructed. Is constructing a Bicycle actually a complex operation? Perhaps you want a BicycleFactory, which can be passed into your class as a dependency, for example - then you could mock BicycleFactory.createBicycle or whatever you call it.

Constructors are like static methods - when you use them, you're tightly bound to the specific code you're calling; there's no clean way to inject other behaviour without approaches like PowerMock's.



回答3:

Your getBicycle() now does at least two things. It retrieves ("gets") a Bicycle, and it creates a Bicycle. Ideally a method or class should do only one thing, and do it well.

Put the creation of the object in a separate method createBicycle() or separate BicycleFactory and mock that.