1

I am writing an integration test using mockito. The unit under test is connected to a mocked object (objA) through an interface. The functionality that I am trying to mimic happens when the mocked objected fires an event and the unit under test is listening to it.

The interface:

public interface MyInterfaceAPI{
   void fireyMyEvent(String msg);
}

The unit under test:

public class UnitUnderTest{

    ObjA objA;

    public UnitUnderTest(ObjA objA_t) {
         objA = objA_t;
         objA.addMyListener(new addMyHandler()); 
    }

    class addMyHandler implements MyInterfaceAPI{
       @Override
       public void fireyMyEvent(String msg) {
             System.out.println(msg);
       };
    };
};

The test:

 public class MyTest {

     @org.junit.Test
     public void run() {

         ObjA  mockObjA = mock(ObjA .class);    
         UnitUnderTest spyController = Mockito.spy(new UnitUnderTest());

         MyInterfaceAPI mo2uut= mock(MyInterfaceAPI.class);
         mo2uut.fireyMyEvent("hello from test"); 
     }
 }

My question is in the test, how do I connect the mo2uut ('mocked object' to 'unit under test') to the addMyHandler class implementation of MyInterfaceAPI inside the UnitUnderTest?

I am clearly missing something, but I am not sure what.

justadev
  • 1,168
  • 1
  • 17
  • 32

3 Answers3

2

You have 2 schools on unit testing: The London / Mockist school, and the Detroit school.

If you want to use mocks, you must use dependency injection, so you can replace the dependencies with mocks. I think most people following the Detroit school would agree on this too, just because using dependency injection "is a good thing" (tm).

What you can do is to pass an instance of ObjA to UnitUnderTest in the constructor; Or alternatively (if ObjA is a collection) add the method UnitUnderTest.addListener(), where you pass an instance of a handler. With these 2 approaches, you'll be injecting a handler.

About using powermock: Powermock is a beast better used on old projects that have very little unit testing and their dependencies are a mess. If you are coding this now, using power mock is wrong (in the spirit of fairness, this is a biased idea, but it's shared with many other people).

Edit

Now I get your question! And I think that you're trying to test too much in one unit test and that causes the problem. Again, the mockist school talks about testing interactions... that's the key point. So in the test for UnitUnderTest the only interaction is with ObjA to set the handler, and that's the end of the story.

You'll probably have another test for ObjA to ensure that all handlers are invoked.

Now the last bit is how to test the code of the handler. But before that, please appreciate how independent each test is, as you're testing the interactions (and any logic in the code), but not more than 1 thing. About the handler... you might not like this, but you have to make that class accessible, either make it public or extract it to another public class. If you extract it, you can put in an internal package so it's clear that the class shouldn't be used by anyone else.

If you have an hour to spare, I would suggest you to watch this great presentation: The Deep Synergy Between Testability and Good Design by Michael Feathers where he goes into a similar example of what you have in your code and why it makes sense to separate it.

Community
  • 1
  • 1
Augusto
  • 28,839
  • 5
  • 58
  • 88
  • Thanks for your response. I edited the code to correct it, objA is actually already passed to UnitUnderTest as an instance. However, I am still not sure how to inject the handler. Any chance to request a code example here? – justadev Feb 01 '16 at 16:39
  • Sure... give me 10 minutes :) – Augusto Feb 01 '16 at 17:04
1

Use PowerMock's PowerMockito to intercept the call to the addMyHandler class injecting a mock of MyInterfaceAPI as explained in Ben Kiefer's tutorial on "PowerMockito: Constructor Mocking"

Boris Pavlović
  • 63,078
  • 28
  • 122
  • 148
0

I have managed to make it working. Posting here the fixed code for people who see this in the future.

public interface MyInterfaceAPI{
   void fireyMyEvent(String msg);
}

The unit under test:

public class UnitUnderTest{

  private ObjA objA;
  public MyInterfaceAPI interfaceHandler;

  public UnitUnderTest(ObjA objA_t) {
     objA = objA_t;
     interfaceHandler = new addMyHandler();
     objA.addMyListener(interfaceHandler); 
  }

  class addMyHandler implements MyInterfaceAPI{
    @Override
    public void fireyMyEvent(String msg) {
         System.out.println(msg);
    };
  };
};

The test:

public class MyTest {

 @org.junit.Test
 public void run() {

     ObjA  mockObjA = mock(ObjA .class);    
     UnitUnderTest spyController = Mockito.spy(new UnitUnderTest());
     spyController.hnd.fireyMyEvent("hello from test"); 
 }
}
justadev
  • 1,168
  • 1
  • 17
  • 32