How to mock case class? - scala

I have following case class:
case class User(username:String, createdDate:DateTime)
and a class to test:
class UserDAO{
def registerUser(user:User)
}
I want to verify that registerUser called with an input user that has username="myusername". Based on this docs https://mockito.googlecode.com/hg-history/1.7/javadoc/org/mockito/Matchers.html I came up with a code like this:
verify(userDAO).registerUser(User(eq("myusername"),any[DateTime]))
however it is not right and I had error while compiling.
Error is Type mismatch, expected UUID actual Boolean

I solved my problem by using a different approach. I used capture the input argument of a mocked object and then validate the captured value.
http://docs.mockito.googlecode.com/hg/org/mockito/ArgumentCaptor.html

Related

Scala Assertion unknown parameter on case class

Let's say I have the below case class that translates directly a db table and where the id will be generated randomly on the creation of a new row.
case class Test(id: UUID, name: String)
Looking at the tests right now, I need to retrieve a row from Test and compare it with
val test1 = (...., "testName")
however I don't have the first parameter since it's created randomly and I would like to ignore it somehow...
I tried doing
test1 = (_, "testName")
but it's not valid.
Is there any way where I can ignore in Scala a case class parameter ?
Thanks!
Assuming we have
case class Test(id: UUID, name: String)
Here's a function that tests two instances of Test for equality, ignoring the id field.
def myEquality(a: Test, b: Test): Boolean =
a == b.copy(id=a.id)
We can't explicitly tell Scala to ignore a field, but we can most certainly mock that field to be the correct value. And since these are case classes (i.e. immutable), we can't mess up any other unrelated data structures by doing this simple trick.
To answer the question posed, the answer is no. Case class instances are defined by the values of their fields. They do not have the property of identity like normal classes. So instantiating a case class with a missing parameter is not possible.

Case object extending class with constructor in Scala

I am a beginner in Scala and was playing around to learn more about Abstract data types. I defined the following definition to replicate Option type:
sealed abstract class Maybe[+A](x:A)
case object Nothing extends Maybe[Nothing](Nothing)
case class Just[A](x:A) extends Maybe[A](x)
But I encountered the following error.
found : Nothing.type
required: Nothing
case object Nothing extends Maybe[Nothing](Nothing)
How do I pass Nothing instead of Nothing.type?
I referred to the following question for hints:
How to extend an object in Scala with an abstract class with constructor?, but it was not helpful.
Maybe more like this. Your Nothing shouldnt have a value, just the type. Also people usually use traits instead of abstract classes.
sealed trait Maybe[+A]
case object None extends Maybe[Nothing]
case class Just[A](x:A) extends Maybe[A]
You probably shouldnt create your own Nothing, thats going to be confusing, you will confuse yourself and the compiler about if you are referring to your one, or the one at the bottom of the type hierarchy.
As mentioned by Stephen, the correct way to do this would be not to have trait and not an abstract class, however, I thought it might be informative to explain why the current methodology fails and how to fix it.
The main issue is with this line:
case object Nothing extends Maybe[Nothing](Nothing)
First thing (as mentioned) you shouldn't call your object Nothing. Secondly, you set the object to extend Maybe[Nothing]. Nothing can't have any actual values so you can't use it as an object. Also, you can't use the object itself as the constructor parameter because that would cause a cyclic behavior.
What you need is to have a bottom type (i.e. a type which all A have in common) and an object of that type. Nothing is a bottom type but has no objects.
A possible solution is to limit yourself to AnyRef (i.e. nullable objects) and use the Null bottom type which has a valid object (null):
sealed abstract class Maybe[+A <: AnyRef](x:A)
case object None extends Maybe[Null](null)
This is a bit of clarification for Assaf Mendelson's answer, but it's too big for a comment.
case object Nothing extends Maybe[Nothing](Nothing)
Scala has separate namespaces for types and values. Nothing in case object Nothing is a value. Nothing in Maybe[Nothing] is a type. Since you didn't define a type called Nothing, it refers to the automatically imported scala.Nothing and you must pass a value of this type as an argument. By definition it has no values but e.g. case object Nothing extends Maybe[Nothing](throw new Exception) would compile, as the type of throw expressions is Nothing. Instead you pass the value Nothing, i.e. the same case object you are defining; its type is written as Nothing.type.
How do I pass Nothing instead of Nothing.type?
It seems like there is no way to do so.
As it says at http://www.scala-lang.org/api/2.9.1/scala/Nothing.html:
there exist no instances of this type.

µPickle Couldn't derive type error on write

I'm trying to use µPickle in Scala.js to produce Json for Ajax request.
Here is my code:
import upickle._
import upickle.default._
case class FmData(name: String, comment: String)
val data = write(FmData("name", "comment"))
And I get error:
Couldn't derive type FmData
How come?
The same issue happened to me before. It was happening when I was defining this case class in package object, other object or inside of method. However when I extracted it to a separate file, it was all fine and working.
Hope it helps.

How to compare result type to be subclass of abstract class to match to?

I have a method with signature
def save(u: User): Future[Option[UserServiceError]]
that I want to test with Specs2.
I've got the following type hierarchy:
abstract class UserServiceError(message: String)
object UserAlreadyExist extends UserServiceError("User already exists")
then, test code looks like this:
users.save(...) must beSome(users.UserAlreadyExist).await
so I expect matcher beSome to understand that UserAlreadyExist is a subtype of UserServiceError from method signature.
However, it gives me an compile time type check error
type mismatch;
[error] found : org.specs2.matcher.Matcher[scala.concurrent.Future[Option[core.model.services.UserService#UserAlreadyExist.type]]]
[error] required: org.specs2.matcher.Matcher[scala.concurrent.Future[Option[core.model.services.UserService#UserServiceError]]]
I have an inkling that I miss something very basic here, like UserAlreadyExist.type isn't supposed to conform with UserServiceError[without .type].
Where am I doing it wrong?
I didn't taken into account that you can have matchers inside beSome() so with next changes test code works (see beEqualTo):
must beSome(beEqualTo(UserService.UserAlreadyExist)).await
I moved UserServiceError's into UserService's companion object also.

what is the input type of classOf

I am wondering what type do I put in place of XXX
def registerClass(cl:XXX) = kryo.register(classOf[cl])
EDIT: For why I want to do this.
I have to register many classes using the above code. I wanted to remove the duplication of calling kyro.register several times, hoping to write code like below:
Seq(com.mypackage.class1,com.mypackage.class2,com.mypackage.class3).foreach(registerClass)
Another question, can I pass String instead? and convert it somehow to a class in registerClass?
Seq("com.mypackage.class1","com.mypackage.class2").foreach(registerClass)
EDIT 2:
When I write com.mypackage.class1, it means any class defined in my source. So if I create a class
package com.mypackage.model
class Dummy(val ids:Seq[Int],val name:String)
I would provide com.mypackage.model.Dummy as input
So,
kryo.register(classOf[com.mypackage.model.Dummy])
Kryo is a Java Serialization library. The signature of the register class is
register(Class type)
You could do it like this:
def registerClass(cl:Class[_]) = kryo.register(cl)
And then call it like this:
registerClass(classOf[Int])
The type parameter to classOf needs to be known at compile time. Without knowing more about what you're trying to do, is there any reason you can't use:
def registerClass(cl:XXX) = kryo.register(cl.getClass)