如何用 Scala (测试)执行 instanceof 检查

我试图将 ScalaTest 合并到我的 Java 项目中; 用 ScalaTest 替换所有的 JUnit 测试。在某一点上,我想检查 Guice 的 Injector 是否注入了正确的类型。在 Java 中,我有一个这样的测试:

public class InjectorBehaviour {
@Test
public void shouldInjectCorrectTypes() {
Injector injector = Guice.createInjector(new ModuleImpl());
House house = injector.getInstance(House.class);


assertTrue(house.door() instanceof WoodenDoor);
assertTrue(house.window() instanceof BambooWindow);
assertTrue(house.roof() instanceof SlateRoof);
}
}

但是我在使用 ScalaTest 时遇到了同样的问题:

class InjectorSpec extends Spec {
describe("An injector") {
it("should inject the correct types") {
val injector = Guice.createInjector(new ModuleImpl)
val house = injector.getInstance(classOf[House])


assert(house.door instanceof WoodenDoor)
assert(house.window instanceof BambooWindow)
assert(house.roof instanceof SlateRoof)
}
}
}

它抱怨值 instanceof不是 Door/Window/Roof的成员。我不能在 Scala 中这样使用 instanceof吗?

86091 次浏览

Scala 不是 Java.Scala 只是没有操作符 instanceof,而是有一个称为 isInstanceOf[Type]的参数方法。

你可能也喜欢看 ScalaTest Crash Course

如果您想要更少的 JUnit 风格,并且如果您想要使用 ScalaTest 的匹配器,您可以编写自己的属性匹配器来匹配类型(条形类型擦除)。

我发现这个线程非常有用: http://groups.google.com/group/scalatest-users/browse_thread/thread/52b75133a5c70786/1440504527566dea?#1440504527566dea

然后您可以编写如下断言:

house.door should be (anInstanceOf[WoodenDoor])

而不是

assert(house.door instanceof WoodenDoor)

The current answers about isInstanceOf[Type] and junit advice are good but I want to add one thing (for people who got to this page in a non-junit-related capacity). In many cases scala pattern matching will suit your needs. I would recommend it in those cases because it gives you the typecasting for free and leaves less room for error.

例如:

OuterType foo = blah
foo match {
case subFoo : SubType => {
subFoo.thingSubTypeDoes // no need to cast, use match variable
}
case subFoo => {
// fallthrough code
}
}

将 Guillaume 的 ScalaTest 讨论引用(以及 James Moore 链接到的另一个讨论)合并为两个方法,为 ScalaTest 2.x 和 Scala 2.10更新(使用 ClassTag 而不是 manifest) :

import org.scalatest.matchers._
import scala.reflect._


def ofType[T:ClassTag] = BeMatcher { obj: Any =>
val cls = classTag[T].runtimeClass
MatchResult(
obj.getClass == cls,
obj.toString + " was not an instance of " + cls.toString,
obj.toString + " was an instance of " + cls.toString
)
}


def anInstanceOf[T:ClassTag] = BeMatcher { obj: Any =>
val cls = classTag[T].runtimeClass
MatchResult(
cls.isAssignableFrom(obj.getClass),
obj.getClass.toString + " was not assignable from " + cls.toString,
obj.getClass.toString + " was assignable from " + cls.toString
)
}

使用 Scalatest 2.2.x (可能更早) ,你可以使用:

anInstance mustBe a[SomeClass]

我使用2.11.8对集合进行断言:

val scores: Map[String, Int] = Map("Alice" -> 10, "Bob" -> 3, "Cindy" -> 8)
scores shouldBe a[Map[_, _]]