Reputation: 1914
Question Context
I have a wrapper class with two objects that contain a list. (i.e. Class1 and Class2 both have a Widget List.)
public class WrapperClass {
Class1 class1;
Class2 class2;
}
I have a utils class which processes the Wrapper class
public class WrapperUtils {
public void processClasses() {
WrapperClass wrapperClass = getWrapperClass();
doSomething(class1.getWidgetList());
doSomething(class2.getWidgetList());
}
private WrapperClass getWrapperClass() {
return wrapperClassFromOnlineService;
}
public void doSomething(List<Widget> widgetList) {}
}
Goal
I'd like to use Mockito to verify that the doSomething
method gets called with class1's widget list.
My Attempt
@Test
public void main(String[] args) {
WrapperClass wrapperClass = new WrapperClass();
wrapperClass.class1 = new Class1();
wrapperClass.class2 = new Class2();
WrapperUtils utils = new WrapperUtils();
Mockito.when(utils.getWrapperClass()).thenReturn(wrapperClass);
Mockito.verify(utils, times(1)).doSomething(wrapperClass.class1.getWidgetList());
Mockito.verify(utils, times(1)).doSomething(wrapperClass.class2.getWidgetList());
}
Results of above code: doSomething registers as being called twice for both verify statements. My guess is that the widget lists are treated as the same?
Upvotes: 0
Views: 396
Reputation: 42223
This code has a design issue that makes it difficult to test with mocks.
What that mean is that
Here's an idea of how I'd write the test, this code is mainly focused on interactions, but it is possible to focus the assertions on the state of Class
(don't mock them in this case !!!) :
@RunWith(MockitoJUnitRunner.class)
public class WrapperUtilsTest {
@Mock Class class1;
@Mock Class class2;
@Test public void ensure_that____whatever() {
// given
WrapperUtils tested_utils = new WrapperUtils(new WrapperClass(class1, class2));
// when
tested_utils.processClass();
// then
verify(class1).someInteraction();
verify(class2).someInteraction();
}
}
And the implementation could look like
public class WrapperUtils {
private WrapperClass wrapperClass;
public WrapperUtils(WrapperClass wrapperClass) {
this.wrapperClass = wrapperClass;
}
public void processClasses() {
doSomething(wrapperClass.class1);
doSomething(wrapperClass.class2);
}
public void doSomething(Class clazz) {
clazz.someInteraction();
}
}
Note the wrapperClass
is injected in the WrapperUtils
via the constructor, that works but you can also pass a Supplier
(available in guava or in JDK8), this supplier could get the data from anywhere, a webservice for exemple. Or it could your type. In the test the supplier would be a mock.
@RunWith(MockitoJUnitRunner.class)
public class WrapperUtilsTest {
@Mock Class class1;
@Mock Class class2;
@Mock Supplier<WrapperClass> wrapped_class_supplier;
@Test public void ensure_that____whatever() {
// given
BDDMockito.given(wrapped_class_supplier.get()).willReturn(new WrapperClass(class1, class2));
WrapperUtils tested_utils = new WrapperUtils(wrapped_class_supplier);
// when
tested_utils.processClass();
// then
verify(class1).someInteraction();
verify(class2).someInteraction();
}
}
I strongly advice you to follow Test Driven Development methodology it really helps to write good software. Also there's this book Growing Object Oriented Software Guided by Tests that is a great read, the book may seem old but it is still describes best practices.
Upvotes: 1