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?
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.
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.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With