For a mocked class I have a method for which I would like to test whether there are no more interactions then needed, which looks similar to:
def someMethod(someMandatoryParam: Int, canBeDefaultIds: Option[Ids] = None): Future[Failures] = {...}
when I am mocking to invoke this method without the default parameter and I verify it that way:
verify(someClass).someMethod(someInt)
and then check if there was no more interactions:
verifyNoMoreInteractions(someClass)
I am getting an error that here was some unexpected interactions.
But when in implementation I change this method to use None instead of default value and verify:
verify(someClass).someMethod(someInt, None)
verifyNoMoreInteractions(someClass)
It works correctly.
Is there a problem with Mocikto and default values in Scala?
Default arguments is Scala specific feature which Java Mockito is likely not aware of. Consider how Scala code looks after -Xprint:jvm phase
abstract trait SomeClass extends Object {
def someInt(a: Option): Option = a;
<synthetic> def someInt$default$1(): Option = scala.None;
}
Notice how the default argument became just another method someInt$default$1. Try using mockito-scala which is designed with Scala in mind, for example the following test passes
import org.mockito.{ArgumentMatchersSugar, IdiomaticMockito}
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
trait SomeClass {
def someInt(a: Option[Int] = None) = a
}
class MockitoScalaDefaultArgsSpec extends AnyFlatSpec with Matchers with IdiomaticMockito with ArgumentMatchersSugar {
"mockito-scala" should "handle default arguments" in {
val someClass = mock[SomeClass]
someClass.someInt()
someClass.someInt() was called
someClass wasNever calledAgain
}
}
Related
I can extend my Scala class Foo with additional methods via an implicit class:
trait Foo {
def bar: String
}
object FooExtensions {
object implicits {
implicit class FooOps(foo: Foo) {
def baz: String = "baz"
}
}
}
But can I mock out those methods?
import org.mockito.Mockito
import org.scalatest.WordSpec
import org.scalatest.mockito.MockitoSugar
class MySpec extends WordSpec with MockitoSugar {
"My mock" should {
"handle methods from implicit classes" in {
import FooExtensions.implicits._
val foo = mock[Foo]
Mockito.when(foo.baz).thenReturn("bix") // fails at runtime
}
}
}
This compiles, but fails with
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
Those methods *cannot* be stubbed/verified.
Mocking methods declared on non-public parent classes is not supported.
2. inside when() you don't call method on mock but on some other object.
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);
Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
Those methods *cannot* be stubbed/verified.
Mocking methods declared on non-public parent classes is not supported.
2. inside when() you don't call method on mock but on some other object.
Is it possible to mock methods added via implicit classes? Hopefully with Mockito (or mockito-scala) but I'm interested in any approach that works.
Thing about extension methods, is that they are basically a syntactic sugar:
trait Foo
implicit class ExtensionMethods(foo: Foo) {
def bar: String = "bar
}
foo.bar
is equal to
new ExtensionMethods(foo).bar
So mocking:
Mockito.when(foo.bar).thenReturn("bix")
becomes:
Mockito.when(new ExtensionMethods(foo).bar).thenReturn("bix")
I think there is no workaround - perhaps PowerMock could let you change class constructor..., but with normal Mockito it is impossible.
Usually, it is not a problem though. That is because either:
you put into extension methods behavior, that only depends on extended value and passed parameters (and extended method is quite often pure function that doesn't require mocking) - if you want to change something there, you change input,
if behavior should change, you implement it inside a type class, and make extension method use that type class to inject behavior
trait Bar {
def bar: String
}
object Bar {
implicit val defaultBar: Bar = new Bar { def bar = "bar" }
}
implicit class ExtensionMethods(foo: Foo) {
def bar(implicit bar: Bar): String = bar.bar
}
// in test
implicit var overridenBar: Bar = ...
assert(foo.bar === "sth")
On a side note: the more functional you'll get the less you'll need to mock things as everything will depend only on input passed inside, and a cascade of mocks will become just a code smell - too tight coupling, too large interfaces, etc. Problem is that many Java libraries do not even follow SOLID principles, which makes them both hard to use/test with FP as well as bad OOP on its own. I'm telling this in case you feel mocking is the only way to go in your case.
The only way to achieve that is to use implicit conversions rather than implicit classes
This is a hack intended to show how this could be achieved, but I'd urge to take a look at the code and see why you actually need to do this
So, following your example, you could modify the code to look like this
trait Foo {
def bar: String
}
object FooExtensions {
object implicits {
implicit fooToOps(foo: Foo): FooOps = new FooOps(foo)
class FooOps(foo: Foo) {
def baz: String = "baz"
}
}
}
and your test
import org.scalatest.WordSpec
import org.mockito.MockitoSugar
class MySpec extends WordSpec with MockitoSugar {
"My mock" should {
"handle methods from implicit classes" in {
val fooOps = mock[FooOps]
implicit fooToOps(foo: Foo): FooOps = fooOps
val foo = mock[Foo]
when(foo.baz) thenReturn "bix" // works
}
}
}
the other thing to consider is that in your production you need to get an implicit parameter of the shape Foo => FooOps so when you call that method from the test the actual implicit mock is provided...
As I said, you can make it work like this, but I agree with Mateusz that you shouldn't need to
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
SLS 5.1 says "Delayed Initializaton. The initialization code of an object or class (but not a trait) that follows the superclass constructor invocation and the mixin-evaluation of the template’s base classes is passed to a special hook, which is inaccessible from user code. Normally, that hook simply executes the code that is passed to it. But templates inheriting the scala.DelayedInit trait can override the hook by re-implementing the delayedInit method, which is defined as follows:"
def delayedInit(body: => Unit)
The ScallopConf command-line parser extends DelayedInit and using it according to the docs generates the warning Selecting value apples from class Conf, which extends scala.DelayedInit, is likely to yield an uninitialized value.
How should the following simple example be rewritten so the warning is not generated?
import org.rogach.scallop._
class Conf(arguments: Seq[String]) extends ScallopConf(arguments) {
val help = opt[Boolean](name = "help", short = 'h', descr = "Help me please.")
}
object Gen {
def main(args: Array[String]) {
val conf: Conf = new Conf(args)
if (conf.help()) {
println(s"""Usage: Gen [--help]""")
sys.exit(-1)
}
println("Do some work here")
}
}
Making help a lazy val and calling conf.afterInit() before accessing conf.help should clear the compiler warnings.
I'd like to make a test for a method which calls error() in it.
IntEmptyStack.top is what I want to test with specs2:
abstract class IntStack {
def push(x: Int): IntStack = new IntNonEmptyStack(x, this)
def isEmpty: Boolean
def top: Int
def pop: IntStack
}
class IntEmptyStack extends IntStack {
def isEmpty = true
def top = error("EmptyStack.top")
def pop = error("EmptyStack.pop")
}
And here's the specs I wrote so far:
import org.junit.runner.RunWith
import org.specs2.runner.JUnitRunner
import org.specs2.mutable.Specification
#RunWith(classOf[JUnitRunner])
class IntStackSpec extends Specification {
"IntEmptyStack" should {
val s = new IntEmptyStack
"be empty" in {
s.isEmpty must equalTo(true)
}
"raise error when top called" in {
s.top must throwA[RuntimeException]
}
}
}
The error occurs in line 13, "raise error when top called" in {. The error message is value must is not a member of Nothing. I think Scala infers s.top as Nothing, not an Int as defined in the abstract class. In this case, how can I write a test without any errors?
Thanks for any comments/corrections to this question.
Example Reference: Scala By Example
The problem here is that scala (and Java) allow subclasses to return more-specific types than superclasses in overridden methods. In this case, your method IntEmptyStack.top's return-type is Nothing (which is a sub-type of Int because Nothing is at the bottom of the type hierarchy.
Evidently spec's implicit conversions necessary for you to write code like a must throwA[X] do not apply when the type of a is Nothing
Change your declarations in IntEmptyStackas follows:
def top: Int = error("EmptyStack.top")
def pop: Int = error("EmptyStack.pop")
Alternatively, of course, you could allow the fact that the correctness of your logic is being proven by the type system. That is, it is not possible to get an element which is at the top of an empty stack: the return type is Nothing! No tests are necessary.
I'm trying to mock a method call that takes a call-by-name argument:
import org.scalatest.WordSpec
import org.scalatest.mock.MockitoSugar
import org.mockito.Mockito._
import org.junit.runner.RunWith
import org.scalatest.junit.JUnitRunner
trait Collaborator {
def doSomething(t: => Thing)
}
trait Thing
#RunWith(classOf[JUnitRunner])
class Test extends WordSpec with MockitoSugar {
"The subject under test" should {
"call the collaborator" in {
// setup
val m = mock[Collaborator]
val t = mock[Thing]
// test code: this would actually be invoked by the SUT
m.doSomething(t)
// verify the call
verify(m).doSomething(t)
}
}
}
I'm primarily interested in Mockito since that's what I'm using, but I'd be interested to see whether any of the major mock frameworks is capable of this kind of testing. The Test fails at runtime on the verify line, with an error like
Argument(s) are different! Wanted:
collaborator.doSomething(
($anonfun$apply$3) <function>
);
-> at Test$$anonfun$1$$anonfun$apply$1.apply(Test.scala:27)
Actual invocation has different arguments:
collaborator.doSomething(
($anonfun$apply$2) <function>
);
-> at Test$$anonfun$1$$anonfun$apply$1.apply(Test.scala:24)
If I'm understanding the situation correctly, the compiler is implicitly wrapping t in a nullary function that returns t. The mock framework is then comparing that function to the one produced in the test code, which is equivalent but not equals().
My case is a relatively simple version of the problem, but I think this would be an issue with any higher-order function.
This looks ugly, but hopefully it can help you to find good solution:
import org.scalatest.mock.MockitoSugar
import org.mockito.Mockito._
trait Collaborator {
def doSomething(t: => Thing)
}
trait Thing
new MockitoSugar {
// setup
val m = mock[Collaborator]
val t = mock[Thing]
m.doSomething(t)
classOf[Collaborator].getMethod("doSomething", classOf[Function0[_]]).invoke(
verify(m),
new Function0[Thing] {
def apply() = null
override def equals(o: Any): Boolean = t == o.asInstanceOf[Function0[Thing]].apply()
})
}
You can try specs2. In specs2, we "hijack" the Mockito Invocation class to account for byname parameters:
trait ByName { def call(i: =>Int) = i }
val byname = mock[ByName]
byname.call(10)
there was one(byname).call(10)
This problem seems to be specific to by-name invocations because in regular higher order functions you can match against the explicit FunctionX object:
verify(collaborator).somethingElse(any(Function2[String, Thing]))
in the by-name case the wrapping of the argument into a Function0 is done implicitly, and Alexey's answer shows how to invoke the mock with an explicit parameter.
You could write something akin to your own verify which would apply arguments captured by mockito.
Mockito internally records invocation and their arguments with e.g.:
http://code.google.com/p/mockito/source/browse/trunk/src/org/mockito/internal/matchers/CapturingMatcher.java