Reputation: 14728
This is probably a simple question, I haven't been able to shorten it though.
I am testing a class of mine, ClassToTest
. In production, it will perform operations on a third party library object, instance of ThirdPartyClass
.
I want to mimic that class with a stub. (Using the definition of stub as used by Martin Fowler's essay: Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what's programmed in for the test)
The problem is:
ClassToTest
has a method setThirdPartyClass(ThirdPartyClass o)
. So to pass a stub to this, the stub would have to extend ThirdPartyClass
. This means my tests will have to use the third party library, whereas my unit test needs to be self contained.The reason is, my code will be run on an embedded system, and the library in question mostly executes native code. But I want to develop and test my code in isolation on my PC. But I don't want to have to modify ClassUnderTest
argument signatures and so on, for example, changing back and forth between:
classToTest.setThirdPartyClass(ThirdPartyClass o){ /*....*/ }
and
classToTest.setThirdPartyClass(MyThirdPartyClassStub o){ /*....*/ }
AFAIK, normally a stub would simply extend the class it's mimicking, so the signatures would not have to be changed (and overriding constructors etc with minimal code).
What is a good way of doing this?
Upvotes: 2
Views: 2138
Reputation: 2611
Possibly not the best example but essentially, using Mockito to mock the ThirdPartyClass.
YourClass
to test
public class YourClass {
private String aString;
// Method that depends on third party component
public void someMethod(ThirdPartyClass doc) {
aString = doc.someStringValue();
}
public String getValue() {
return aString;
}
}
Test using Mockito to mock the ThirdPartyClass
and control the value returned
public class YourClassTest {
//Class you want to test
private YourClass testee;
@Test
public void testSomeMethod() {
testee = new YourClass();
//
// ThirdPartyClass. When the method someStringValue()
// is called you control the value returned
//
ThirdPartyClass testDoc = mock(ThirdPartyClass.class);
when(testDoc.someStringValue()).thenReturn("aString");
// Call method to test and pass mock as argument
testee.someMethod(testDoc);
// Check state of your object you want to test
assertThat(testee.getValue(), equalTo("aString"));
}
}
Upvotes: 2
Reputation: 48644
The easiest way of mocking (stubbing) ThirdPartyClass
, as has been mentioned, would be if that class implements an interface, and that interface is the complete interface your ClassToTest
uses. Then you could write a MockThirdParty
class that implements ThirdPartyInterface
. But I guess you can not do that.
Another option is to hide the ThirdPartyClass
behind a ThirdPartyFacade
class that you write. As you write it, you can have the it implement a ThirdPartyInterface
that you design. The methods of the ThirdPartyFacade
class simply delegate to the ThirdPartyClass
, so it is safe for you to do relatively little testing of that class; unit tests are not necessary for it. Alter your ClassToTest
so it uses a reference to a ThirdPartyInterface
object, rather than a reference to a ThirdPartyClass
object.
You can now write a MockThirdPartyFacade
class for testing, which implements ThirdPartyInterface
, for testing ClassToTest
. You can make this mock class as simple or as complicated as you tests need it to be. Different test cases could even use different mock classes; you do not need a general purpose mock class.
Upvotes: 2
Reputation: 31648
Does your ThridPartyClass
implement an interface? If so you can change your class under test to use the interface instead of the concrete class. Then your stub just implements the interface.
If not, there are mocking libraries such as EasyMock and Mockito which can mock the class for you.
Using easymock for example:
@Test
public void test(){
ThirdPartyClass mock = createMock(ThirdPartyClass.class);
expect(mock.foo().andReturn("bar");
replay(mock);
classToTest.setThirdPartyClass(mock);
//perform your tests on classToTest
}
Upvotes: 2