How to define a custom argument matcher with mockito in spec2? - scala

I want to verify if the business logic passes the expected user object to dao, but I can't figure how to write an custom argument matcher for it.
"user" should {
"be saved" in {
val dao = new UserDao()
dao.save(any[User]) returns mock[User]
runMyBusinessLogic();
val expectedUser = new User("Freewind", 123.23234)
there was one(dao).save(mymatcher(expectedUser));
}
}
The User class:
case class User(name:String, random: Double)
Which contains a double field, that I need to do some special comparison for it.
The mymatcher is the matcher I want to define:
def mymatcher(expected: User) = ??? {
// compare `name` and `random`
}
But I don't know how to do it in spec2, and can't find any useful documents. Any helps?

I use beLike matcher. Like this:
one(daoMock).insert { beLike[MyEntity] { case t:Entity => {
t.summary mustEqual "Summary"
t.description mustEqual "Description"
}}}
Inside beLike matcher you could use ordinary value matchers.

For mockito matching I used Matchers.argThat
import org.mockito.Matchers
import org.mockito.Mockito.verify
verify(service).methodCall(Matchers.argThat({
case CaseClass("const", arg2) =>
arg2 == expected
case _ => false
}))

Related

Scala tests with Either and Pattern Matching best practice

I want to test my method which returns an Either. This is how i do this:
#Test def `Test empty name is not valid`: Unit = {
val book = createBook()
val result = insertEntryToBook(book, "", "12345")
result match {
case Left(InvalidNameFormat) => true
case _ => fail()
}
}
Should i do some assert() call instead of fail() to make the test's fail message more explicit (e.g. for assertion side-to-side view)?
There is no reason to pattern match here. You can just assert the result equals the expected value wrapped in a Left().
assertEquals(Left(InvalidNameFormat), result)
In case your test fails, you get a precise error message.
ScalaTest can be used with JUnit, so consider mixing in EitherValues which should give more informative messages
import org.junit.Test
import org.scalatest.{EitherValues, Matchers}
class ExampleSuite extends Matchers with EitherValues {
#Test def matchEithers(): Unit = {
val result: Either[String, Int] = Right(42)
result.left.value should be ("Boom")
}
}
which gives
org.scalatest.exceptions.TestFailedException: The Either on which left.value was invoked was not defined as a Left.
at org.scalatest.EitherValues$LeftValuable.value(EitherValues.scala:124)
at example.ExampleSuite.matchEithers(ExampleSuite.scala:9)
...

Scala Bound checking

I am confused about this sentence "If the identifier is bound to a thunk or a text". How can I check that? I have code where identifier is an extension of expression, while thunk and text are of type values. I have this code here but when I run it, I get a stackoverflow error.
package expression
import context._
import value._
case class Identifier(val name: String) extends Expression{
override def toString = name
/*def execute(env: Environment): Value = {
env(this)
}*/
def execute(env:Environment): Value =
{
val envThis = env(this)//wrong here
println(this.getClass)
if(envThis.isInstanceOf[Text])
{
//println(envThis.asInstanceOf[Text].body.getClass) identifier class type
envThis.asInstanceOf[Text].body.execute(env) //wrong here
}
else if(envThis.isInstanceOf[Thunk])
{
envThis.asInstanceOf[Thunk].apply()
}
else
{
env(this)
}
}
}
It is hard to tell without knowing more about the context, but perhaps you should be looking up the name of the identifier in the environment, rather than the Identifier instance?
It would certainly be much clearer to use a match statement, something like this:
def execute(env: Environment): Value =
{
val envThis = env(name)
println(this.getClass)
envThis match {
case text: Text =>
text.body.execute(env)
case thunk: Thunk =>
thunk()
case other =>
other
}
}

scalamock stubbing method with specific parameters fails on null

Hi I want to stub a method with specific parameters and to get the result with a helper method
val myDAOMock = stub[MyDao]
(myDAOMock.getFoos(_:String)).when("a").returns(resHelper("a"))
//btw-is there a way to treat "a" as a parameter to the stubbed method and to the return ?
(myDAOMock.getFoos(_:String)).when("b").returns(resHelper("b"))
def resHelpr(x:String) = x match{
case "a" => Foo("a")
case "b" => Foo("b")
}
but it seems that on my test I can capture only one since the 2nd test fails (regardless to the order that I run the tests )
"A stub test" must{
"return Foo(a)" in{
myDAOMock.getFoos("a")
}
"return Foo(b)" in{
myDAOMock.getFoos("b") //this one will fail on null pointer exception
}
how can I improve my stubbing ?
I refactored your example a bit. I believe your issue is that the stubs for getFoos need to be defined within your tests.
import org.scalamock.scalatest.MockFactory
import org.scalatest._
class TestSpec extends FlatSpec with Matchers with MockFactory {
val myDAOMock = stub[MyDao]
val aFoo = Foo("a")
val bFoo = Foo("b")
def resHelper(x: String): Foo = {
x match {
case "a" => aFoo
case "b" => bFoo
}
}
"A stub test" must "return the correct Foo" in {
(myDAOMock.getFoos(_: String)) when "a" returns resHelper("a")
(myDAOMock.getFoos(_: String)) when "b" returns resHelper("b")
assert(myDAOMock.getFoos("a") === aFoo)
assert(myDAOMock.getFoos("b") === bFoo)
}
}
I think this was an issue in older versions of ScalaMock and should now be fixed in later versions, returning a better message instead of the NPE. The NPE happens as you re-used a mock in two cases.
See http://scalamock.org/user-guide/sharing-scalatest/ how to do that safely.

Eval Tree in Scala 2.11.7

I'm trying to implement JSON-RPC server in Scala and want to mark my remote methods with annotations. Also it will be nice if method itself should not be worried about input parameters validation, so I want to put this validations inside annotation. I ended up with this:
class RPCMethod(validators: (String, PartialFunction[Any, Boolean])*) extends StaticAnnotation
And remote method is annotated like this:
#RPCMethod(
"name" -> {
case x: String => x == "Andrey"
}
)
Now I'm trying to extract the {case ...} part and eval it to a function to check inbound value. But all I could get with reflection is a Tree:
val annotation = method.annotations.find(_.tree.tpe == typeOf[RPCMethod]).get
val validators = annotation.tree.children.tail
if (validators.isEmpty) {
return true
} else {
validators.head match {
case q"scala.this.Predef.ArrowAssoc[$_](${name: String}).->[$_]($func)" => // Don't know how to eval 'func'
case _ => throw some error
}
}
So how can I get a valid function object from this Tree?

Mocking default values for return types with mockito + specs2

Given a mock:
val myMock = mock[SomeClass]
I am trying to set it up so that the mock returns default values for various types. E.g. for things that returns String, it would return "".
I discovered RETURNS_SMART_NULLS which looks like it works for basic return types like String. Here is how I am using it in Scala / Specs2:
val myMock = mock[SomeClass].settings(smart = true)
Now to the problem: since I am using Scala, my code / APIs do not return nulls but return Option values. So what I am trying to do is get the mock to default to returning a non null value for Option return types: either None (preferred), or Some[T] where T is the type in the container (if its String, then Some("")).
So for example if SomeClass has an attribute address of type Option[String], how can I configure mockito to return None when myMock.address invoked instead of null. These nulls are causing downstream errors.
Note, its not a viable solution for me to specifically mock the behavior of each of these individual invocations (e.g: myMock.address returns None)
I was able to test this class:
class Timers(i: Int, s: String) {
def returnOption: Option[Int] = Some(i)
def returnString: String = s
}
with this test:
import org.specs2.mutable.Specification
import org.junit.runner.RunWith
import org.specs2.runner.JUnitRunner
import org.mockito.Mockito._
import org.mockito.stubbing.Answer
import org.mockito.invocation.InvocationOnMock
#RunWith(classOf[JUnitRunner])
class TimersSpec extends Specification {
val m = mock(classOf[Timers], new Answer[Any]() {
def answer(inv: InvocationOnMock) = {
inv.getMethod.getReturnType match {
case c if c == classOf[Option[_]] => None
case c if c == classOf[String] => ""
case _ => null
}
}
})
"A mock timer" should {
"return a None" in {
m.returnOption must beNone
}
"return a empty string" in {
m.returnString mustEqual ""
}
}
}