Reputation: 19110
I’m using JUnit 4.11 and Mockito 1.9.5. How can I match all of the arguments in a method call except one, in which I don’t care if it’s generically matched? Here is what I have
Mockito.verify(m_emailSvc).sendEmail(user.getAddress().getEmail(), fromEmail, subject, “template.vm", paramMap, (File) Matchers.any(File.class));
Notice that the last argument (of type java.io.File) is the one I’m trying to match generically. Unfortunately, when this call is made, I get the run time exception
java.lang.ClassCastException: org.hamcrest.core.IsInstanceOf cannot be cast to java.io.File
at org.mainco.subco.myproject.service.TrainingSessionServiceDWRIT.testAddCEUCreditsCompleteTraining(TrainingSessionServiceDWRIT.java:394)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
What is the proper way to generically match only one argument? If this requires an upgrade, that’s fine with me.
Edit:
In response to the answer given, here is the new exception that occurs upon running the JUnit test. This may strike at the heart of my question — how do I combine a generic matcher with specific matchers.
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
6 matchers expected, 2 recorded:
-> at org.mainco.subco.myproject.service.TrainingSessionServiceDWRIT.testAddCEUCreditsCompleteTraining(TrainingSessionServiceDWRIT.java:394)
-> at org.mainco.subco.myproject.service.TrainingSessionServiceDWRIT.testAddCEUCreditsCompleteTraining(TrainingSessionServiceDWRIT.java:394)
This exception may occur if matchers are combined with raw values:
//incorrect:
someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
//correct:
someMethod(anyObject(), eq("String by matcher"));
For more info see javadoc for Matchers class.
at org.mainco.subco.myproject.service.TrainingSessionServiceDWRIT.testAddCEUCreditsCompleteTraining(TrainingSessionServiceDWRIT.java:394)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Edit 2: Ok, I wrapped everything in Matchers.eq calls …
Mockito.verify(m_emailSvc).sendEmail(Matchers.eq(user.getAddress().getEmail()),
Matchers.eq(fromEmail),
Matchers.eq(pdCompletionSubject),
Matchers.eq("send_pd_registration_completion.vm"),
Matchers.eq(paramMap),
Matchers.eq(Matchers.any(File.class)));
but still get the exception below
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
6 matchers expected, 7 recorded:
-> at org.mainco.springboard.myproject.service.TrainingSessionServiceDWRIT.testAddCEUCreditsCompleteTraining(TrainingSessionServiceDWRIT.java:394)
-> at org.mainco.springboard.myproject.service.TrainingSessionServiceDWRIT.testAddCEUCreditsCompleteTraining(TrainingSessionServiceDWRIT.java:394)
-> at org.mainco.springboard.myproject.service.TrainingSessionServiceDWRIT.testAddCEUCreditsCompleteTraining(TrainingSessionServiceDWRIT.java:394)
-> at org.mainco.springboard.myproject.service.TrainingSessionServiceDWRIT.testAddCEUCreditsCompleteTraining(TrainingSessionServiceDWRIT.java:394)
-> at org.mainco.springboard.myproject.service.TrainingSessionServiceDWRIT.testAddCEUCreditsCompleteTraining(TrainingSessionServiceDWRIT.java:394)
-> at org.mainco.springboard.myproject.service.TrainingSessionServiceDWRIT.testAddCEUCreditsCompleteTraining(TrainingSessionServiceDWRIT.java:394)
-> at org.mainco.springboard.myproject.service.TrainingSessionServiceDWRIT.testAddCEUCreditsCompleteTraining(TrainingSessionServiceDWRIT.java:394)
This exception may occur if matchers are combined with raw values:
//incorrect:
someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
//correct:
someMethod(anyObject(), eq("String by matcher"));
For more info see javadoc for Matchers class.
at org.mainco.springboard.myproject.service.TrainingSessionServiceDWRIT.testAddCEUCreditsCompleteTraining(TrainingSessionServiceDWRIT.java:394)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Upvotes: 0
Views: 1442
Reputation: 95614
To answer the question directly: The default action, without using Matchers, is equivalent to Matchers.eq. To preserve that action while using other Matchers, including any
, you can call Matchers.eq
explicitly.
At this point, your call would look like this:
// N.B. Matchers is actually org.mockito.Matchers!
Mockito.verify(m_emailSvc).sendEmail(
Matchers.eq(user.getAddress().getEmail()),
Matchers.eq(fromEmail),
Matchers.eq(subject),
Matchers.eq("template.vm"),
Matchers.eq(paramMap),
Matchers.any(File.class));
However, the above is very unlikely to be responsible for the error message:
java.lang.ClassCastException: org.hamcrest.core.IsInstanceOf cannot be cast to java.io.File
Instead, this indicates that you're using the wrong Matchers class. You've imported org.hamcrest.Matchers
, where calls to Matchers.any(Class<T> clazz)
returns an instance of org.hamcrest.core.IsInstanceOf
. Instead, you want to call org.mockito.Matchers.any(Class<T> clazz)
, which appears to return a T
(to avoid your cast) but actually works via side effects.
You'll need to fix both problems (importing the correct Matchers class and also using one matcher per argument) to solve your problem. For more context on the difference between Hamcrest and Mockito matchers, and the need for one matcher per argument, see my other SO answer.
Upvotes: 3