question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Allow partial mixing of concrete values with matchers

See original GitHub issue

I’m pretty sure we’re all familiar with the dreadful message “Invalid use of argument matchers” which is caused (most of the time) due to mixing of concrete values and matchers. After using Mockito for several years, I gotta say that this is one of the most annoying drawbacks of the framework.

Recently I’ve been getting more and more into the code of the framework, and started wondering why this restriction is there in the first place. I looked it up, and found this thread on the Google mailing list, in which a guy named Brice (@bric3 ?) explains the reasoning behind this in a fairly simple manner.

In short, the matchers cannot be passed to the mock invocation, since they have a different type than that of the arguments. The way Mockito is handling this is by “registering” the matchers prior to the invocation on a local-thread stack, which the mock-handler later inspects upon the method invocation. When only matchers are used, it is easy to match each matcher to a parameter of the method–by simply matching the stack to the parameter list–but when concrete values are mixed in, this becomes ambiguous.

I would like to suggest a middle-ground solution that will probably cover (at least) 80% of the cases - How about assuming that each null argument a method is invoked with is supposed to correspond to a matcher, while the rest will be treated as concrete values? This way, only cases where null is passed “concretely” alongside matchers will be invalid. For example:

when(myMock.foo(any(), null)) // invalid
when(myMock.foo(any(), "1")) // valid

There would also be a problem with primitive types, as matchers cannot be passed to the method as nulls, but in this case they could be passed as default values and then an invocation will be considered invalid if the number of default primitive values passed to the method exceeds the number of matchers of said primitive type on the stack.

Thoughts?

Issue Analytics

  • State:open
  • Created 5 years ago
  • Reactions:11
  • Comments:15 (11 by maintainers)

github_iconTop GitHub Comments

2reactions
ChristianSchwarzcommented, Jun 14, 2018

@TimvdLippe @bric3 @szpak @mockitoguy @mockitocore

What do you guys think of a limited support for mixed values/matchers? There is a good chance that Mockito can support mixing for more than 90% of all method calls (just a pessimistic guess). The famous “Invalid use of argument matchers” can become a corner case, were users are still forced to apply matchers everywhere. This would make test code even better / more readable.

I see currently following expansion stages:

  • support for mixing primitive values and build in mockito primitve matchers ( eq(..), any###() ) using default matcher return values
  • support for mixing primitive/ object values and build in mockito matchers, default matcher return values / mocks
  • improved matcher resolution using additional method signature analysis
0reactions
ChristianSchwarzcommented, Aug 13, 2018

@oleksiyp I came to a similar solution in #828 “Prototype implementation of when syntax for void methods”. Since when needs to accept a lambda the Mockito API needs an update, i guess this wont happen in Mockito 2. Introducing when with lambda would be useful to unify the whole stubbing API too.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Mockito Matchers.any(...) on one argument only - Stack Overflow
This exception may occur if matchers are combined with raw values: //incorrect: someMethod(anyObject(), "raw String"); When using matchers, all ...
Read more >
Mockito Argument Matchers - any(), eq() - DigitalOcean
If we want to use a specific value for an argument, then we can use eq() method. when(mockFoo. bool(eq("false"), anyInt(), any(Object.
Read more >
Matchers - GitHub Pages
You can define expectations with anything that returns a Result : Boolean; Standard result; Matcher result; Scalacheck property; Mock expectation; DataTable ...
Read more >
ArgumentMatchers (Mockito 3.3.3 API) - javadoc.io
Object argument that is equal to the given value. static float, floatThat(ArgumentMatcher<Float> matcher). Allows creating custom float argument matchers.
Read more >
Mockito ArgumentMatchers - Baeldung
Mockito requires that we provide all arguments either by matchers or exact values. There are two more points to note when we use...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found