首先,我对模拟和存根有一个一般性的问题。我真的看不出这两个词之间的区别。 到目前为止,这是我所知道的: 当创建一个单元测试并且被测试的方法从另一个类调用一个方法时,应该使用一个模拟对象。包含被调用方法的类必须被模拟。现在,我必须决定是否进行嘲笑或存根。
模拟:我只是检查我正在测试的方法是否从模拟类中调用另一个方法。
存根:由于我不想依赖被调用方法背后的代码,因此我预定义了在调用该方法时应返回的内容。因此,即使被测方法调用了尚未实现的方法,我也可以进行单元测试。
我很确定,我还不太了解关于嘲笑和存根的一切。这可能就是我自己无法解决以下问题的原因。
这是我要为其创建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类的构造方法)。这就是我被困住的地方。有什么解决方案可以在不创建其他设置器方法的情况下设置价格?
答案 0 :(得分:0)
Mockito提供@InjectMocks批注,该批注进行了一些反射魔术,并将使用@Mock注释的测试的任何字段“推”到被测类中。有关一些指导,请参见here。
@InjectMocks有点棘手,因为它在无法完成工作时不会向您提供任何提示,因此它只是不会注入模拟对象,您一直想知道为什么测试会以奇怪的方式表现。 / p>
使用该批注的替代方法是“某种其他方式的依赖项注入”,例如,通过使用一个构造函数,该构造函数将需要模拟的对象用于测试。
关于嘲笑还是存根……实际上,这两个词没有确切的定义。例如,您可以获得一些想法here。有人告诉您,模拟需要一个说明,例如返回什么。对于嘲笑,这不一定是正确的,因为当您在嘲笑对象上调用返回值的方法(例如null或0)时,Mockito将返回一些默认值。