Initialising variables in a mock class scala - 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)
}
}

Related

Why are nested Java classes not importable from Scala?

How am I supposed to mock a nested Java class using scalamock, especially when said nested Java class is coming from a third party library?
Given the following sources:
src/main/java/Outer.java
/**
* Outer class that offers a Nested class inaccessible from Scala :(
*/
public class Outer {
public class Nested {
}
}
src/main/java/UseNestedJavaClassFromJava.java
public class UseNestedJavaClassFromJava {
private Outer.Nested nested;
}
src/main/scala/ImportNestedJavaClass.scala
// TODO uncomment the below line to break the build
//import Outer.Nested
Uncommenting the scala import line results in a compilation failure while compiling UseNestedJavaClassFromJava.java works just fine.
Full minimal example with gradle: https://github.com/billyjf/async-http-client-gradle-scala.
Apparently this was somewhat already addressed in the below question, but resorting to Java glue code or reflection trickery just for the sake of testing Scala code that leverages a Java library with nested Java classes seems a bit unreasonable to me, is there really no other solution?
Scala can't access Java inner class?
I finally found a solution using Mockito:
import org.mockito.Mockito
import org.scalamock.scalatest.MockFactory
import org.scalatest.mockito.MockitoSugar
import org.scalatest.{FlatSpec, Matchers}
class OuterNestedTest extends FlatSpec with MockFactory with Matchers with MockitoSugar {
"Nested Java class" should "be mockable using Mockito from within a scalatest" in {
val mockedNestedJavaClass = Mockito.mock(classOf[Outer#Nested])
Mockito.when(mockedNestedJavaClass.methodWithAParam("some value"))
.thenReturn("mocked", Nil: _*)
mockedNestedJavaClass.methodWithAParam("some value") shouldBe "mocked"
}
}
class Main {
val z = new Outer;
private[this] val y:z.Inner = null
}
For more context:
Outer.Inner is interpreted as Outer$.Inner (companion object).
Official Scala website:
As opposed to Java-like languages where such inner classes are members
of the enclosing class, in Scala such inner classes are bound to the
outer object.
https://docs.scala-lang.org/tour/inner-classes.html

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

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

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.

Guice and Play2 Singleton from trait

I am using Play with Scala and I am trying to create a singleton, and i want to inject it from its trait and not directly.
for example:
#ImplementedBy(classOf[S3RepositoryImpl])
trait S3Repository {
}
#Singleton
class S3RepositoryImpl extends S3Repository {
}
But this fails with error:
trait Singleton is abstract; cannot be instantiated
I have tried several combinations and they all produce the same.
I come from Spring background and its very natural there? am i missing something about how Guice handles this type of Injection?
Thanks.
As pointed out by #Tavian-Barnes, the solution is to ensure you have the following import:
import javax.inject.Singleton
I have here a "complete" working example, just hope that I'm not stating the obvious...
package controllers
import play.api._
import play.api.mvc._
import com.google.inject._
class Application #Inject() (s3: S3Repository) extends Controller {
def index = Action {
println(s3.get)
Ok
}
}
#ImplementedBy(classOf[S3RepositoryImpl])
trait S3Repository {
def get: String
}
#Singleton
class S3RepositoryImpl extends S3Repository {
def get: String = "bla"
}
Whenever you mark a class' constructor with #Inject the Guice will manage the injection of the instance itself. So, if you marked your class as #Singleton, Guice will create and will always give you just that one instance. Nobody can stop you from manually instantiating a class in your code... You can explore it in detail at Play.
Use below import, instead of import javax.inject.Singleton
import com.google.inject.{Inject, Singleton}
Import both Inject and Singleton.
import javax.inject.{Inject, Singleton}
Refrain from using:
import com.google.inject.{Inject, Singleton}
as play framework requires the javax import

How to instantiate lexical.Scanner in a JavaTokenParsers class?

I am writing a parser which inherits from JavaTokenParsers in that I have a function as follow:
import scala.util.parsing.combinator.lexical._
import scala.util.parsing._
import scala.util.parsing.combinator.RegexParsers;
import scala.util.parsing.combinator.syntactical.StdTokenParsers
import scala.util.parsing.combinator.token.StdTokens
import scala.util.parsing.combinator.lexical.StdLexical
import scala.util.parsing.combinator.lexical.Scanners
import scala.util.parsing.combinator.lexical.Lexical
import scala.util.parsing.input._
import scala.util.parsing.combinator.syntactical._
import scala.util.parsing.combinator.token
import scala.util.parsing.combinator._
class ParseExp extends JavaTokenParsers{
//some code for parsing
def parse(s:String) = {
val tokens = new lexical.Scanner(s)
phrase(expr)(tokens)
}
}
I am getting the following error :
type Scanner is not a member of package scala.util.parsing.combinator.lexical
[error] val tokens = new lexical.Scanner(s)
[error] ^
Why I have this error while I have imported all packages?
The JavaTokenParsers does not implement the Scanners trait. So you would need to extends also from this trait (or a trait that extends it) in order to have access to this class.
Unless your expr parser accepts the Reader as a parameter (not from its apply method), you'd need to override the type of elements and the input type if I'm not mistaken to make this working.
Also is there any reason you need to have a Reader[Token]?.
If you don't need a Reader[Token]and since you give your input in a plain string,
phrase(expr)(new CharSequenceReader(s))
should work.