Mockito Scala NullPointerException - scala

I am having troubles getting my first Mock working in my Chat application using Mockito, I am trying to mock a Repository that takes a user ID as a string and returns all the conversations for this user. I am having a very hard time getting rid of a NullPointerException
Here is my Repository trait:
trait UserRepository {
val getConversations: (String) => Option[Vector[User]]
}
Here is my Service:
class UserService(userRepository: UserRepository){
private val boolToNumber : (Boolean) => Int = (bool) => ... not useful here
private val countToBool : (Int) => Boolean = (int) => ... not useful here
val getParticipations: (String) => Option[Vector[User]] = (name) => {
userRepository.getConversations(name) match {
... some implementation
}
}
And my tests
// init
val userRepository = mock[UserRepository]
// setup
when(userRepository.getConversations("Smith")) thenReturn (
Some(
Vector(
User("Smith", true, true, ConversationKey("Smith", "Smith and O'Connell chatroom")),
User("Smith", false, true, ConversationKey("Smith", "Smith and O'Connell chatroom"))
)
)
)
val userService : UserService = new UserService(userRepository)
// run
val actual = userService.getParticipations("Smith")
// verify
actual mustBe Vector(User("Smith", false, true, ConversationKey("Smith", "Smith and O'Connell chatroom")))
What I have tried so far:
printing after each operation in the tests, printing UserRepository returns Mock for UserRepository, hashCode: 1319190020, but the UserService is not printing so it is the one throwing the NullPointerException
changing "Smith" by the matcher any[String], same error, and
anyString same error
Wrapping String in a class called StringValue, same error Mockito
matchers

Change your val functions to def functions.
Im not too sure exactly why this is, but mockito is a java library so im not surprised that it doesnt handle scala function values well where Def's compile to the same thing as java methods.

Related

Scala Spark unit test Dataset.map function

I am having trouble writing unit test for the Dataset.map function for the below snippet, I am trying to write unit test using Flatspec and Matchers library
// Function within a Class
def dataValidation(ds: Dataset[someCaseClass]): Long = {
val validDs: Dataset[Booelan] = ds.map(entry => validate(entry))
validDs.filter(entry = !entry).count
}
def validate(data: someCaseClass): Boolean{
if(valid(data))
true
else
false
}
In the above code snippet I am facing hardtime in writing mock data for
val validDs: Dataset[Booelan] = ds.map(entry => validate(entry))
I get below error if I try to mock the map function as below
unit test code
when(
mock[Dataset[someCaseClass]].map(entry => validate(entry))
).thenReturn(mock[Dataset[Boolean]])
error that I get
SmartNull returned by this unstubbed method call on a mock:
dataset.map(
<function1>,
class[value[0]: boolean]
);

Mocking for a Controller Unit-tests with ScalaTest + Play

I try to write a unit test for a small function in a controller using Play/ScalaTest+ Play. The function I want to test looks like this:
def functionToTest(id: String) = Action.async {
implicit request =>
lang
deeperFunction{ implicit context =>
...
}
}
The deeperFunction
def deeperFunction(block: Context => Future[Result])(implicit request: RequestHeader): Future[Result] = {
// returns Future.successful(Found("DummyUrltoRedirect"))
}
}
The deeperFunction is inherited from a trait and I don't want use the real one here because it's a unit test and so I want to use a matcher instead
val deeperMock = mock[Rainmaker]
val contextMock = mock[Context]
val controller = new Controller()(.....) // list of implicit arguments
"Controller" must {
"return something" in {
val request = FakeRequest("GET", "/something")
when(deeperMock.deeperFunction(anyObject)(anyObject)) thenReturn Future.successful(Found("DummyUrlToRedirect"))
val id = "id"
val result = controller.functionToTest(id).apply(request)
status(result) mustBe Ok
}
}
But when I run this, the line "val result = controller.functionToTest(id).apply(request)" still seems to call the real deeperFunction, not the fake one and therefore throws a null matcher at some point.
I also tried to use
when(controller.deeperFunction(anyObject)(anyObject)) thenReturn Future.successful(Found("DummyUrlToRedirect"))
instead, because the deeperFunction is inherited, but with the same result.
I tried to stick to theses instructions
ScalaTest+Play
dzone
but it seems I am still missing some basics/understanding. Thanks in advance.

How to bind enum on routes using scala?

I'm trying to receive some filter list as query param of a get request, which is also an enum on my controller. To do so, I'm using play framework with scala. The problem is: I can't putting the enum type as query param on it, because IDE doesn't recognize as a valid type.
So, I have something like this on routes file
GET /service-orders/ controllers.ServiceOrdersController.listServiceOrders(status: ServiceStatus)
My enum file:
object ServiceStatus extends Enumeration {
type ServiceStatus = Value
val Pending = Value("pending")
val Started = Value("started")
val Completed = Value("completed")
val Error = Value("error")
}
On build.sbt, I use this trying to inject package on routes file
routesImport ++= Seq(
"serviceOrders.models.ServiceStatus"
),
I tried a lot of things, but with no success. I read in some place that I could use QueryStringBindable function, but I can't did this works well... Can you guys please help me to solve this?
Edit: Btw, there's a way to check if status is contained on a list of filters without making this?
.filter {
serviceOrder =>
status.map(serviceOrder.serviceStatus === _)
.reduceOption(_ || _)
.getOrElse(true: Rep[Boolean])
}
This was the only way I could thought to filter status by a list of filters received as query param from API.
You can implement the QueryStringBindable instance like so:
package serviceOrders.models
object ServiceStatus extends Enumeration {
type ServiceStatus = Value
val Pending = Value("pending")
val Started = Value("started")
val Completed = Value("completed")
val Error = Value("error")
implicit val queryStringBindable: QueryStringBindable[ServiceStatus] =
new QueryStringBindable[ServiceStatus] {
override def bind(
key: String,
params: Map[String, Seq[String]]
): Option[Either[String, ServiceStatus]] =
params.get(key).collect {
case Seq(s) =>
ServiceStatus.values.find(_.toString == s).toRight("invalid value")
}
override def unbind(key: String, value: ServiceStatus): String =
implicitly[QueryStringBindable[String]].unbind(key, value.toString)
}
}
In build.sbt you need this:
routesImport ++= Seq("serviceOrders.models.ServiceStatus._")
And this in your routes file:
GET /some/route controllers.SomeController.index(status: ServiceStatus)
Then you can create an index method that takes a ServiceStatus parameter in SomeController and Play will take care of the query parameters.
// edit:
You could actually use the QueryStringBindable.Parsing class to simplify the implementation further.

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.

scala method implicit convertion not working

I have a Play 2.3 project with custom headers coming from AJAX that need to be passed to every service call (to be passed further to the web services). I thought about making it an implicit parameter, like in this dumbed down example :
case class CriteriaHeaders(license: String)
case class Criteria(criteriaHeaders: CriteriaHeaders, id: Int)
class ProjectController(service: Service) {
implicit def criteriaToCiteriaHeaders(criteria: Criteria): CriteriaHeaders = criteria.criteriaHeaders
def findName(criteria: Criteria) = {
// implicit val criteriaHeaders: CriteriaHeaders = criteria.criteriaHeaders
service
.findName(criteria.id)
.fold(
error => error,
name => name
)
}
}
class Service {
def findName(id: Int)
(implicit criteriaHeaders: CriteriaHeaders): Either[String, String] = ??? // TODO
}
(Of course in the real project there is an ActionBuilder, a Json parser etc.)
Usage :
val controller = new ProjectController(new Service())
val name = controller.findName(Criteria(CriteriaHeaders("abc"), 123))
It doesn't compile, giving an error :
Error:(21, 17) could not find implicit value for parameter licenseHeaders: A$A172.this.CriteriaHeaders.findName(criteria.id)
However, if I uncomment the implicit val, it works. Why it doesn't work with the implicit method?
EDIT :
In case anyone find this useful, I took second suggestion from #till-rohrmann and I put the implicit in the companion object of the CriteriaHeaders, so it is available in every controller using it.
object CriteriaHeaders {
implicit def criteriaToCiteriaHeaders(implicit criteria: Criteria) = criteria.criteriaHeaders
}
The problem is that an implicit conversion which takes an explicit parameter won't be called to obtain the implicit argument for the Service.findName method. There are two solutions to your problem.
Call the findName method with an explicit second parameter list and the Criteria argument. Then the compiler knows that it has to convert the criteria value into a CriteriaHeaders.
class ProjectController(service: Service) {
implicit def criteriaToCriteriaHeaders(criteria: Criteria): CriteriaHeaders = criteria.criteriaHeaders
def findName(criteria: Criteria) = {
service
.findName(criteria.id)(criteria)
.fold(
error => error,
name => name
)
}
}
Make the parameter criteria of ProjectController.criteriaToCriteriaHeaders and ProjectController.findName implicit. Then the implicit conversion will be used.
class ProjectController(service: Service) {
implicit def criteriaToCiteriaHeaders(implicit criteria: Criteria): CriteriaHeaders = criteria.criteriaHeaders
def findName(implicit criteria: Criteria) = {
service
.findName(criteria.id)
.fold(
error => error,
name => name
)
}
}