Question

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?

Était-ce utile?

La solution

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:

  1. 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)
      }
      ...
    }
    
  2. 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 {
      ...
    }
    
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top