Why is this specs2 test using Mockito passing? - scala

Suppose I had this interface and class:
abstract class SomeInterface{
def doSomething : Unit
}
class ClassBeingTested(interface : SomeInterface){
def doSomethingWithInterface : Unit = {
Unit
}
}
Note that the doSomethingWithInterface method does not actually do anything with the interface.
I create a test for it like this:
import org.specs2.mutable._
import org.specs2.mock._
import org.mockito.Matchers
import org.specs2.specification.Scope
trait TestEnvironment extends Scope with Mockito{
val interface = mock[SomeInterface]
val test = new ClassBeingTested(interface)
}
class ClassBeingTestedSpec extends Specification{
"The ClassBeingTested" should {
"#doSomethingWithInterface" in {
"calls the doSomething method of the given interface" in new TestEnvironment {
test.doSomethingWithInterface
there was one(interface).doSomething
}
}
}
}
This test passes. Why? Am I setting it up wrong?
When I get rid of the scope:
class ClassBeingTestedSpec extends Specification with Mockito{
"The ClassBeingTested" should {
"#doSomethingWithInterface" in {
"calls the doSomething method of the given interface" in {
val interface = mock[SomeInterface]
val test = new ClassBeingTested(interface)
test.doSomethingWithInterface
there was one(interface).doSomething
}
}
}
}
The test fails as expected:
[info] x calls the doSomething method of the given interface
[error] The mock was not called as expected:
[error] Wanted but not invoked:
[error] someInterface.doSomething();
What is the difference between these two tests? Why does the first one pass when it should fail? Is this not an intended use of Scopes?

When you mix-in the Mockito trait to another trait you can create expectations like there was one(interface).doSomething. If such an expression fails it only returns a Result, it doesn't throw an Exception. It then gets lost in a Scope because it is just a "pure" value inside the body of a trait.
However if you mix-in the Mockito trait to a mutable.Specification then an exception will be thrown on a failure. This is because the mutable.Specification class specifies that there should be ThrownExpectations by mixing in that trait.
So if you want to create a trait extending both Scope you can either:
create the trait from inside the specification and not have it extend Mockito:
class MySpec extends mutable.Specification with Mockito {
trait TestEnvironment extends Scope {
val interface = mock[SomeInterface]
val test = new ClassBeingTested(interface)
}
...
}
create trait and specification as you do, but mix-in org.specs2.execute.ThrownExpectations
trait TestEnvironment extends Scope with Mockito with ThrownExpectations {
val interface = mock[SomeInterface]
val test = new ClassBeingTested(interface)
}
class MySpec extends mutable.Specification with Mockito {
...
}

Related

How to mock return of None of method which return type is Option[SomeCaseClassDefinedInsideThisClass]

I would expect this test to pass:
import org.scalamock.scalatest.MockFactory
import org.scalatest.{FlatSpec, Matchers}
class FruitImpl {
case class FruitName(name: String)
def getFruitName: Option[FruitName] = {
Some(FruitName("apple"))
}
}
class FruitSpec extends FlatSpec with Matchers with MockFactory {
val f = mock[FruitImpl]
(f.getFruitName _).expects().returning(None)
behavior of "getFruitName method"
it should "return None" in {
f.getFruitName should === (None)
}
}
But it fails with:
[error] my/path/QuestionTest.scala:13: overriding method getFruitName in class FruitImpl of type => Option[this.FruitName];
[error] method getFruitName has incompatible type
[error] val f = mock[FruitImpl]
[error] ^
This works, though:
import org.scalamock.scalatest.MockFactory
import org.scalatest.{FlatSpec, Matchers}
case class FruitName(name: String)
class FruitImpl {
def getFruitName: Option[FruitName] = {
Some(FruitName("apple"))
}
}
class FruitSpec extends FlatSpec with Matchers with MockFactory {
val f = mock[FruitImpl]
(f.getFruitName _).expects().returning(None)
behavior of "getFruitName method"
it should "return None" in {
f.getFruitName should === (None)
}
}
The only difference is that the case class FruitName is defined outside of the class FruitImpl. Why does one version of the code fails and the other doesn't? What should one do to fix the error in the first example?
Without looking at the ScalaMock code, I'd say that the mock is not a true derivation of FruitImpl in the OO sense. Its purpose is to allow method interception, so it only deals with the facade. It follows then that the mock actually has no definition of the path dependent type FruitName, and so cannot work with a method signature that depends on it.
This is precisely why it does work when the FruitName definition is moved out of FruitImpl. It now exists independently of the mock, who's method signatures depending on it then work as expected.

Check what the method of mocked object receives

In my project, whenever a class produces some output, instead of doing println it calls OutputStore.write, which is a class and method I defined.
I am trying to test the output of another class so I mocked OutputStore. I want to see what parameters it receives to OutputStore.write.
val mockOutputStore = mock[OutputStore]
I would like to do something like this:
val argument = ArgumentCaptor.forClass(classOf[OutputStore])
verify(mockOutputStore).write(argument.capture())
assertEquals("some parameter", argument.getValue())
However, this doesn't compile as verify is not even recognized.
The signature of my test class is this:
class SomeUnitTestSet extends org.scalatest.FunSuite with MockitoSugar with PropertyChecks
Any idea how to check what parameters a mocked object's method receives?
Here is a translation of what #JBNizet suggested into a Scala code
Assuming you have your OutputStore class
class OutputStore {
def write(msg: String) = {
println(msg)
}
}
and some OutputStoreApiUser class
class OutputStoreApiUser(val outputStore: OutputStore) {
def foo(): Unit = {
outputStore.write("some parameter")
outputStore.write("some parameter2")
}
}
Then your test might be something like this (in real life you probably #Inject outputStore but this is not relevant here):
import org.mockito.Mockito.verify // static import!
import org.scalatest.mockito.MockitoSugar
import org.scalatest.prop.PropertyChecks
class SomeUnitTestSet extends org.scalatest.FunSuite with MockitoSugar with PropertyChecks {
test("Capture calls"){
val mockOutputStore = mock[OutputStore]
val apiUser = new OutputStoreApiUser(mockOutputStore)
apiUser.foo()
verify(mockOutputStore).write("some parameter")
verify(mockOutputStore).write("some parameter2")
}
}
This one compiles and works for me as I would expect

Unit testing trait with object

I have the following construct, where I have a
trait DataServiceLocalImpl extends DataService {
override lazy val dataService = DataComponentLocalImpl
}
object DataComponentLocalImpl extends DataComponent {
def getData(element:String):String = GetStuffFromFile(element)
}
trait DataService {
val dataService: DataComponent
}
trait DataComponent {
def getData(element:String):String
}
The GetStuffFromFile reads a file from disk once (I only want this once, hence the object), creates a map and then returns the value for element.
This is all done in an Play Framework 2.3 surrounding and the app works as well, but when I use it in a test as an implicit I get the following error:
java.lang.NoClassDefFoundError: Could not initialize class DataComponentLocalImpl
Test suite:
class AutoCompleteSpec extends PlaySpec with Mockito with OneAppPerSuite {
val resource = new DataServiceLocalImpl {}
implicit val dataService = resource.dataService
}
If I remove the implicit it works...
You should create an object with the service overriden.
object FakeImpl extends DataServiceLocalImpl {
override dataService = //Fake or test data service here
}
You then create an anonymous class definition that allows you to test the trait.

Using Akka TestKit with Specs2

I'm trying to craft a specs2 test using Akka's TestKit. I'm stuck on a persistent compile error I can't figure out how to resolve, and I'd appreciate suggestions.
The compile error is:
TaskSpec.scala:40: parents of traits may not have parameters
[error] with akka.testkit.TestKit( ActorSystem( "testsystem", ConfigFactory.parseString( TaskSpec.config ) ) )
Following suggestions from Akka docs and internet xebia and Akka in Action, I'm trying to incorporate the TestKit into a specs2 Scope. Here's a snippet of the code where I'm getting the error:
class TaskSpec
extends Specification
with AsyncTest
with NoTimeConversions {
sequential
trait scope
extends Scope
with TestKit( ActorSystem( "testsystem", ConfigFactory.parseString( TaskSpec.config ) ) )
with AkkaTestSupport {
...
I have the following helper:
trait AkkaTestSupport extends After { outer: TestKit =>
override protected def after: Unit = {
system.shutdown()
super.after
}
}
Here is one thing you can do:
import org.specs2.mutable.SpecificationLike
import org.specs2.specification._
class TestSpec extends Actors { isolated
"test1" >> ok
"test2" >> ok
}
abstract class Actors extends
TestKit(ActorSystem("testsystem", ConfigFactory.parseString(TaskSpec.config)))
with SpecificationLike with AfterExample {
override def map(fs: =>Fragments) = super.map(fs) ^ step(system.shutdown, global = true)
def after = system.shutdown
}
This should avoid the compilation error you had because TestKit is an abstract class and it is only mixing-in traits: SpecificationLike is a trait (Specification isn't) and AfterExample is a trait.
Also the specification above runs in the isolated mode, meaning that there is a brand new TestSpec object instantiated for each example and the AfterExample trait makes sure that the system is shutdown after each example.
Finally the map method is overriden with a special step to make sure that the system created for the first TestSpec instance (the one declaring all the examples) will be cleanly disposed of.

case class context in specs2 acceptance tests: "must is not a member of Int"

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)
}