How can you mock a method call on a trait with ScalaMock? - scala

Before you point to the documentation, please point out what's wrong with this minimal, failing example:
import org.scalatest.FlatSpec
import org.scalamock.scalatest.proxy.MockFactory
class StubbingTest extends FlatSpec with MockFactory {
trait Foo {
def f(x: Int): Int
}
"foo" should "stub" in {
val foo = stub[Foo]
(foo.f _).when(3).returns(4)
assert(foo.f(3) == 4)
}
}
Which results in java.lang.NoSuchMethodException: com.sun.proxy.$Proxy4.mock$f$0() at line 11: (foo.f _).when ...
According to the documentation, this should work. What am I missing here?

I figured it out by pure luck while browsing the Scaladoc:
Change
import org.scalamock.scalatest.proxy.MockFactory
to
import org.scalamock.scalatest.MockFactory
My IDE's Auto-import failed me, but it would have really helped if the ScalaMock documentation examples included proper imports.

Related

What to use instead of symbols in scalatest?

In scalatest, you’re supposed to be able to test boolean properties using symbols like this:
iter shouldBe 'traversableAgain
But this notation have been deprecated in the most recent versions of scala, so now you’re supposed to write:
iter shouldBe Symbol("traversableAgain")
Which is a bit ugly. Is there any better alternative?
Consider BePropertyMatcher which provides type-safe predicate matching syntax
iter should be (traversableAgain)
for example
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.{BePropertyMatchResult, BePropertyMatcher}
import org.scalatest.matchers.should.Matchers
trait CustomMatchers {
val traversableAgain = new BePropertyMatcher[Iterator[_]] {
def apply(left: Iterator[_]): BePropertyMatchResult =
BePropertyMatchResult(left.isTraversableAgain, "isTraversableAgain")
}
}
class BePropertyMatcherExampleSpec extends AnyFlatSpec with Matchers with CustomMatchers {
"BePropertyMatcher" should "provide type-safe checking of predicates" in {
Iterator(42, 11) should be (traversableAgain)
}
}
There is also a related issue Replacement for using symbols as property matchers for 2.13+ #1679

Initialising variables in a mock class scala

I am writing unit tests for an akka actor model implementation. The system contains classes and traits that need to be initialised. My issue lies with the testing of the methods. When I mock required parameters for a class, it removes the intelij compiler error, however all of the variables are set to null.
I have attempted to use
when(mock.answer).thenReturn(42)
and directly assigning the variables
val mock.answer = 42
The above two through compilation errors. "When" is not recognised and directly assigning values cases a runtime error.
Any insight would be much appreciated.
I am not sure if I understood your issue correctly, but try the self contained code snippet below and let me know if it is not clear enough:
import org.junit.runner.RunWith
import org.scalatest.junit.JUnitRunner
import org.scalatest.mockito.MockitoSugar
import org.scalatest.{FunSuite, Matchers}
import org.mockito.Mockito.when
#RunWith(classOf[JUnitRunner])
class MyTest extends FunSuite with Matchers with MockitoSugar {
trait MyMock {
def answer: Int
}
test("my mock") {
val myMock = mock[MyMock]
when(myMock.answer).thenReturn(42)
myMock.answer should be(42)
}
}

`exception during macro expansion: [error] scala.reflect.macros.TypecheckException` when using quill

I'm pretty new to Scala, Play, and Quill and I'm not sure what I'm doing wrong. I have my project split up into models, repositories, and services (and controllers, but that is not relevant for this question). Right now, I'm getting this error for the lines in my services that are making changes to the database:
exception during macro expansion: scala.reflect.macros.TypecheckException: Can't find implicit `Decoder[models.AgentId]`. Please, do one of the following things:
1. ensure that implicit `Decoder[models.AgentId]` is provided and there are no other conflicting implicits;
2. make `models.AgentId` `Embedded` case class or `AnyVal`.
And I'm getting this error for all the other lines in my services:
exception during macro expansion: [error] scala.reflect.macros.TypecheckException: not found: value quote
I found a similar ticket, but the same fix does not work for me (I am already requiring ctx as an implicit variable, so I can't import it as well. I'm totally at a loss and if anyone has any suggestions, I would be happy to try anything. I'm using the following versions:
Scala 2.12.4
Quill 2.3.2
Play 2.6.6
The code:
db/package.scala
package db
import io.getquill.{PostgresJdbcContext, SnakeCase}
package object db {
class DBContext(config: String) extends PostgresJdbcContext(SnakeCase, config)
trait Repository {
val ctx: DBContext
}
}
repositories/AgentsRepository.scala
package repositories
import db.db.Repository
import models.Agent
trait AgentsRepository extends Repository {
import ctx._
val agents = quote {
query[Agent]
}
def agentById(id: AgentId) = quote { agents.filter(_.id == lift(id)) }
def insertAgent(agent: Agent) = quote {
query[Agent].insert(_.identifier -> lift(agent.identifier)
).returning(_.id)
}
}
services/AgentsService.scala
package services
import db.db.DBContext
import models.{Agent, AgentId}
import repositories.AgentsRepository
import scala.concurrent.ExecutionContext
class AgentService(implicit val ex: ExecutionContext, val ctx: DBContext)
extends AgentsRepository {
def list: List[Agent] =
ctx.run(agents)
def find(id: AgentId): List[Agent] =
ctx.run(agentById(id))
def create(agent: Agent): AgentId = {
ctx.run(insertAgent(agent))
}
}
models/Agent.scala
package models
import java.time.LocalDateTime
case class AgentId(value: Long) extends AnyVal
case class Agent(
id: AgentId
, identifier: String
)
I am already requiring ctx as an implicit variable, so I can't import it as well
You don't need to import a context itself, but everything which is inside in order to make it work
import ctx._
Make sure to place it before ctx.run called, as in https://github.com/getquill/quill/issues/998#issuecomment-352189214

scalatest Flatspec: Timeout for entire class

With the scalatest Flatspec and the TimeLimits trait I can set a timeout for a line of code like so:
import org.scalatest.time.SpanSugar._
import org.scalatest.concurrent.TimeLimits
import org.scalatest.FlatSpec
class MyTestClass extends Flatspec with TimeLimits {
"My thread" must "complete on time" in {
failAfter(100 millis) { infiniteLoop() }
// I have also tried cancelAfter
}
}
This should fail due to a timeout. However, when I run this test in Intellij it just runs forever.
Furthermore, I do not want to have to rewrite the timeout for every method, instead I would like to configure it once for the entire class. The PatienceConfig claims to do that, but it does not seem to do anything. The test is still runs forever.
import org.scalatest.FlatSpec
import org.scalatest.time.{Millis, Span}
import org.scalatest.concurrent.{Eventually, IntegrationPatience}
class MyTestClass extends Flatspec with Eventually with IntegrationPatience {
implicit val defaultPatience = PatienceConfig(timeout=Span(100, Millis))
"My thread" must "complete on time" in {
inifiniteLoop()
}
}
I looked for a solution myself. came a cross this answer, it worked for me.
I am using flatspec, added the trait TimeLimitedTests
with TimeLimitedTests
then inside the code I wrote my limit for each of the tests val timeLimit: Span = Span(2000, Millis)
which is defined by the trait (we are overriding it).
Finally it didn't work until I overriden the interrupter as suggested by Rumoku in the referenced answer by
override val defaultTestInterruptor: Interruptor = new Interruptor {
override def apply(testThread: Thread): Unit = {
println("Kindly die")
testThread.stop() // deprecated. unsafe. do not use
}}
I hope this helps

Scalamock: How to get "expects" for Proxy mocks?

I am using Scalamock with ScalaTest, and am trying to mock a Java interface. I currently have:
private val _iface = mock [MyInterface]
now I want to do
_iface expects `someMethod returning "foo" once
But the compiler does not find expects.
I imported org.scalatest._ and org.scalamock.scalatest._. What else am I missing?
First of all, proxy mocks are not supported very well in ScalaMock 3, and I think they will be completely removed in ScalaMock 4. Do you really need to use proxy mocks instead macro mocks?
This should work:
package example
import org.scalatest.FlatSpec
import org.scalatest.Matchers
import org.scalamock.scalatest.proxy.MockFactory
trait MyInterface {
def someMethod : String
}
class MyTest extends FlatSpec with Matchers with MockFactory {
"MyInterface" should "work" in {
val m = mock[MyInterface]
m.expects('someMethod)().returning("foo")
m.someMethod shouldBe "foo"
}
}
If not, please check ScalaMock proxy mocks unit tests for more examples.
I think it should be something more like:
import org.scalamock.scalatest.MockFactory
class MyTest extends FlatSpec with Matchers with MockFactory {
"MyInterface" should "work" in {
val m = mock[MyInterface]
(m.someMethod _).expects().returning("foo")
m.someMethod shouldBe "foo"
}
}
I think the expects arg is expecting the arg to the function
I use scalaMock version 4.1.0, this works for me:
For some trait:
trait MyInterface { def someMethod(n1: Int, n2: Int) }
This should be put into a test
val myInterfaceMock = mock[MyInterface]
myInterfaceMock.someMethod _ expects (1,2)
For more reading: scalaMock Guide, you'll find some examples there