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.
Related
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
}
}
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
The following code does not compile:
import scala.language.implicitConversions
trait Base {
class Wrp[+T](val v: T) // wrapper / internal representation
}
trait BooleanOps extends Base {
// implicit conversion
implicit def lift2BooleanOpsCls(x: Boolean): BooleanOpsCls =
new BooleanOpsCls(new Wrp[Boolean](x))
class BooleanOpsCls(wx: Wrp[Boolean]) {
def ||(wy: =>Wrp[Boolean]): Wrp[Boolean] = new Wrp[Boolean](wx.v || wy.v)
}
}
trait MyExample extends BooleanOps {
// test method
def foo(): Wrp[Boolean] = {
val ret: Wrp[Boolean] = false || new Wrp[Boolean](true)
ret
}
}
Output:
MyExample.scala:18: error: type mismatch;
found : MyExample.this.Wrp[Boolean]
required: Boolean
val ret: Wrp[Boolean] = false || new Wrp[Boolean](true)
^
But if I:
1) put the class Wrp outside of Base
or
2) move the body of BooleanOps to MyExample
everything compiles.
Why does not the original example work? If you have some insight in this behavior, help would be appreciated. Thank you.
One issue is the call-by-name nature of the argument in the def ||(wy: =>Wrp[Boolean])
if you rewite it to def ||(wy: Wrp[Boolean]) it works
but I agree that it is weird that it works if you move around Wrp or BooleanOpsCls! Intended or bug of implicit resolution??
The original example will work if you rename the || method. The compiler finds the false.||() method and doesn't bother to look for an implicit that might also work there.
The problem is that there is no single class called Wrp (ignore the T for a moment) -- Base does not define Wrp but rather defines a named subclass of each and every concrete class that extends Base. The implicits are a red herring, too. The error that's the giveaway is the mention of MyExample.this.Wrp -- remember that there is no such class even as MyExample -- val x = new MyExample would have type Object with MyExample.
I am working in ScalaFX Project. In this moment I am adapting classes from javafx.scene.control.cell. In this package, methods with same signature are duplicated in many classes. e.g. StringConverter<T> converter(). To avoid unnecessary duplication of code (and to know how to use existential types), I created the following code:
// Defined in scalafx.util package. All classes in scalafx use this trait
package scalafx.util
trait SFXDelegate[+D <: Object] extends AnyRef {
def delegate: D
override def toString = "[SFX]" + delegate.toString
override def equals(ref: Any): Boolean = {
ref match {
case sfxd: SFXDelegate[_] => delegate.equals(sfxd.delegate)
case _ => delegate.equals(ref)
}
}
override def hashCode = delegate.hashCode
}
// Package Object
package scalafx.scene.control
import javafx.{ util => jfxu }
import javafx.beans.{ property => jfxbp }
import javafx.scene.{ control => jfxsc }
import scalafx.Includes._
import scalafx.beans.property.ObjectProperty
import scalafx.util.SFXDelegate
import scalafx.util.StringConverter
package object cell {
type Convertable[T] = {
def converterProperty: jfxbp.ObjectProperty[jfxu.StringConverter[T]]
}
type JfxConvertableCell[T] = jfxsc.Cell[T] with Convertable[T]
trait ConvertableCell[C <: JfxConvertableCell[T], T]
extends SFXDelegate[C] {
def converter: ObjectProperty[StringConverter[T]] = ObjectProperty(delegate.converterProperty.getValue)
def converter_=(v: StringConverter[T]) {
converter() = v
}
}
}
In JfxConvertableCell type I wanna say
My type is a javafx.scene.control.Cell of type T that has a method called converterProperty that returns a javafx.beans.property.ObjectProperty of type javafx.util.StringConverter[T].
While in ConvertableCell trait, my intention is say that delegate value (from SFXDelegate trait) must be of type JfxConvertableCell. The first class that I tried to create was the counter-part of CheckBoxListCell:
package scalafx.scene.control.cell
import javafx.scene.control.{cell => jfxscc}
import scalafx.scene.control.ListCell
import scalafx.util.SFXDelegate
class CheckBoxListCell[T](override val delegate: jfxscc.CheckBoxListCell[T] = new jfxscc.CheckBoxListCell[T])
extends ListCell[T](delegate)
with ConvertableCell[jfxscc.CheckBoxListCell[T], T]
with SFXDelegate[jfxscc.CheckBoxListCell[T]] {
}
However in this moment I got this message from compiler:
type arguments [javafx.scene.control.cell.CheckBoxListCell[T],T] do not conform to trait ConvertableCell's type parameter bounds [C <: scalafx.scene.control.cell.package.JfxConvertableCell[T],T]
Did I understand something wrong? CheckBoxListCell have the converterProperty method. Can't we use types and existential types as a mold into which we fit our delegated classes?
The problem is in your definition of converterProperty. You define it as a parameterless method, while it is seen by scala as a method with an empty parameter list.
Just doing this makes it compile properly:
type Convertable[T] = {
def converterProperty(): jfxbp.ObjectProperty[jfxu.StringConverter[T]]
}
While scala treats a parameterless method and a method with an empty parameter list as essentially the same thing as far as overriding is concerned (see scala spec # 5.1.4), they are still different entites.
And when interroperating with java code (which has no notion of parameterless method), a nullary method is seen as a method with an empty prameter list, not as a parameterless method, thus the structural types don't match.
Consider the following typical Scala 'pimp' code:
class PimpedA(a:A){
def pimp() = "hi"
}
implicit def pimpA(a:A) = new PimpedA(a)
new A(){
pimp() //<--- does not compile
}
However, changing it to:
new A(){
this.pimp()
}
Makes it work.
Shouldn't it be the same to the Scala compiler?
EDIT : Is there any solution that can make it work without having to add the this.?
Not at all. For it to work, pimp needs to be either an object or an imported member of a value, and it is neither. A class has an "implicit" import this._. It has not a mechanism that auto-prepends this to stuff to see if it compiles.
In this case you should give compiler a hint that pimp() is not a random function. When you write
this.pimp()
compiler know there isn't pimp function on class A so it's an error and before giving up it searches implicit conversion in scope and finds it.
pimpA(this).pimp()
And when you just call pimp() compiler doesn't know what object to pass to the pimpA(a: A) implicit function.
UPDATE
It is hard to understand what is your goal. I can only suggest to make PimpedA a typeclass (Pimp[T] in this example).
trait Pimp[T] {
def action(p: T): String
}
implicit object PimpA extends Pimp[A] {
override def action(p: A) = "some actions related to A"
}
def pimp[T: Pimp](p: T) = implicitly[Pimp[T]].action(p)
class A {
val foo = pimp(this)
}
scala> new A foo
res2: String = some actions related to A