-1

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?

Jenew
  • 39
  • 8
  • Your code is hard to test because it breaks the open-closed principle (OCP, the O in SOLID) and the dependency inversion principle (DIP, the D). If a new Price type comes along, you have to rewrite Movie too; it's not closed to modification and it relies on the concrete implementations. Also on mocks vs stubs, see e.g. http://engineering.pivotal.io/post/the-test-double-rule-of-thumb/. – jonrsharpe Jun 18 '19 at 07:43

1 Answers1

0

Mockito offers the @InjectMocks annotation, which does some reflection magic and "pushes" any field of your test annotated with @Mock into your class under test. See here for some guidance.

@InjectMocks is a bit tricky, as it doesn't give you any hints when it failed to do its job, then it simply does not inject the mocked object, and you keep wondering why your tests behave in strange ways.

The alternative to using that annotation is "some other way of dependency injection", for example by having a constructor that takes the object(s) you need to mock for tests.

Regarding mocking vs stubbing ... there are actually no exact definitions for these two words. You can get some ideas here for example. You are told there that mocks need a specification what to return for example. Which isn't necessarily true with mockito, as Mockito will return some default values when you call a value-returning method on a mock object (like null, or 0).

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • Just to confirm that "mock" and "stub" have no officially recognized definition, [mypy uses the word stub for the specification](https://github.com/python/mypy/wiki/Creating-Stubs-For-Python-Modules) so the opposite of what is described in the linked answer. I personally say "mock" when I mean to replace an object completely and "stub" when you just replace one method on an instance (which is not possible in Java, but in Python for example yes). – Giacomo Alzetta Jun 18 '19 at 07:32
  • @GiacomoAlzetta As said: different people, different words. In Java (well Mockito), you can do *partial mocking*, where you define for a special mock (called a **spy**) which "real" methods to call, and which ones to mock. So you can get to that behavior with some methods mocked, some not ... for one object in java, too. – GhostCat Jun 18 '19 at 07:35