开发者

How to prevent super class from being mocked by jmockit?

开发者 https://www.devze.com 2023-03-22 04:32 出处:网络
Given a class hierarchy that looks like this: public class Vehicle { private String name; public Vehicle(String name) {

Given a class hierarchy that looks like this:

public class Vehicle {

    private String name;

    public Vehicle(String name) {
        this.name = name;
    }

    public String getName() {
        return 开发者_C百科name;
    }

}


public class Car extends Vehicle {

    public Car(String name) {
        super(name);
    }

    public String drive() {
        return "driving the car";
    }

    public String boardBus() {
        Bus bus = new Bus("bus to cut off");

        return bus.board();
    }

}

public class Bus extends Vehicle {

    public Bus(String name) {
        super(name);
    }

    public String board() {
        return "boarding the bus";
    }

}

I'm trying to test the Car class. However, Car also happens to make use of Bus. So, in my test, I'm trying to mock Bus. My test code looks like this:

import static org.junit.Assert.assertEquals;
import mockit.Mocked;
import mockit.NonStrictExpectations;

import org.junit.Test;

public class CarTest {

    @Test
    public void testCar() {
        final String name = "I am a car";
        final Car car = new Car(name);

        new NonStrictExpectations() {
            @Mocked Bus bus;

            {
                bus.board(); result = "test bus boarding";
            }
        };

        assertEquals("I am a car", car.getName());
    }

}

The assert fails because car.getName() returns null.

By inserting System.out.println's in the constructors for Vehicle, Car, and Bus, I'm suspecting that the "real" Vehicle that is loaded by new Car(name) is later replaced by a mocked Vehicle when the @Mocked Bus bus is executed.

Is there a way for jmockit to preserve the real Vehicle that is "instantiated" when Car is constructed?


I see two solutions:

@Test
public void boardBus_usingInstanceSpecificMockingForNewedInstances()
{
    new Expectations() {
        @Capturing @Injectable Bus bus;

        {
            bus.board(); result = "mocked";
        }
    };

    String result = new Car("myCar").boardBus();
    assertEquals("mocked", result);
}

@Test
public void boardBus_usingPartialMocking()
{
    final Bus bus = new Bus("");
    new Expectations(bus) {{ bus.board(); result = "mocked"; }};

    String result = new Car("myCar").boardBus();
    assertEquals("mocked", result);
}


There is no Vehicle "associated" with a Car - Car is a Vehicle. Association and inheritance are not the same. Therefore it's not possible to have a Car with a "mocked" Vehicle - this sentence is meaningless when Car extends Vehicle.

Are you sure there isn't a (legit) bug in either the Car's constructor or getName()? What does the code for these methods look like?

0

精彩评论

暂无评论...
验证码 换一张
取 消