0

How to stub a method with a parameter that has specifics properties ?

For example :

doReturn(true).when(object).method( 
    // an object that has a property prop1 equals to "myprop1"
    // and prop2 equals to "myprop2"
)
Yohan D
  • 930
  • 2
  • 7
  • 24

1 Answers1

1

You're going to need either a custom Mockito matcher or a Hamcrest matcher for this problem, or a hybrid of the two. The two work a little differently, but you can use them together with adapters.

With Hamcrest

You'll need to use Matchers.argThat (Mockito 1.x) or MockitoHamcrest.argThat (Mockito 2.x) to adapt the Hamcrest hasProperty matcher and combine it.

doReturn(true).when(object).method(
  argThat(allOf(hasProperty("prop1", eq("myProp1")),
                hasProperty("prop2", eq("myProp2"))))
)

Here, argThat adapts a Hamcrest matcher to work in Mockito, allOf ensures you're only matching objects that satisfy both conditions, hasProperty inspects the object, and eq (notably Hamcrest's eq, not Mockito's eq) compares string equality.

Without Hamcrest

Mockito no longer depends directly on Hamcrest as of Mockito v2.0 (in beta now), so you may want to do the same logic with Mockito's ArgumentMatcher class in a similar style.

doReturn(true).when(object).method(
  argThat(new ArgumentMatcher<YourObject>() {
    @Override public boolean matches(Object argument) {
      if (!(argument instanceof YourObject)) {
        return false;
      }
      YourObject yourObject = (YourObject) argument;
      return "myProp1".equals(yourObject.getProp1())
          && "myProp2".equals(yourObject.getProp2());
    }
  })
)

Naturally, this same custom matcher class technique works with Hamcrest too, but you might prefer the hasProperty technique above if you're sure you're working with Hamcrest.

Refactoring

One word of caution: Though you are welcome to save Matcher objects however you'd like (returned in a static helper method or saved in a field), the call to argThat has side effects, so the call must be made during the call to method. In other words, save and reuse your Matcher or ArgumentMatcher instances if you want, but don't refactor out the call to argThat unless you do so into a static method so argThat still gets called at the right time.

// GOOD with Hamcrest's Matcher:
Matcher<YourObject> hasTwoProperties = (...)
doReturn(true).when(object).method(argThat(hasTwoProperties));

// GOOD with Mockito's ArgumentMatcher:
ArgumentMatcher<YourObject> hasTwoProperties = (...)
doReturn(true).when(object).method(argThat(hasTwoProperties));

// BAD because argThat is called early:
YourObject expectedObject = argThat(...);
doReturn(true).when(object).method(expectedObject);

// GOOD because argThat is called correctly within the method call:
static YourObject expectedObject() { return argThat(...); }
doReturn(true).when(object).method(expectedObject());
Community
  • 1
  • 1
Jeff Bowman
  • 90,959
  • 16
  • 217
  • 251