At first I have a general question about mocking and stubbing. I can't really see the difference between these two words. Here is what I know so far: When creating a Unit test and the method being tested calls a method from another class, a mock object should be used. The class that contains the called method has to be mocked. Now I have to decide If I do mocking or stubbing.
Mocking: I just check if the method I am testing calls the other method from the mocked class.
Stubbing: As I don't want to rely on the code behind the called method, I predefine what it should return when it is called. Therefore I am able to do a Unit Test, even though the method under test calls methods that aren't even implemented yet.
I am pretty sure, that I haven't quite understood everything about mocking and stubbing. That's probably the reason why I can't solve the following problem myself.
Here is the method, I want to create a UnitTest for. getCharge is in a Class called Movie:
double getCharge(int daysRented) {
return price.getCharge(daysRented);
}
Here some important Code of the Movie class:
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);
}
}
As I am doing a Unit Test, I don't want to use the logic of the price class. Therefore I mock the price class and predefine what the getCharge-Method of the price class should return:
@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);
}
Obviously this won't work because I haven't linked my mockedPrice with the price object in my Movie class. The problem is that I can only set the price object by using setPriceCode (see Constructor of Movie class). And this is where I am stuck. Is there any solution to set the Price without creating another setter Method?