I have an application with 3 layers:
App <--> Graph <--> Couchbase
I'm trying to test the GraphConnector by mocking the couchbase layer and "replacing" it with a very basic in-memory graph implementation, using the same approach demonstrated in the JMockit tutorial.
This is my test class (pardon the poor indentation, didn't get the hang of it yet):
public class GraphConnectorTest {
public static final class MockCouchbase extends MockUp<ICouchConnector> {
private Map<String, CouchEntry> couch;
#Mock
public void $clinit() {
couch = new HashMap<String, CouchEntry>();
}
#Mock
public void put(CouchEntry entry) {
couch.put(entry.getKey(), entry);
}
#Mock
public CouchEntry get(String key) {
return couch.get(key);
}
}
GraphConnectorImpl graph = new GraphConnectorImpl();
#BeforeClass
public static void setUpClass() {
new MockCouchbase();
}
#Test
public void testPost() throws Exception {
GraphNode node = new GraphNode(GraphNodeType.DOMAIN, "alon.com");
graph.post(node);
GraphNode retNode = graph.getSingleNode(node.getValue(), node.getType());
assertEquals(node.getValue(), retNode.getValue());
assertEquals(node.getType(), retNode.getType());
}
}
And here is my class under test:
public class GraphConnectorImpl implements IGraphConnector {
private static ICouchConnector couch = new CouchConnectorImpl(); // <-- Basic implementation which I don't want the test to execute
#Override
public void post(GraphNode node) {
CouchEntry entry = new CouchEntry(node.getValue(), JsonDocument.create(node.getValue()));
couch.put(entry);
}
#Override
public GraphNode getSingleNode(String nodeName, GraphNodeType nodeType) {
return new GraphNode(nodeType, couch.get(nodeName).getKey());
}
}
For some reason, the class MockCouchbase that I created within the test class isn't automatically bound to the private field ICouchConnector couch of the tested class, as shown in the tutorial. Instead, the real implementation is called, which is obviously undesirable.
If I remove the reference to the real implementation, I just get a good ol' NullPointerException.
I tried playing with the #Tested and #Injectable annotations but to no avail.
Solving my own question.
The problem with the way I wrote the class under test was explicitly invoking the constructor of the real implementation. I'll be surprised if any mocking framework can "bypass" that.
Instead, I should've created a constructor that gets ICouchConnector as one of its arguments, e.g. use dependency injection properly.
public class GraphConnectorImpl implements IGraphConnector {
private static ICouchConnector couch;
public GraphConnectorImpl(ICouchConnector connector) {
couch = connector;
}
// Rest of class...
}
JMockit will then attempt to find a constructor that corresponds to the fields annotated #Tested and #Injectable in the test class.
public class GraphConnectorTest {
#Tested
GraphConnectorImpl graph;
#Injectable
ICouchConnector couch;
// Rest of class...
}
Related
Even though I have read the manual and gone through multiple answers for Powermock, could not mock a static method for my use case.
Class:
#Component
public class SCUtil{
public void createSC(){
try {
String host = InetAddress.getLocalHost().getHostAddress();
// ...
// ...
// ...
} catch (UnknownHostException e) {
log.error("Exception in creasting SC");
throw new ServiceException(e);
}
}
}
Test class:
#RunWith(PowerMockRunner.class)
#PrepareForTest( InetAddress.class )
public class SCUtilTest {
#InjectMocks
private SCUtil scUtil;
private Event event;
#Before
public void beforeEveryTest () {
event = new InterventionEvent();
}
#Test(expected = ServiceException.class)
public void testCreateSC_Exception () {
PowerMockito.mockStatic(InetAddress.class);
PowerMockito.when(InetAddress.getLocalHost()).thenThrow(new UnknownHostException("test"));
scUtil.createSC(event);
}
}
Here, the test is failing as no exception is being thrown:
java.lang.AssertionError: Expected exception:
com.example.v1.test.selftest.errorhandling.ServiceException
I have wrecked more than a couple of hours in this and still have not gotten it to work. What am I doing wrong?
Thank you for all the help in advance :)
java.net.InetAddress is a system class. The caller of the system class should be defined in #PrepareForTest({ClassThatCallsTheSystemClass.class}).
See documentation.
The way to go about mocking system classes are a bit different than
usual though. Normally you would prepare the class that contains the
static methods (let's call it X) you like to mock but because it's
impossible for PowerMock to prepare a system class for testing so
another approach has to be taken. So instead of preparing X you
prepare the class that calls the static methods in X!
Please note #InjectMocks annotation does not inject static mocks, it can be removed.
Example of working test:
#RunWith(PowerMockRunner.class)
#PrepareForTest(SCUtil.class)
public class SCUtilTest {
private SCUtil scUtil = new SCUtil();
#Test(expected = ServiceException.class)
public void testCreateSC_Exception () throws UnknownHostException {
PowerMockito.mockStatic(InetAddress.class);
PowerMockito.when(InetAddress.getLocalHost()).thenThrow(new UnknownHostException("test"));
scUtil.createSC();
}
}
I've written a class which reads the entire file and returns the content.
class ClassToTest {
public methodToTest(String input) {
return privateMethod(input);
}
private privateMethod(input) {
ClassPathResource classPathResource = new ClassPathResource(input);
IOUtils.toString(classPathResource.getFile());
}
}
Now, inside my test class, I don't want my test to actually read the file from so I'm trying to mock the method classPathResource.getFile() but somehow I'm not able to do so without writing PrepareForTests() and if I do that those test are not counted in JaCoCo.
I've written test case as
#Test
public void test_methodToTest() {
mockStatic(IOUtils.class);
when(IOUtils.toString(any()).thenReturn("DUMMY_STRING");
methodToTesT("file1.txt");
...
}
The problem is IOUtils.toString gets mocked properly but the call classPathResource.getFile() tries to access the file on the disk. For this, I can do this
PowerMockito.whenNew(ClassPathResource.class)
.withAnyArguments().thenReturn(mockedClassPath);
And add annotation to my test class as
#PrepareForTest(ClassToTest.class)
class MyTestClass {
...
}
But now the problem is this test class is skipped from the JACOCO test coverage . How can I write tests for this class?
You can pass a mocked reference into the constructor doing this:
class ClassToTest {
private ClassPathResource classPathResource;
public ClassToTest(ClassPathResource classPathResource) {
this.classPathResource = classPathResource;
}
public methodToTest(String input) {
IOUtils.toString(classPathResource.getFile(input));
}
}
Or you can pass the mocked reference into the method doing this:
class ClassToTest {
public methodToTest(ClassPathResource classPathResource) {
IOUtils.toString(classPathResource.getFile());
}
}
Having to mock a private member should be seen as a code smell and an indication that something is wrong with the current design. Because ClassPathResource is being initialized internal to the subject class it is now tightly coupled to that class. While not entirely impossible to mock it does make testing the class cleanly more difficult. Consider inverting the creation of the class to a delegate as a dependency.
public interface PathResource {
String getFile(String input);
}
This will allow the injection of the dependency
class ClassToTest {
private classPathResource;
public ClassToTest (PathResource resource) {
this.classPathResource = resource;
}
public String methodToTest(String input) {
return privateMethod(input);
}
private String privateMethod(String input) {
return IOUtils.toString(classPathResource.getFile(input));
}
}
and the dependency can be mocked/faked/stubbed when testing.
public void Test() {
//Arrange
//mock creation
PathResource resource = mock(PathResource.class);
String input = "path";
String expected = "expected_output";
//stubbing
when(resource.getFile(input)).thenReturn(expected);
ClassToTest subject = new ClassToTest(resource);
//Act
String actual = subject.methodToTest(input);
//Assert
verify(resource).getFile(input);
assertEquals(expected, actual);
}
in production code the ClassPathResource would be derived from the abstraction
public class ClassPathResource implements PathResource {
//...code removed for brevity
}
and it would be associated with the abstraction at the composition root.
Following the above suggestions would now allow ClassToTest to be tested in isolation without any knock on effects of implementation concerns.
I am using Junit 4.12 with PowerMock 1.6 with Mockito. I have also used PowerMockRule library as described here. I am trying to execute initialization code for all of my test cases exactly once as described in this SO Thread. Its executing the initialization code exactly one time however, if I do ServiceInitializer.INSTANCE inside test method it returns me new object. I am not able to understand this behavior. Does anyone have any idea why this is happening? If I execute my code without PowerMockRule Library and run my test with PowerMockRunner then it works fine but in that case my ClassRule is not getting executed.
public class ServiceInitializer extends ExternalResource {
public static final TestRule INSTANCE = new ServiceInitializer();
private final AtomicBoolean started = new AtomicBoolean();
#Override protected void before() throws Throwable {
if (!started.compareAndSet(false, true)) {
return;
}
// Initialization code goes here
System.out.println("ServiceInitializationHelper:"+this); //Print Address #3702c2f1
}
#Override protected void after() {
}
}
class BaseTest{
#Rule
public PowerMockRule powerMockRule = new PowerMockRule();
#ClassRule
public static final TestRule serviceInitializer = ServiceInitializer.INSTANCE;
#Before
public final void preTest() {
// some code
}
#After
public final void postTest() {
//some code
}
}
#PrepareForTest({MyClass.class})
public class MyTest extends BaseTest {
#Test
public void testMethodA_1(){
System.out.println(ServiceInitializer.INSTANCE);//Print Address #54d41c2b
}
}
Update
I printed the classloader for the classes and it turns out for first print statement the classloder was sun.misc.Launcher$AppClassLoader and for the second print statement the classloder was org.powermock.core.classloader.MockClassLoader. How can I solve this?
You don't have a singleton. You have a static INSTANCE variable. Keep in mind that one of those can exist for every classloader you have.
Instead make an enum of ServiceInitializer, like so
public enum ServiceInitializer {
INSTANCE;
// rest of class goes here
}
And rely on the JVM's language contracts to ensure the singleton.
Or, better yet, write your code to handle situations where more than one ServiceInitializer can exist, but it just happens that your program only uses one instance. This is the ideal choice, allowing you to alternate between the real ServiceInitializer and a mock if desired.
Edwin is correct; this is an issue with PowerMock creating a new ClassLoader for every test. I strongly recommend refactoring your code so it can be tested without PoeerMock and switch to Mockito.
These books may be helpful
Working Effectively With Legacy Code
Refactoring to Patterns
In the mean time, you can reference ServiceInitializer from your base class:
public class ServiceInitializer extends ExternalResource {
public static final ServiceInitializer INSTANCE = new ServiceInitializer();
private final AtomicBoolean started = new AtomicBoolean();
#Override protected void before() throws Throwable {
if (!started.compareAndSet(false, true)) {
return;
}
// Initialization code goes here
System.out.println("ServiceInitializationHelper:"+this);
}
#Override protected void after() {
}
}
class BaseTest{
#Rule
public PowerMockRule powerMockRule = new PowerMockRule();
#ClassRule
public static final ServiceInitializer serviceInitializer = ServiceInitializer.INSTANCE;
#Before
public final void preTest() {
// some code
}
#After
public final void postTest() {
//some code
}
}
#PrepareForTest({MyClass.class})
public class MyTest extends BaseTest {
#Test
public void testMethodA_1(){
System.out.println(serviceInitializer);
}
}
Well I finally found the work around for this problem. As explained in my question my class was getting loaded by two different class loaders and thus causing problems for me. In order to resolve my issue I used #PowerMockIgnore annotation in order to defer its loading as follows:
#PowerMockIgnore({"com.mypackage.*"})
class BaseTest{
// Stuff goes here
}
This annotation tells PowerMock to defer the loading of classes with the names supplied to value() to the system classloader. You can read about this annotation from here.
I'm trying to unit test an existing ZK controller and I want to find a way to handle a call like the following while unit testing my Controller,
Sessions.getCurrent().setAttribute("from", from.getValue());
I'd be happy to either replacing the offending code, or find a way around it for the unit test. My goal is testability by dealing with the NullPointerException
My test is simple (it's not too bad a place to start...)
#Test
public void zkControllerDoesMockingInitialisedSuccessfully() throws Exception {
T2TripBigDaoInterface tripBigDao = createMock(T2TripBigDao.class);
ZkFieldValidator fieldValidator = createMock(ZkTextFieldValidator.class);
FieldRangeValidator rangeValidator = createMock(DefaultFieldRangeValidator.class);
TripController controller = new TripController(tripBigDao, fieldValidator, rangeValidator);
replay(tripBigDao, fieldValidator, rangeValidator);
controller.onClick$getTrips(new Event("getTrips"));
verify(tripBigDao, fieldValidator, rangeValidator);
// Test purpose: Just get a unit test of the controller running to start with....
}
Extract of the controller:
public class TripController extends GenericForwardComposer {
....
public void onClick$getTrips(Event event) throws Exception {
Sessions.getCurrent().setAttribute("from", from.getValue());
Sessions.getCurrent().setAttribute("to", to.getValue());
....
}
....
Extract of the stack trace:
java.lang.NullPointerException
at com.t2.webservice.controller.alert.TripController.onClick$getTrips(TripController.java:72)
at com.t2.webservice.controller.alert.TripControllerTest.zkControllerDoesMockingInitialisedSuccessfully(TripControllerTest.java:45)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
This is one of the things I dislike most about ZK: their use of singletons and the impact that has on testability.
What I end up doing is removing any references to their singletons (Sessions, Executions, Selectors) from my controllers. In normal operation these singletons get used, but in tests they can be mocked out.
How you go about this is up to you, I still haven't found a pattern I'm in love with.
Here's one idea..
public class TripController extends GenericForwardComposer {
private final TripSessionManager tripSessionManager;
public TripController() {
// ZK calls the default constructor
this(new ZKTripSessionManager());
}
protected TripController(TripSessionManager tripSessionManager) {
this.tripSessionManager = tripSessionManager;
}
public void onClick$getTrips(Event event) throws Exception {
tripSessionManager.setTo(to.getValue());
tripSessionManager.setFrom(from.getValue());
}
}
Your TripSessionManager would then look like this..
public interface TripSessionManager {
void setTo(String to);
void setFrom(String from);
}
With the default ZK implementation relying on the Sessions singleton..
public ZKTripSessionManager implements TripSessionManager {
public void setTo(String to) {
setAttribute("to", to);
}
public void setFrom(String from) {
setAttribute("from", from);
}
private void setAttribute(String name, String value) {
// only valid if called in a ZK managed thread
Sessions.getCurrent().setAttribute(name, value);
}
}
By abstracting out the implementation, you can test your controller with a mock TripSessionManager..
#Test
public void test() {
TripSessionManager mockTripSessionManager = mock(TripSessionManager);
when(mockTripSessionManager.setTo(anyString()).thenAnswer(...);
when(mockTripSessionManager.setFrom(anyString()).thenAnswer(...);
TripController controller = new TripController(mockTripSessionManager);
}
You could also imagine different ways of managing these new dependencies (eg: avoid new ZKTripSessionManager()) using dependency injection frameworks like Spring or Guice.
I have a Java class that simply extends a library class and calls a method of its parent with a default parameter. How do I write a Junit test for that? A MockObjectTestCase is good too. Here is an example of what I'm talking about:
public class ResourceBundleMessageSource {
public String getMessage(String key, Object[] objects, Locale locale) {
//Spring library method
}
}
public class MessageResource extends ResourceBundleMessageSource {
public String getMessage(String key) {
return (getMessage(key, null, Locale.getDefault());
}
}
I know the wrapper method isn't even necessary, but makes frequent calls to it easier. Note the class works fine, I'm only interested in how the unit test is written.
If you would be willing to refactor your class slightly, I would recommend MessageResource delegate to a MessageSource instance, rather than extend ResourceBundleMessageSource. Then I'd use mocks in my unit test. Something like this:
public class MessageResource implements MessageSource {
private final MessageSource delegate;
public MessageResource(MessageSource delegate) {
this.delegate = delegate;
}
public String getMessage(String key) {
return delegate.getMessage(key, null, Locale.getDefault());
}
// need to implement three other MessageSource methods,
// simple pass-throughs to delegate
}
and unit test
public class MessageResourceTest {
private MessageSource mockDelegate;
private MessageResource messageResource;
#Before
public void setUp() throws Exception {
mockDelegate = //mock with your favorite framework, or by hand
messageResource = new MessageResource(mockDelegate);
}
#Test
public void testGetMessage() {
String key = "foo";
String actualMessage = messageResource.getMessage(key);
assertEquals(key, /* get key passed to mock delegate */ );
assertSame(Locale.getDefault(), /* get Locale passed to mock delegate */);
assertEquals(/*expected message from mock*/, actualMessage);
}
}
For this particular example I probalby would not bother to test it.
If you do need to test it, try something like:
#Test
public void getDefaultMessage() {
ResourceBundleMessageSource origSource = <create source>
MessageResource subSource = <create with same criteria as origSource>
String key = <some key that is locale-specific>
assertEquals(origSource.getMessage(key, null, Locale.getDefault()),
subSource.getMessage(key));
}
If the first two lines are hard to write, then it makes even more sense not to test it.
If you have several tests like this, move the first two lines into a setup fixture.
I don't think it's even worth writing a unit test for that. If there's already a test for ResourceBundleMessageSource.getMessage(), then that should be good enough.