Сначала у меня общий вопрос о насмешках и окурках. Я не вижу разницы между этими двумя словами.
Вот что я знаю до сих пор:
Когда создается модульный тест, а тестируемый метод вызывает метод из другого класса, следует использовать фиктивный объект. Класс, содержащий вызываемый метод, должен быть пересмотрен. Теперь я должен решить, буду ли я издеваться или окуриваться.
Mocking: я просто проверяю, вызывает ли тестируемый мной метод другой метод из mocked-класса.
Заглушка. Поскольку я не хочу полагаться на код, вызываемый вызываемым методом, я заранее определяю, что он должен возвращать при вызове. Поэтому я могу выполнить модульный тест, хотя тестируемый метод вызывает методы, которые еще даже не реализованы.
Я почти уверен, что я не совсем понял насчет насмешек и окурков. Вероятно, поэтому я не могу решить следующую проблему самостоятельно.
Вот метод, для которого я хочу создать UnitTest. getCharge находится в классе под названием Movie:
double getCharge(int daysRented) {
return price.getCharge(daysRented);
}
Вот несколько важных кодов класса Movie:
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-метода ценового класса:
@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);
}
Очевидно, что это не сработает, потому что я не связал свою mockedPrice с объектом цены в моем классе Movie. Проблема в том, что я могу установить объект цены только с помощью setPriceCode (см. Конструктор класса Movie). И вот где я застрял. Есть ли какое-либо решение для установки цены без создания другого метода установки?