Reputation: 5736
I am new to mocking and so I'm playing around with this scenario. I have a method MyClass.process()
which calls MyClass.getFactory()
. I want to mock getFactory()
to fail so that I can assure process()
recovers correctly.
It seems that if I call getFactory()
after the mock it throws the exception correctly, but if it is called through the original process()
method the exception is not thrown.
public class MyClass {
public MyFactory getFactory() throws FactoryException {
return ...
}
public String process() {
try {
MyFactory factory = getFactory();
...
}
catch(FactoryException ex) {
...
}
}
}
Test class:
public class MyClassTest {
@Test
public void testGetFactoryFails() {
try {
MyClass mockMyClass = mock(MyClass.class);
when(mockMyClass.getFactory()).thenThrow(new FactoryException());
mockMyClass.process();
fail("FactoryException should have been thrown.");
}
catch(FactoryException ex) {
// all good
}
}
}
Thanks for all the feedback. I can see how mocking single methods under more complex environments would quickly become unmanageable. The contents of getFactory() is not important as this is concept code, not production code.
One way I tried that works well:
public class MyClassTest {
class MyClassMock1 extends MyClass {
@Override
public MyFactory getFactory() throws FactoryException {
throw new FactoryException("Bad factory instance.");
}
}
@Test
public void testGetFactoryFails() {
try {
MyClassMock1 mockMyClass = new MyClassMock1();
mockMyClass.process();
fail("FactoryException should have been thrown.");
}
catch(FactoryException ex) {
assertEquals("Bad factory instance.", ex.getMessage());
}
}
}
Upvotes: 0
Views: 1043
Reputation: 14520
it's because partial mocking is BAD (and that's what you are trying to do). it leads exactly to those kind of problems. it's introduced mainly for legacy systems testing. if you write new code and you have to use partial mocking this mean you most probably have bad system design.
you should make getFactory
delegate the invocation to some other service (injected into MyClass
) and then you should mock the whole service
Upvotes: 0
Reputation: 340713
I'll expand what @Can't Tell already said. You use mocking library to mock dependencies of a class under test. In your case you test MyClass
and during tests you should mock all the dependencies (classes that MyClass
uses).
You want to mock a single method in one class and test another method. While this might be technically possible (but due to various proxying/wrapping mechanics it doesn't work for you), it's certainly a bad design.
Show us your getFactory()
method. If it handles the whole work alone, extract it to a separate class and mock it. If it only delegates to another class, mock that one. Sadly, this extracted class will be named... MyFactoryFactory
...
Once you get your dependency extracted, mock it and pass to MyClass
before testing (via contstructor, setter...)
Upvotes: 1