4

Here is the code I am trying to run:

import org.specs2.mock.Mockito
import org.specs2.mutable.Specification
import org.specs2.specification.Scope
import akka.event.LoggingAdapter

class MySpec extends Specification with Mockito {


  "Something" should {
      "do something" in new Scope {

      val logger = mock[LoggingAdapter]

      val myVar = new MyClassTakingLogger(logger)

      myVar.doSth()

      there was no(logger).error(any[Exception], "my err msg")
      }
  }

}

When running this, I get the following error:

[error]    org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
[error]    Invalid use of argument matchers!
[error]    2 matchers expected, 1 recorded:
[error]    -> at         org.specs2.mock.mockito.MockitoMatchers$class.any(MockitoMatchers.scala:47)
[error]
[error]    This exception may occur if matchers are combined with raw values:
[error]        //incorrect:
[error]        someMethod(anyObject(), "raw String");
[error]    When using matchers, all arguments have to be provided by matchers.
[error]    For example:
[error]        //correct:
[error]        someMethod(anyObject(), eq("String by matcher"));

Which would make a lot of sense, but neither eq("my err msg") nor equals("my err msg") does the job as I get an error. What am I missing?

eddyP23
  • 6,420
  • 7
  • 49
  • 87
  • `eq("my err msg")` is required for this case, and I suspect the error you're getting when using it is a different error—possibly related to your actual test. Can you please paste in the error you get when using `eq`? – Jeff Bowman Sep 07 '15 at 19:17
  • It is a very vague compilation error: `[error] (template: String,arg1: Any)Unit [error] (cause: Throwable,message: String)Unit [error] cannot be applied to (Exception, Boolean) [error] there was no(logger).error(any[Exception], eq("my err msg"))` – eddyP23 Sep 08 '15 at 18:18

2 Answers2

7

I would like to add that you should be wary of default arguments, i.e. if using matchers when stubbing methods, make sure to pass argument matchers for all arguments, because default arguments will almost certainly have constant values - causing this same error to appear.

E.g. to stub the method

def myMethod(arg1: String, arg2: String arg3: String = "default"): String

you cannot simply do

def myMethod(anyString, anyString) returns "some value"

but you also need to pass an argument matcher for the default value, like so:

def myMethod(anyString, anyString, anyString) returns "some value"

Just lost half an hour figuring this out :)

Zoltán
  • 21,321
  • 14
  • 93
  • 134
  • This should be mentioned in the chosen answer, it just saved me a lot of time and frustration. – K. C. Oct 29 '16 at 16:16
6

When you are using matchers to match parameters you have to use them for all parameters. as the all arguments have to be provided by matchers indicates.

Moreover if you use a specs2 matcher it needs to be strongly-typed. equals is a Matcher[Any] but there is no conversion from Matcher[Any] to a String which is what method accepts.

So you need a Matcher[T] or a Matcher[String] in your case. If you just want to test for equality, the strongly-typed matcher is ===

there was no(logger).error(any[Exception], ===("hey"))
Eric
  • 15,494
  • 38
  • 61
  • How would you create an arbitrary `Matcher[String]`? – eddyP23 Sep 08 '15 at 18:14
  • Like you could easily want matchers like "contains" or "is contained in" or sth similar – eddyP23 Sep 08 '15 at 18:22
  • `def m: Matcher[String] = (s: String) => (isOk(s), s+ " is not ok")` – Eric Sep 08 '15 at 22:14
  • do you know how I could write a matcher that also takes right hand side parameter? In particular I am interested to write a matcher that checks whether left hand side string contains right hand side string: `"some string" should containString "me st"` @Eric – eddyP23 Jun 02 '16 at 12:54
  • 1
    Yes, use a parameter: `def containString(expected: String): Matcher[String] = { actual: String => (actual.contains(expected), "wrong") }`. – Eric Jun 02 '16 at 12:58
  • The above did not work, but with slight modification, the following worked: `def containString(right: String): Matcher[String] = new Matcher[String] { def apply(left: String) = MatchResult(left.contains(right), s"'$left' does not contain '$right'", s"'$left' contains '$right'") }` – eddyP23 Jun 02 '16 at 13:14
  • 1
    The version I gave you should work if you import `org.specs2.matcher.MatcherImplicits._` when you are outside a specification. – Eric Jun 02 '16 at 13:55