学习存根和模拟的问题:无法将模拟类与单元测试链接

时间:2019-06-18 07:22:51

标签: java junit mockito

首先,我对模拟和存根有一个一般性的问题。我真的看不出这两个词之间的区别。 到目前为止,这是我所知道的: 当创建一个单元测试并且被测试的方法从另一个类调用一个方法时,应该使用一个模拟对象。包含被调用方法的类必须被模拟。现在,我必须决定是否进行嘲笑或存根。

模拟:我只是检查我正在测试的方法是否从模拟类中调用另一个方法。

存根:由于我不想依赖被调用方法背后的代码,因此我预定义了在调用该方法时应返回的内容。因此,即使被测方法调用了尚未实现的方法,我也可以进行单元测试。

我很确定,我还不太了解关于嘲笑和存根的一切。这可能就是我自己无法解决以下问题的原因。

这是我要为其创建UnitTest的方法。 getCharge在一个名为Movie的类中:

    double getCharge(int daysRented) {
        return price.getCharge(daysRented);
    }

以下是电影类的一些重要代码:

public class Movie {

    public static final int CHILDRENS = 2;
    public static final int REGULAR = 0;
    public static final int NEW_RELEASE = 1;

    private Price price;

    private String title;

    public Movie(String title, int priceCode) {
        if (title == null) {
            throw new IllegalArgumentException("Title cannot be null");
        } else if (title.isBlank()) {
            throw new IllegalArgumentException("Title cannot be empty");
        }
        this.title = title;
        this.setPriceCode(priceCode);
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        if (title == null) {
            throw new IllegalArgumentException("Title cannot be null");
        } else if (title.isBlank()) {
            throw new IllegalArgumentException("Title cannot be empty");
        }
        this.title = title;
    }

    double getCharge(int daysRented) {
        return price.getCharge(daysRented);
    }

    public void setPriceCode(int priceCode) {
        switch (priceCode) {
        case REGULAR:
            price = new RegularPrice();
            break;
        case CHILDRENS:
            price = new ChildrensPrice();
            break;
        case NEW_RELEASE:
            price = new NewReleasePrice();
            break;
        default:
            throw new IllegalArgumentException("Incorrect Price Code");
        }
    }

    public int getFrequentRenterPoints(int daysRented) {
        if (daysRented <= 0) {
            throw new IllegalArgumentException("Rented days have to be more than 0.");
        }
        return price.getFrequentRenterPoints(daysRented);
    }

}

在进行单元测试时,我不想使用价格类的逻辑。因此,我模拟了价格类并预定义了价格类的getCharge-Method应该返回什么:

    @Test
    public void testGetCharge() {
        // given
        Price mockedPrice = Mockito.mock(Price.class);
        when(mockedPrice.getCharge(3)).thenReturn(3.0);
        // when
        double expected = 3.0;
        double actual = movie.getCharge(3);

        assertEquals(expected, actual);

    }

很显然,这是行不通的,因为我没有将我的嘲笑的价格链接到我的电影类中的价格对象。问题是我只能使用setPriceCode设置价格对象(请参见Movie类的构造方法)。这就是我被困住的地方。有什么解决方案可以在不创建其他设置器方法的情况下设置价格?

1 个答案:

答案 0 :(得分:0)

Mockito提供@InjectMocks批注,该批注进行了一些反射魔术,并将使用@Mock注释的测试的任何字段“推”到被测类中。有关一些指导,请参见here

@InjectMocks有点棘手,因为它在无法完成工作时不会向您提供任何提示,因此它只是不会注入模拟对象,您一直想知道为什么测试会以奇怪的方式表现。 / p>

使用该批注的替代方法是“某种其他方式的依赖项注入”,例如,通过使用一个构造函数,该构造函数将需要模拟的对象用于测试。

关于嘲笑还是存根……实际上,这两个词没有确切的定义。例如,您可以获得一些想法here。有人告诉您,模拟需要一个说明,例如返回什么。对于嘲笑,这不一定是正确的,因为当您在嘲笑对象上调用返回值的方法(例如null或0)时,Mockito将返回一些默认值。