Mockito Scala Specs2 mocking complex functions (Play Framework) - scala

I'm trying to properly stub the ehCache API used by Play Framework. In particular, its getOrElse function with signature:
def getOrElse[A: ClassTag](key: String, expiration: Duration)(orElse: => A)
Within my specs 2 code, I have:
val mockCache = mock[EhCacheApi]
mockCache.getOrElse[???](anyString,anyObject[Duration])(???) returns
[Object I'd like returned]
Question is if it's possible to use matchers for the ??? parts, especially for the currying argument part.
The return type for the CacheApi function should be Future[Seq[Object]] .
Public git repo link: Github

This works
class VariationAssignmentSpec(implicit ee: ExecutionEnv) extends PlaySpecification with Mockito {
case class Variation(id: Option[Long] = None)
lazy val v1 = Variation(Option(1L))
lazy val v2 = Variation(Option(2L))
"Cache#getOrElse" should {
"return correct result" in {
val mockCache = mock[CacheApi]
mockCache.getOrElse[Future[Seq[Variation]]](anyString, any[Duration])(any)(any) returns
Future(Seq(v1, v2))
val resultFuture: Future[Seq[Variation]] =
mockCache.getOrElse("cache.key", 10.seconds)(Future(Seq(v1,v2)))
resultFuture must equalTo(Seq(v1,v2)).await
}
}
}

Related

Error converting Play Silhouette Module from Guice To Macwire

I am trying to convert from Guice to Macwire as a dependency injection framework. It is going fine apart from this Silhouette Module where I am getting a compilation error. Error at bottom.
Working Module in Guice:
class SilhouetteModule #Inject()(environment: play.api.Environment, configuration:
Configuration) extends AbstractModule with ScalaModule {
override def configure() = {
val iamConfig = IAMConfiguration
.fromConfiguration(configuration)
.fold(throw _, identity)
val htPasswdFile = File.apply(configuration.get[String]("file"))
bind[IdentityService[User]].toInstance(SimpleIdentityService.fromConfig(iamConfig))
bind[Silhouette[BasicAuthEnv]].to[SilhouetteProvider[BasicAuthEnv]]
bind[RequestProvider].to[BasicAuthProvider].asEagerSingleton()
bind[PasswordHasherRegistry].toInstance(PasswordHasherRegistry(new BCryptPasswordHasher()))
bind[AuthenticatorService[DummyAuthenticator]].toInstance(new DummyAuthenticatorService)
bind[AuthInfoRepository].toInstance(HtpasswdAuthInfoRepository.fromFile(htPasswdFile))
bind[SecuredErrorHandler].to[RestHttpSecuredErrorHandler]
}
#Provides
def provideEnvironment(identityService: IdentityService[User], authenticatorService:
AuthenticatorService[DummyAuthenticator], eventBus: EventBus, requestProvider:
RequestProvider): Environment[BasicAuthEnv] =
Environment[BasicAuthEnv](
identityService,
authenticatorService,
Seq(requestProvider),
eventBus
)
}
}
Equivalent attempt in Macwire:
trait SilhouetteModule extends BuiltInComponents {
import com.softwaremill.macwire._
val iamConfig = IAMConfiguration
.fromConfiguration(configuration)
.fold(throw _, identity)
val htPasswdFile = File.apply(configuration.get[String]("file"))
lazy val identityService: IdentityService[User] =
SimpleIdentityService.fromConfig(iamConfig)
lazy val basicAuthEnv: Silhouette[BasicAuthEnv] = wire[SilhouetteProvider[BasicAuthEnv]]
lazy val requestProvider: RequestProvider = wire[BasicAuthProvider]
lazy val passwordHasherRegistry: PasswordHasherRegistry = PasswordHasherRegistry(
new BCryptPasswordHasher())
lazy val authenticatorService: AuthenticatorService[DummyAuthenticator] =
new DummyAuthenticatorService
lazy val authInfoRepo: AuthInfoRepository =
HtpasswdAuthInfoRepository.fromFile(htPasswdFile)
lazy val errorHandler: SecuredErrorHandler = wire[RestHttpSecuredErrorHandler]
lazy val env: Environment[BasicAuthEnv] = Environment[BasicAuthEnv](
identityService,
authenticatorService,
Seq(requestProvider),
eventBus
)
def eventBus: EventBus
}
The Macwire example does not compile: I get an error:
Cannot find a value of type: [com.mohiva.play.silhouette.api.actions.SecuredAction]
lazy val basicAuthEnv: Silhouette[BasicAuthEnv] = wire[SilhouetteProvider[BasicAuthEnv]]
Sorry its a lot of code but I thought a side-by-side comparison would be more helpful.
Any help would be great!
MacWire doesn't magically creates values - if it needs to construct a value, it looks what values are taken by the constructor and - if by looking at all values available in the scope it can unambiguously find all the parameters of the constructor, the macro creates code new Class(resolvedArg1, resolvedArg2, ...).
So
all of these values have to be in Scope - they can be constructed by MacWire, or be abstract members implemented by some mixin, but still you have to write them down explicitly
if you have 2 values of the same type in scope - MacWire cannot generate the code because how it would know which value to pick? (Well, if one of the values is in closer "closer" than the other it can, but if they are equally close it cannot be resolved)
So if you get the error:
Cannot find a value of type: [com.mohiva.play.silhouette.api.actions.SecuredAction]
it means that you haven't declared any value of type com.mohiva.play.silhouette.api.actions.SecuredAction in SilhouetteModule nor in BuiltInComponents.
If this is something that is provided by another trait you can add abstract declaration here
val securedAction: SecuredAction // abstract val
and implement it somewhere else (be careful to avoid circular dependencies!).

Mock new object creation in Scala

I want to write unit test for below scala class.
In the below implementation, QueryConfig is final case class.
class RampGenerator {
def createProfile(queryConfig: QueryConfig): String = {
new BaseQuery(queryConfig).pushToService().getId
}
}
The unit test I have written is this
#RunWith(classOf[JUnitRunner])
class RampGeneratorTest extends FlatSpec with Matchers {
"createProfile" must "succeed" in {
val rampGenerator = new RampGenerator()
val queryConfig = QueryConfig("name", "account", “role")
val baseQuery = mock(classOf[BaseQuery])
val profile = mock(classOf[Profile])
when(new BaseQuery(queryConfig)).thenReturn(baseQuery)
when(baseQuery.pushToService()).thenReturn(profile)
when(profile.getId).thenReturn("1234")
val id = rampGenerator.createProfile(queryConfig)
assert(id.equals("1234"))
}
}
Currently it gives below exception, which is expected, since I don't have mocked class used in when. How do I mock the new instance creation?
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
There are two options:
Use powermockito to mock the constructor (see this question for details)
Externalize object creation
A bit more on the second option - this is actually a testing technique that helps in a variety of situations (a couple of examples: yours, creating akka actors and asserting on hierarchies) - so it might be useful to just have it in the "toolbox".
In your case it'll look something like this:
class RampGenerator(queryFactory: QueryFactory) {
def createProfile(queryConfig: QueryConfig) = queryFactory.buildQuery(queryConfig).pushToService().getId()
}
class QueryFactory() {
def buildQuery(queryConfig: QueryConfig): BaseQuery = ...
}
#RunWith(classOf[JUnitRunner])
class RampGeneratorTest extends FlatSpec with Matchers {
"createProfile" must "succeed" in {
val rampGenerator = new RampGenerator()
val queryConfig = QueryConfig("name", "account", “role")
val queryFactory = mock(classOf[QueryFactory])
val profile = mock(classOf[Profile])
val baseQuery = mock(classOf[BaseQuery])
when(queryFactory.buildQuery(queryConfig)).thenReturn(baseQuery)
when(baseQuery.pushToService()).thenReturn(profile)
when(profile.getId).thenReturn("1234")
val id = rampGenerator.createProfile(queryConfig)
assert(id.equals("1234"))
}
}
Please note query factory does not have to be a separate factory class/hierarchy of classes (and certainly does not require something as heavyweight as abstract factory pattern - although you can use it). In particular, my initial version was just using queryFactory: QueryConfig => BaseQuery function, but mockito cannot mock functions...
If you prefer to inject factory method directly (via function), Scalamock has support for mocking functions

Way to enhance a class with function delegation

I have the following classes in Scala:
class A {
def doSomething() = ???
def doOtherThing() = ???
}
class B {
val a: A
// need to enhance the class with both two functions doSomething() and doOtherThing() that delegates to A
// def doSomething() = a.toDomething()
// def doOtherThing() = a.doOtherThing()
}
I need a way to enhance at compile time class B with the same function signatures as A that simply delegate to A when invoked on B.
Is there a nice way to do this in Scala?
Thank you.
In Dotty (and in future Scala 3), it's now available simply as
class B {
val a: A
export a
}
Or export a.{doSomething, doOtherThing}.
For Scala 2, there is unfortunately no built-in solution. As Tim says, you can make one, but you need to decide how much effort you are willing to spend and what exactly to support.
You can avoid repeating the function signatures by making an alias for each function:
val doSomething = a.doSomething _
val doOtherthing = a.doOtherThing _
However these are now function values rather than methods, which may or may not be relevant depending on usage.
It might be possible to use a trait or a macro-based solution, but that depends on the details of why delegation is being used.
Implicit conversion could be used for delegation like so
object Hello extends App {
class A {
def doSomething() = "A.doSomething"
def doOtherThing() = "A.doOtherThing"
}
class B {
val a: A = new A
}
implicit def delegateToA(b: B): A = b.a
val b = new B
b.doSomething() // A.doSomething
}
There is this macro delegate-macro which might just be what you are looking for. Its objective is to automatically implement the delegate/proxy pattern, so in your example your class B must extend class A.
It is cross compiled against 2.11, 2.12, and 2.13. For 2.11 and 2.12 you have to use the macro paradise compile plugin to make it work. For 2.13, you need to use flag -Ymacro-annotations instead.
Use it like this:
trait Connection {
def method1(a: String): String
def method2(a: String): String
// 96 other abstract methods
def method100(a: String): String
}
#Delegate
class MyConnection(delegatee: Connection) extends Connection {
def method10(a: String): String = "Only method I want to implement manually"
}
// The source code above would be equivalent, after the macro expansion, to the code below
class MyConnection(delegatee: Connection) extends Connection {
def method1(a: String): String = delegatee.method1(a)
def method2(a: String): String = delegatee.method2(a)
def method10(a: String): String = "Only method I need to implement manually"
// 96 other methods that are proxied to the dependency delegatee
def method100(a: String): String = delegatee.method100(a)
}
It should work in most scenarios, including when type parameters and multiple argument lists are involved.
Disclaimer: I am the creator of the macro.

How to bind Class with Google Guice using a FQDN String

I'm using Play 2.5 with the Guice dependency injection.
Normal bind works like:
bind(classOf[SomeClass]).to(classOf[DefaultClass])
I now only need to be able to bind a class where the className has been specified in the Configuration.
I tried something like:
val className = config.getString("someClass.className")
val x: Class[_] = Class.forName(className)
bind(classOf[SomeClass]).to(classOf[x])
But then the types are wrong.
It needs to be done via Guice, since the SomeClass has an argument that needs to be injected, otherwise I would have used something like
val className = config.getString("someClass.className")
val x = Class.forName(className).newInstance().asInstanceOf[SomeClass]
bind(classOf[SomeClass]).toInstance(x)
Does anybody have an idea on how to bind it via guice?
I think you are looking for something like this...
lazy val injector = (new GuiceApplicationBuilder).injector()
def inject[T : ClassTag]: T = {
injector.instanceOf[T]
}
This is the simplest version, but doesn't handle arguments. You would create a class and then call this as inject[SomeDep].
I've not found a good way of injecting on-the-fly, the only way of really doing it via #inject at the top most invoked class. We only use inject for unit tests at present.
Thanks for the reply, but I finally got it to work using Scala's Reflection.
object Reflection {
import scala.reflect.api
import reflect.runtime.universe._
import reflect.ClassTag
def classTagToClass[T: reflect.ClassTag]: Class[T] = {
def ctag = implicitly[reflect.ClassTag[T]]
ctag.runtimeClass.asInstanceOf[Class[T]]
}
def typeToClassTag[T: TypeTag]: ClassTag[T] = {
ClassTag[T]( typeTag[T].mirror.runtimeClass( typeTag[T].tpe ) )
}
def stringToTypeTag[A](name: String): TypeTag[A] = {
val c = Class.forName(name) // obtain java.lang.Class object from a string
val mirror = runtimeMirror(c.getClassLoader) // obtain runtime mirror
val sym = mirror.staticClass(name) // obtain class symbol for `c`
val tpe = sym.selfType // obtain type object for `c`
// create a type tag which contains above type object
TypeTag(mirror, new api.TypeCreator {
def apply[U <: api.Universe with Singleton](m: api.Mirror[U]): U#Type =
if (m eq mirror) {
tpe.asInstanceOf[U#Type]
}
else {
throw new IllegalArgumentException(s"Type tag defined in $mirror cannot be migrated to other mirrors.")
}
})
}
}
using the above object you can bind a class using it FQDN in the following way:
configuration.getString("config.className")
.map(className =>
bind(classOf[AbstractClass]).to(classTagToClass(typeToClassTag(stringToTypeTag[AbstractClass](className))))
).getOrElse(bind(classOf[AbstractClass]).to(classOf[AbstractClassImpl]))

Proxy class support

Is there Scala way for runtime generation of proxy classes? not DynamicProxy but runtime types that extend provided class/interface and pass all calls through provided callback.
Java world uses cglib/javassist for that, but what is the best way to proxy in Scala?
def makeProxy[T](interceptor: Interceptor, implicit baseClass: Manifest[T]): T
Google says Scala macros can be used for this but I am unsure how.
Here is an example how (more-less) to do something like that with macro:
def testImpl[T : c.WeakTypeTag](c: Context): c.Expr[Any] = {
import c.universe._
val className = newTypeName(weakTypeTag[T].tpe.typeSymbol.name.toString) //not best way
val m = weakTypeOf[T].declarations.iterator.toList.map(_.asMethod) //`declaration` takes only current; `members` also takes inherited
.filter(m => !m.isConstructor && !m.isFinal).map { m => //all reflection info about method
q"""override def ${m.name} = 9""" //generating new method
}
c.Expr { q"""new $className { ..$m } """}
}
def t[T] = macro testImpl[T]
class Aaa{ def a = 7; def b = 8}
scala> t[Aaa].a
res39: Int = 9
scala> t[Aaa].b
res40: Int = 9
All such macro works only if overriden methods are not final as they can't change types (as it works in compile-time) - only create new and inherit. This example doesn't process classes with non-empty constructors and many other things. m here is instance of MethodSymbol and gives you full scala-style reflection about input class' method. You need only generate correct AST in response.
To read more about that:
macroses: http://docs.scala-lang.org/overviews/macros/overview.html
scala's runtime-reflection http://docs.scala-lang.org/overviews/reflection/environment-universes-mirrors.html
q"asiquotes" : http://docs.scala-lang.org/overviews/quasiquotes/expression-details.html
Another solution would be:
scala> def getClasss[T: ClassTag] = classTag[T].runtimeClass
getClasss: [T](implicit evidence$1: scala.reflect.ClassTag[T])Class[_]
Using this instance you can apply any asm/cglib/javassist or even DynamicProxy to it.