Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

For what reason should I mock?

I am new to Mockito and PowerMockito as well. I found out that I can not test static methods with pure Mockito so I need to user PowerMockito (right?).

I have very simple class called Validate with this very easy method

public class Validate {
        public final static void stateNotNull(
            final Object object,
            final String message) {
    if (message == null) {
        throw new IllegalArgumentException("Exception message is a null object!");
    }
    if (object == null) {
        throw new IllegalStateException(message);
    }
}

So I need to verify that:

1) When I call that static method on null message argument, IllegalArgumentException is called
2) When I call that static method on null object argument, IllegalStateException is called

From what I got so far, I wrote this test:

import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.isNull;

import org.junit.Before;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.testng.annotations.Test;

@RunWith(PowerMockRunner.class)
@PrepareForTest(Validate.class)
public class ValidateTestCase {

    @Test(expectedExceptions = { IllegalStateException.class })
    public void stateNotNullTest() throws Exception {
        PowerMockito.mockStatic(Validate.class);
        Validate mock = PowerMockito.mock(Validate.class);
        PowerMockito.doThrow(new IllegalStateException())
            .when(mock)
            .stateNotNull(isNull(), anyString());
        Validate.stateNotNull(null, null);
    }
}

So this says that I mock Validate class and I am checking that when mock is called on that method with null argument as an object and any string as a message, an IllegalStateException is thrown.

Now, I really don't get it. Why I just can't call that method directly, dropping the whole voodoo magic around mocking that static class? It seems to me that unless I call Validate.stateNotNull that test passes anyway ... For what reason should I mock it?

like image 458
stewenson Avatar asked Mar 01 '13 14:03

stewenson


People also ask

Why do we need to mock?

The purpose of mocking is to isolate and focus on the code being tested and not on the behavior or state of external dependencies. In mocking, the dependencies are replaced by closely controlled replacements objects that simulate the behavior of the real ones.

Should you mock in unit tests?

In a unit test, mock objects can simulate the behavior of complex, real objects and are therefore useful when it is impractical or impossible to incorporate a real object into a unit test. Mocking makes sense in a unit testing context.

Should you mock all dependencies?

Correct. You should mock things that depend on anything persistent or external in order to prevent the test from depending on anything persistent or external.

What does mocking a class do?

Mocking is done when you invoke methods of a class that has external communication like database calls or rest calls. Through mocking you can explicitly define the return value of methods without actually executing the steps of the method.


2 Answers

You should not mock the classes and methods you are testing. You should only mock methods that are needed to perform the test itself.

For example, if you need some objects from a web service to perform a test, you could mock the web service calls, so you don't need to actually call the web service.

like image 121
Fortega Avatar answered Oct 03 '22 09:10

Fortega


First, decide what your objective is and what you want to test. Your test isn't testing your Validate class method, it's creating a mock that behaves like that method, as Fortega points out. Identify what it is you are testing (the object under test) and what it is you need in order to perform the test (the collaborators), then look at the collaborators and decide whether they are things that are easy to create or if you need to mock them.

For something like this class which has no dependencies on anything, I would recommend doing without mocks entirely. There is nothing here that needs mocking, the test can be written like this:

import static org.junit.Assert.*;

public class ValidateTestCase {

    @Test
    public void testHappyPath() throws Exception {
        Validate.stateNotNull("", "");
    }

    @Test
    public void testNullMessage() throws Exception {
        try {
            Validate.stateNotNull(null, null);
            fail();
        }
        catch (IllegalStateException e) {
            String expected = "Exception message is a null object!"
            assertEquals(expected, e.getMessage());
        }
    }

    @Test(expected=IllegalStateException.class)
    public void testNullObject() throws Exception {
        Validate.stateNotNull(null, "test");
    }
}

and that tells you whether the code does what you want it to.

Don't mock unless there is some dependency that you want to avoid introducing to the test due to it being either an external resource (like a filesystem or database) or some complex subsystem. The mock frameworks can be very useful but they add complexity, they can over-specify the behavior of the things they are testing, making the tests brittle, and they can make tests hard to read. Do without them if you can.

like image 38
Nathan Hughes Avatar answered Oct 03 '22 09:10

Nathan Hughes