问题
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.
回答1:
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.
回答2:
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"
回答3:
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");
}
}
来源:https://stackoverflow.com/questions/35133263/mockito-and-interface-event