I had some test code using Mockito (see below), however, I think I need to switch to the more powerful JMockit to achieve my test.
However, if I use the @Tested
annotation on the Session class, the init method called from the constructor throws an Exception.
If I use @Mocked
on the Session class I don't have the real methods available to test.
What is not shown below is that I will also need access to the details
object during the test. However, this is retrieved from the plugin
object during the constructor and the constructor calls the problematic init
method.
How do I test the checkDetails
method with JMockit?
Test Code
import org.mockito.Mockito;
import org.testng.Assert;
import org.testng.annotations.Test;
public class SessionTest {
@Test
public void testSession() {
Session session = Mockito.mock(Session.class);
Mockito.doCallRealMethod().when(session).checkDetails(Mockito.any(String.class));
Assert.assertEquals(session.checkDetails("Foo"), true);
}
}
Class to test
import java.net.Socket;
import java.net.SocketException;
import java.util.List;
public class Session {
private final Socket socket;
private final List<String> details;
private final Plugin plugin;
public Session(Socket socket, Plugin plugin) throws SocketException {
this.socket = socket;
this.plugin = plugin;
this.details = plugin.getDetails();
init();
}
public void init() throws SocketException {
socket.setTcpNoDelay(true);
}
public boolean checkDetails(String item) {
for (String detail : details) {
if (detail.equals(item)) {
return true;
}
}
return false;
}
}
Dependency
import java.util.List;
public class Plugin {
private List<String> details;
public List<String> getDetails() {
return details;
}
}
Note: This is a very much simplified version of the code and changing the production code is not possible at this time.
I would not run this test with partial mocking, personally. This is not a case where you would want to partially mock your code-under-test. (I only mock the CUT in cases where I have a utility method I am independently testing, and I want to assume that utility method works just fine, and test the larger context. You are not doing that here.)
I would take one of two tacks, depending on exactly what my goals were.
Option One
Treat the constructor as part of what you are testing:
Option Two
Assume the object was constructed properly and has its
List<String> details
field initialized properly.Actual Partial Mocking
If this doesn't cut it and you really have your heart set on partial mocking (e.g. you haven't given the full story and you really need to do it), here's how it would work. Let's suppose we have one more method on
Session
:and let's further assume that
checkDetails
consults this helper method rather than a field in your instance.Then a test using partial mocking might look like this:
Faking It
Alternatively, you can use a fake. Again, same assumptions of a
getDetails()
method as in the last section:Final Words
Note that in all cases, when you start to partially mock or fake an object, then the default action is to do the real implementation for that partial mock or fake. Only methods explicitly mocked/faked will be, well, mocked or faked. This is in contrast to the Mockito method you use where there's an explicit
doCallRealMethod()
(and you would be calling a mocked method without it).Also, the
assertThat(...)
stuff is not part of JMockit; it's part of JUnit and is just how I like to do my tests, and I'm too lazy to go back and change it to the assertions you had.