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 IntEmptyStack
as 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.