Can you capture and inspect arguments supplied to a method under test with ScalaMock? - scala

The Java Mocking framework Mockito has a utility class called ArgumentCaptor that accumulates a list of values as a method under verification is invoked multiple times.
Does ScalaMock have a similar mechanism?

There's an under the hood mechanism that does this in the preview release of ScalaMock3, but it's not currently exposed to client code.
What's your use case for this?
You might be able to achieve what you need by using where or onCall documented here (under the "Predicate matching" and "Return Value" headings respectively).

In Specs2 you can use the following:
myMock.myFunction(argument) answers(
passedArgument => "something with"+passedArgument
)
This maps to Mockito's ArgumentCaptor under the hood.

According to the Mockito documentation, you can use specs2 matchers directly, e.g.
val myArgumentMatcher: PartialFunction[ArgumentType, MatchResult[_]] = {
case argument => argument mustEqual expectedValue
}
there was one(myMock).myFunction(beLike(myArgumentMatcher))
The cool thing about this solution is that the partial function allows for really great flexibility. You can pattern match on your argument, etc. Of course, if you really just need to compare the argument value, then there's no need for the partial function, you can just do
there was one(myMock).myFunction(==_(expectedValue))

Another option is to implement your own argument captor by extending the existing matchers. Something of the kind should do the trick (For scalamock 3) :
trait TestMatchers extends Matchers {
case class ArgumentCaptor[T]() {
var valueCaptured: Option[T] = None
}
class MatchAnyWithCaptor[T](captor: ArgumentCaptor[T]) extends MatchAny {
override def equals(that: Any): Boolean = {
captor.valueCaptured = Some(that.asInstanceOf[T])
super.equals(that)
}
}
def capture[T](captor: ArgumentCaptor[T]) = new MatchAnyWithCaptor[T](captor)
}
You can use this new matcher by adding that trait to your test class
val captor = new ArgumentCaptor[MyClass]
(obj1.method(_: MyClass)).expects(capture(captor)).returns(something)
println(captor.capturedValue)

Use ArgumentCapture:
val subject = new ClassUnderTest(mockCollaborator)
// Create the argumentCapture
val argumentCapture = new ArgumentCapture[ArgumentClazz]
// Call the method under test
subject.methodUnderTest(methodParam)
// Verifications
there was one (mockCollaborator).someMethod(argumentCapture)
val argument = argumentCapture.value
argument.getSomething mustEqual methodParam

Related

Using Scala macros, can i make implementer of method call super?

Can Scala macros be used to make implementers of a method in a trait invoke the super method. For instance like this:
trait Super {
//some macro magic here: list = super.list ++ child.list
def list: List[String] = List("ein", "zwei", "DIE")
}
class Sub extends Super {
override def list: List[String] = List("4", "5")
}
object Testy extends App {
println(new Sub().list) //List(ein, zwei, DIE, 4, 5)
}
Update:
See comment from #Sergey below - this is not really doable with macros.
I don't think you need macros in this particular case. In order to enforce some data from a superclass' method to be added to all results of implementing methods in any subclass, the preferred approach would be to use a template method. Make a final def performing the addition of the fixed part and an abstract def declaring the variable part, like so:
trait Super {
protected def additionalList: List[String]
final def list: List[String] = List("ein", "zwei", "DIE") ++ additionalList
}
class Sub extends Super {
protected val additionalList = List("4", "5")
}
object Testy extends App {
println(new Sub().list) // List(ein, zwei, DIE, 4, 5)
}
Update: If, however, you need exactly the behavior as specified in the original question, then you're out of luck, I fear: a macro can only affect what it immediately wraps, e.g. a def macro can only transform what is passed into the method, and an annotation macro can only transform its immediate annottee, be it a class, a field, a method, etc. There's no way for a macro to enforce rules on code which doesn't even know about the macro. So basically you have two options: either make your users call super manually, or write an annotation macro and have your users annotate their subclasses with it. Both of these options are easy to omit, unfortunately.

How to stub a method call with an implicit matcher in Mockito and Scala

My application code uses AService
trait AService {
def registerNewUser (username: String)(implicit tenant: Tenant): Future[Response]
}
to register a new user. Class Tenant is a simple case class:
case class Tenant(val vstNumber:String, val divisionNumber:String)
Trait AServiceMock mimics the registration logic by using a mocked version of AService
trait AServiceMock {
def registrationService = {
val service = mock[AService]
service.registerNewUser(anyString) returns Future(fixedResponse)
service
}
}
Iow whenever registerNewUser is called on AService the response will be "fixedResponse" (defined elsewhere).
My question is, how do I define the implicit tenant-parameter as a mockito matcher like anyString?
btw. I'm using Mockito with Specs2 (and Play2)
Sometimes you have to post on SO first to come up with the completely obvious answer (duhh):
service.registerNewUser(anyString)(any[Tenant]) returns Future(fixedResponse)
This a complement to #simou answer. For now I think this is how it should be done, but I think it is intresting to know why the alternative solution proposed by #Enrik should be avoided as it may fail at run time with a cryptic error in some circumstances.
What you can safely do is if you want an exact match on your implicit argument for your stub, you can just add it in the scope :
trait AServiceMock {
implicit val expectedTenant: Tenant = Tenant("some expected parameter")
def registrationService = {
val service = mock[AService]
service.registerNewUser(anyString) returns Future(fixedResponse)
service
}
}
This will work fine but only if service.registerNewUser is expected to be called with the exact same tenant that the one provided by the implicit value expectedTenant .
What will not reliably work on the other hand is anything in the style :
implicit val expectedTenant1: Tenant = any[Tenant]
implicit def expectedTenant2: Tenant = any[Tenant]
implicit def expectedTenant3: Tenant = eqTo(someTenant)
To reason is related to how mockito create its argument matcher.
When you write myFunction(*,12) returns "abc" mockito actually use a macro that :
add code to intialize a list were argument matcher can register
If needed, wrap all argument that are not matcher in matchers.
add code to retrive the list of matchers that were declared for this function.
In the case of expectedTenant2 or expectedTenant3 what may append is that a first argument matcher will be registerd when the function is evaludated. But the macro will not see this function is registering a macther. It will only consider the declared return type of this function and so may decide to wrap this returned value inside a second matcher.
So in practice if you have code like this
trait AServiceMock {
implicit def expectedTenant(): Tenant = any[Tenant]
def registrationService = {
val service = mock[AService]
service.registerNewUser(anyString) returns Future(fixedResponse)
service
}
}
You expect it to be like that after applying the implicit :
trait AServiceMock {
def registrationService = {
val service = mock[AService]
service.registerNewUser(anyString)(any[Tenant]) returns Future(fixedResponse)
service
}
}
But actually mockito macro will make it as something more or less like that :
trait AServiceMock {
def registrationService = {
val service = mock[AService]
// In practice the macro use DefaultMatcher and not eqTo but that do not change much for the matter we discuss.
service.registerNewUser(anyString)(eqTo(any[Tenant])) returns Future(fixedResponse)
service
}
}
So now you declare two matcher inside the implicit argument of your stub. When mockito will retrive the list of matchers that were declared for registerNewUser, it will see three of them and will think that you are trying to register a stub with three argument for a function that need only two and will log :
Invalid use of argument matchers!
2 matchers expected, 3 recorded:
I'm not yet sure why it may still work in some cases, my hypotheses are :
Maybe the macro sometime decide in some case that a matcher is not needed, and do not wrap the value returned by implicit function in an additional matcher.
Maybe with some leniency option enabled, mockito ignore additional matcher. Even if that was the case, the additonal matcher may mess up the order of the argument for your stub.
It may be also possible that under some circonstance, the scala compiler inline the implicit def, this would allow the macro to see that a matcher was used.

How can I add new methods to a library object?

I've got a class from a library (specifically, com.twitter.finagle.mdns.MDNSResolver). I'd like to extend the class (I want it to return a Future[Set], rather than a Try[Group]).
I know, of course, that I could sub-class it and add my method there. However, I'm trying to learn Scala as I go, and this seems like an opportunity to try something new.
The reason I think this might be possible is the behavior of JavaConverters. The following code:
class Test {
var lst:Buffer[Nothing] = (new java.util.ArrayList()).asScala
}
does not compile, because there is no asScala method on Java's ArrayList. But if I import some new definitions:
class Test {
import collection.JavaConverters._
var lst:Buffer[Nothing] = (new java.util.ArrayList()).asScala
}
then suddenly there is an asScala method. So that looks like the ArrayList class is being extended transparently.
Am I understanding the behavior of JavaConverters correctly? Can I (and should I) duplicate that methodology?
Scala supports something called implicit conversions. Look at the following:
val x: Int = 1
val y: String = x
The second assignment does not work, because String is expected, but Int is found. However, if you add the following into scope (just into scope, can come from anywhere), it works:
implicit def int2String(x: Int): String = "asdf"
Note that the name of the method does not matter.
So what usually is done, is called the pimp-my-library-pattern:
class BetterFoo(x: Foo) {
def coolMethod() = { ... }
}
implicit def foo2Better(x: Foo) = new BetterFoo(x)
That allows you to call coolMethod on Foo. This is used so often, that since Scala 2.10, you can write:
implicit class BetterFoo(x: Foo) {
def coolMethod() = { ... }
}
which does the same thing but is obviously shorter and nicer.
So you can do:
implicit class MyMDNSResolver(x: com.twitter.finagle.mdns.MDNSResolver) = {
def awesomeMethod = { ... }
}
And you'll be able to call awesomeMethod on any MDNSResolver, if MyMDNSResolver is in scope.
This is achieved using implicit conversions; this feature allows you to automatically convert one type to another when a method that's not recognised is called.
The pattern you're describing in particular is referred to as "enrich my library", after an article Martin Odersky wrote in 2006. It's still an okay introduction to what you want to do: http://www.artima.com/weblogs/viewpost.jsp?thread=179766
The way to do this is with an implicit conversion. These can be used to define views, and their use to enrich an existing library is called "pimp my library".
I'm not sure if you need to write a conversion from Try[Group] to Future[Set], or you can write one from Try to Future and another from Group to Set, and have them compose.

Mockito for Objects in Scala

I'm using Scala 2.10, specs2 and Mockito. I want to mock scala.io.Source.fromURL(). The issue seems to be fromURL() is a function in io.Source's object.
val m = mock[io.Source]
m.fromURL returns io.Source.fromString("Some random string.")
It's a pretty straightforward mock in an Unit test. Why isn't it working?
Thanks!
Instead of mocking it, you could try spying it as follows:
val m = spy(io.Source)
Or you could mock it as follows:
val m = mock[io.Source.type]
But then how are you using Source in the class you are testing? If you had an example class like so:
class MyClass{
def foo = {
io.Source.doSomething //I know doSomething is not on Source, call not important
}
}
Then in order to take advantage of mocking/spying, you'd have to structure your class like so:
class MyClass{
val source = io.Source
def foo = {
source.doSomething
}
}
And then your test would have to look something like this:
val mockSource = mock[io.Source.type]
val toTest = new MyClass{
override val source = mockSource
}
In the Java world, static methods are the bane of mocking. In the Scala world, calls to objects can also be troublesome to deal with for unit tests. But if you follow the code above, you should be able to properly mock out an object based dependency in your class.
Good news! With the latest 1.16 release of mockito-scala, you can now mock scala objects.
To enable withObjectMocked feature, it is mandatory to create the file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker containing a single line:
mock-maker-inline
Example:
object FooObject {
def simpleMethod: String = "not mocked!"
}
"mock" should {
"stub an object method" in {
FooObject.simpleMethod shouldBe "not mocked!"
withObjectMocked[FooObject.type] {
FooObject.simpleMethod returns "mocked!"
//or
when(FooObject.simpleMethod) thenReturn "mocked!"
FooObject.simpleMethod shouldBe "mocked!"
}
FooObject.simpleMethod shouldBe "not mocked!"
}
}
See: https://github.com/mockito/mockito-scala#mocking-scala-object
Years later, above answer doesn't work as others have pointed out.
And you cannot mock the scala.io.Source object.
Can I mock final / private methods or classes? This is not supported, as mocks generated with macros are implemented as subclasses of the type to mock. So private and final methods cannot be overridden. You may want to try using an adapter or façade in your code to make it testable. It is better to test against a trait/interface instead of a concrete implementation. There are libraries that support this kind of mocking, such as PowerMock. Be aware that this kind of mocking involves Bytecode manipulation, which has the risk that your test double diverges from the actual implementation.
So what I did is an work around to abstract out scala.io.Source.fromUrl() as a function argument and pass in mocked function in tests.
// original func
def aFuncThatUsesSource() = {
val source = scala.io.Source("127.0.0.1:8080/...")
val result = source.mkString
Try(source.close())
result
}
// test friendly func that accepts `scala.io.Source.fromURL` as arg
def aTestFriendlyFunc(makeApiCall: String => BufferedSource) = {
val source = makeApiCall("127.0.0.1:8080/...")
val result = source.mkString
Try(source.close())
result
}
....
// test spec
def testyMcTesterson = () => {
val makeApiCall = mockFunction[String, BufferedSource]
makeApiCall.expects("something...")
.returns( new BufferedSource(new ByteArrayInputStream("returns something".getBytes)) )
aTestFriendlyFunc(makeApiCall) shouldEqual "returns something"
}

Generating a Scala class automatically from a trait

I want to create a method that generates an implementation of a trait. For example:
trait Foo {
def a
def b(i:Int):String
}
object Processor {
def exec(instance: AnyRef, method: String, params: AnyRef*) = {
//whatever
}
}
class Bar {
def wrap[T] = {
// Here create a new instance of the implementing class, i.e. if T is Foo,
// generate a new FooImpl(this)
}
}
I would like to dynamically generate the FooImpl class like so:
class FooImpl(val wrapped:AnyRef) extends Foo {
def a = Processor.exec(wrapped, "a")
def b(i:Int) = Processor.exec(wrapped, "b", i)
}
Manually implementing each of the traits is not something we would like (lots of boilerplate) so I'd like to be able to generate the Impl classes at compile time. I was thinking of annotating the classes and perhaps writing a compiler plugin, but perhaps there's an easier way? Any pointers will be appreciated.
java.lang.reflect.Proxy could do something quite close to what you want :
import java.lang.reflect.{InvocationHandler, Method, Proxy}
class Bar {
def wrap[T : ClassManifest] : T = {
val theClass = classManifest[T].erasure.asInstanceOf[Class[T]]
theClass.cast(
Proxy.newProxyInstance(
theClass.getClassLoader(),
Array(theClass),
new InvocationHandler {
def invoke(target: AnyRef, method: Method, params: Array[AnyRef])
= Processor.exec(this, method.getName, params: _*)
}))
}
}
With that, you have no need to generate FooImpl.
A limitation is that it will work only for trait where no methods are implemented. More precisely, if a method is implemented in the trait, calling it will still route to the processor, and ignore the implementation.
You can write a macro (macros are officially a part of Scala since 2.10.0-M3), something along the lines of Mixing in a trait dynamically. Unfortunately now I don't have time to compose an example for you, but feel free to ask questions on our mailing list at http://groups.google.com/group/scala-internals.
You can see three different ways to do this in ScalaMock.
ScalaMock 2 (the current release version, which supports Scala 2.8.x and 2.9.x) uses java.lang.reflect.Proxy to support dynamically typed mocks and a compiler plugin to generate statically typed mocks.
ScalaMock 3 (currently available as a preview release for Scala 2.10.x) uses macros to support statically typed mocks.
Assuming that you can use Scala 2.10.x, I would strongly recommend the macro-based approach over a compiler plugin. You can certainly make the compiler plugin work (as ScalaMock demonstrates) but it's not easy and macros are a dramatically superior approach.