I have a case class which is a simple wrapper around a collection:
final case class Foo(foos: Seq[Int])
and in my tests, I'd like to make assertions about the emptiness and lone elements of Foo#foos. I'm currently circumventing the problem by accessing Foo#foos directly:
foo.foos shouldBe empty
or
foo.foos.loneElement should===(1)
This works, but breaks encapsulation.
I've looked through the scalatest docs, but haven't found a way to define these operators outside of a companion.
How can I define them? Bonus points for inlining them in the tests.
Define some implicits to deal with Foo (in the test-directory, not in the main source code tree):
import org.scalatest.enablers.Emptiness
trait FooImplicits {
case class FooLoneElementWrapper(wrapped: Foo) {
def loneElement: Int = {
assert(wrapped.foos.size == 1)
wrapped.foos(0)
}
}
implicit def fooCanHazLoneElement(foo: Foo) = FooLoneElementWrapper(foo)
implicit object FooEmptiness extends Emptiness[Foo] {
def isEmpty(foo: Foo) = foo.foos.isEmpty
}
}
Now simply mixin the trait FooImplicits into the FlatSpec where you would like to use it:
import org.scalatest._
class FooSpec extends FlatSpec with Matchers with FooImplicits {
"Foo" should "be empty when it's empty" in {
Foo(Seq()) shouldBe empty
}
it should "have loneElements" in {
val x = Foo(Seq(1))
x.loneElement should equal (1)
}
}
Profit:
[info] Foo
[info] - should be empty when it's empty
[info] - should have loneElements
Notice that the FooImplicits can be defined in the same package as Foo in the main tree, even though it is in a completely different test-source-code tree. This way, it can access package-visible members of Foo.
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
}
}
Gen.sequence seems to be ignoring size of given Traversable. Is that by design? I'm using version 1.14.0 with Scala 2.13. Following generator
Gen.sequence[List[Int], Int](List.fill(3)(Gen.const(5)))
sometimes generates List of size 1. What am I missing ?
Sample test
import org.scalacheck.Gen
import org.scalatest.concurrent.ScalaFutures
import org.scalatest.{Assertions, FlatSpec, Inside, Inspectors, Matchers, OptionValues}
import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
class RuleSpec extends FlatSpec with Matchers with Assertions with OptionValues with Inside with Inspectors with ScalaFutures with ScalaCheckPropertyChecks {
val filterGen = Gen.listOfN(3, Gen.const(5))
val inputGen = Gen.pick(10, 5 to 15).map(_.toList).filter(_.nonEmpty)
"A HasAny rule with partially matching filter" should "validate input" in {
forAll(filterGen, inputGen) { case (filter, input) =>
val result = HasAny(filter: _*).valid(input)
println(s"$result: $filter ${input}\n")
result should be(true)
}
}
}
This might be due to Test Case Minimisation
One interesting feature of ScalaCheck is that if it finds an argument
that falsifies a property, it tries to minimise that argument before
it is reported. This is done automatically when you use the
Prop.property and Prop.forAll methods to create properties, but not if
you use Prop.forAllNoShrink.
Hence try using Prop.forAllNoShrink like so
Prop.forAllNoShrink(filterGen, inputGen) { case (filter, input) => ...
If using ScalaTest's forAll then try the suggestion in Add support for not shrinking values in GeneratorDrivenPropertyChecks #584 by creating the following trait
trait NoShrink {
implicit def noShrink[A]: Shrink[A] = Shrink(_ => Stream.empty)
}
and mix it in the spec like so
class RuleSpec extends FlatSpec ... with ScalaCheckPropertyChecks with NoShrink {
...
forAll(filterGen, inputGen) { case (filter, input) => ...
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'm trying to define a reusable trait that expects a value to be in an outer scope. I can define the trait inside the outer scope and it will work, but won't be reusable. When I move the trait to a separate scope, the trait can't access the value and I haven't found a way to declare it as present in the outer scope of the type the trait is being mixed in to.
The closest I have got so far is this:
import javafx.beans.property.ObjectProperty
import akka.actor.{Props, ActorSystem}
import javafx.event.EventHandler
import javafx.stage.{WindowEvent => JWindowEvent}
import scalafx.application.{Platform, JFXApp}
import scalafx.scene.Scene
import scalafx.scene.canvas.Canvas
import scalafx.scene.paint.Color
object MicroServicesApp extends JFXApp {
implicit val system = ActorSystem("system")
val canvas = new Canvas {
width = 1200
height = 900
}
stage = new MicroServicesPrimaryStage with AutomaticMicroServicesWindowCloser {
title.value = "Map Viewer"
scene = new Scene {
fill = Color.LightGreen
content = canvas
}
}
}
class MicroServicesPrimaryStage(implicit val actorSystem: ActorSystem) extends JFXApp.PrimaryStage with MicroServices {
}
/**
* A class enabled with a micro-services actor system.
*/
trait MicroServices {
def actorSystem: ActorSystem
}
/**
* An automatic window closer for a ScalaFX and Akka micro-services application.
*
* When this trait is mixed in to a class with the MicroServices trait and the onCloseRequest property,
* the onCloseRequest property will be initialized with a useful default event handler that shuts down
* the Akka actor system as well as the ScalaFX platform.
*/
trait AutomaticMicroServicesWindowCloser extends MicroServicesWindowCloser {
def onCloseRequest: ObjectProperty[EventHandler[JWindowEvent]]
def onCloseRequest_=(handler: EventHandler[JWindowEvent]): Unit
onCloseRequest = closeRequest()
}
/**
* A window closer for a ScalaFX and Akka micro-services application.
*/
trait MicroServicesWindowCloser extends MicroServices {
def closeRequest(): EventHandler[JWindowEvent] = new EventHandler[JWindowEvent] {
override def handle(e: JWindowEvent)
{
println("... closing application.")
actorSystem.shutdown()
Platform.exit()
}
}
}
It gets pretty close to what I'm after, the only give-away is the need for the client code to declare the value in the outer scope to be implicit. Ideally I would like the client code to mix-in the trait without changing anything else.
In the example I can use 'system' from within 'MicroServicesPrimaryStage', but not from within the mixed-in trait. I think this is because 'system' is in scope but not considered to be defined as a member of 'MicroServicesPrimaryStage'.
I could create an alias for 'system' with a val or a def and make it work that way, but that also means an extra step in modifying the client code. It would be nice if the trait could require a definition for 'system' and be able to find it in the outer scope at the point where the trait is mixed-in.
Is this possible?
Edit 1
These two println statements illustrate the cause of my confusion:
stage = new MicroServicesPrimaryStage with AutomaticMicroServicesWindowCloser {
println(s"val system is accessible from outer scope: $system ...") // compiles
println(s"... but is not mixed-in to MicroServicesPrimaryStage as ${this.system}.") // does not compile
...
I don't think the cake pattern can solve this on its own, because the question is about how the type system interacts with definitions in outer scopes.
Edit 2
SBT file for use with Java 8:
name := "workspace-sbt"
version := "1.0"
scalaVersion := "2.11.4"
resolvers += Opts.resolver.sonatypeSnapshots
libraryDependencies ++= Seq("org.scalatest" % "scalatest_2.11" % "2.2.1" % "test",
"org.scalafx" %% "scalafx" % "8.0.20-R7-SNAPSHOT",
"com.typesafe.akka" %% "akka-actor" % "2.3.7")
You are mistaken:
"In the example I can use 'system' from within 'MicroServicesPrimaryStage', but not from within the mixed-in trait. I think this is because 'system' is in scope but not considered to be defined as a member of 'MicroServicesPrimaryStage'."
This is not true. You can certainly use super class members as definitions for abstract members of mixed in traits. Consider this:
trait Foo {
def foo: String
def printFoo = println(foo)
}
class FooBar(val foo)
object FooBar {
def main(argv: Array[String]) = new FooBar("foo") with Foo printFoo
}
This compiles and will print "foo" if run. Is it not what you are trying to do?
Maybe that's what you're looking for:
scala> abstract class Aaaa(implicit val a: Int)
defined class Aaaa
scala> class Kkk extends Aaaa
<console>:9: error: could not find implicit value for parameter a: Int
class Kkk extends Aaaa
^
scala> implicit val a = 5
a: Int = 5
scala> class Kkk extends Aaaa
defined class Kkk
scala> new Kkk
res12: Kkk = Kkk#1a79ef3
scala> res12.a
res13: Int = 5
Let's imagine, that Int is an ActorSystem)
This value will be accessible from both Kkk and Aaaa. But implicit value should be defined in the scope, where you actually mixin Aaaa.
Sorry if I, too, am missing something.
This is just the classic charlotte cake pattern.
Or, maybe you're asking for a fruit cake, with an extra surprise in the next layer. (Maybe a King's cake is a better metaphor.)
package cakesample
// something useful
trait Something {
def thing: String
}
// a trait requiring something
trait Needy { _: Something =>
def theThingIs: String = thing
}
// another trait that uses something
trait User { _: Something =>
def use: String = thing * 2
}
// fruit cake fixings
case class Widget(w: String)
trait WidgetFramework {
// used by the framework
def widget: Widget
trait WidgetCog {
def run() = Console println s"Running ${widget.w}"
}
}
// sample usage
object Test extends App with Something with Needy with User with WidgetFramework {
// normal cake, a charlotte
def thing = "hello, world"
Console println s"$theThingIs: $use"
// a fruit cake
// define a widget
val widget = Widget("my widget")
// to be used by an object implementing a trait
object client extends WidgetCog
client.run()
}
I don't know why it should be yellow, except yellow is funnier than pound in this context. (Update: charlotte is more technically correct; but in the spirit of the season, a fruit cake is maybe what you're after.)
I'm using specs2 (v1.8.2) on with Scala (v2.9.1) to write acceptance tests. Following the example at http://etorreborre.github.com/specs2/guide/org.specs2.guide.SpecStructure.html#Contexts, I have the following Specification and context case class:
import org.specs2._
class testspec extends SpecificationWithJUnit { def is =
"test should" ^
"run a test in a context" ! context().e1
}
case class context() {
def e1 = 1 must beEqualTo(1)
}
I get a compiler error:
error: value must is not a member of Int def e1 = 1 must beEqualTo(1)
when compiling the context case class.
Obviously I'm new to specs2 (and to Scala). References to the appropriate documentation would be greatly appreciated.
Obviously the doc is wrong (was wrong, I fixed it now).
The correct way to write declare the case class for a context is usually to include it in the Specification scope:
import org.specs2._
class ContextSpec extends Specification { def is =
"this is the first example" ! context().e1
case class context() {
def e1 = List(1,2,3) must have size(3)
}
}
Otherwise if you want to reuse the context in another specification, you can, as Dario wrote, access the MustMatchers functionalities either by importing the MustMatchers object methods or by inheriting the MustMatchers trait.
must is not a member of Int, because to "must" is not known in the context of your "context" class. Put the method "e1" inside your specification class and it should work. E.g.
import org.specs2._
class TestSpec extends Specification { def is =
"test should" ^
"run a test in a context" ! e1 ^
end
def e1 = 1 must beEqualTo(1)
}
edit
Ah, I see what you want ;-). This should work like this:
To have the matchers in the scope of the context class you have to import the MustMatchers.
import org.specs2._
import matcher.MustMatchers._
class ContextSpec extends Specification { def is =
"this is the first example" ! context().e1
}
case class context() {
def e1 = List(1,2,3) must have size(3)
}