Bagaimana melakukan pemeriksaan instanceof dengan Scala (Test)

100

Saya mencoba untuk memasukkan ScalaTest ke dalam proyek Java saya; mengganti semua pengujian JUnit dengan ScalaTests. Pada satu titik, saya ingin memeriksa apakah Injector Guice menyuntikkan tipe yang benar. Di Java, saya punya tes seperti ini:

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

Tapi saya punya masalah melakukan hal yang sama dengan 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)
        }
    }
}

Ia mengeluh bahwa nilainya instanceofbukan anggota Door/ Window/ Roof. Tidak bisakah saya menggunakan instanceofcara itu di Scala?

metode pembantu
sumber

Jawaban:

114

Scala bukanlah Java. Scala tidak memiliki operator instanceofmelainkan memiliki metode parametrik yang dipanggil isInstanceOf[Type].

Anda mungkin juga menikmati menonton ScalaTest Crash Course .

agilesteel
sumber
6
yah, itu tidak benar-benar menjawab pertanyaan itu. ScalaTest memiliki dukungan bawaan untuk pemeriksaan tipe. Lihat jawaban dari @ martin-g
maasg
Bagaimana melakukannya jika "Jenis" itu sifat?
Lobo
Tidak yakin apakah saya mengerti benar, tetapi harus sama: isInstanceOf[TraitName].
agilesteel
88

Dengan Scalatest 2.2.x (bahkan mungkin lebih awal) Anda dapat menggunakan:

anInstance mustBe a[SomeClass]
martin-g
sumber
4
Ini adalah pendekatan yang direkomendasikan pada versi terbaru ScalaTests
maasg
6
juga tersedia a[Type]sehingga Anda dapat secara tata bahasa benar;)
Samuel
Saya sedang mencari itu! :)
Atais
22
tiger shouldBe a [Tiger]adalah sintaks saat ini scalatest.org/at_a_glance/FlatSpec
jhegedus
2
@jhegedus mustBejuga benar, jika Anda menggunakan doc.scalatest.org/3.0.1/#org.scalatest.MustMatchers yang Anda inginkan untuk FreeSpec.
Tobi
30

Jika Anda ingin mengurangi JUnit-esque dan jika Anda ingin menggunakan matcher ScalaTest, Anda dapat menulis matcher properti Anda sendiri yang cocok dengan tipe (penghapusan tipe batang).

Saya menemukan utas ini cukup berguna: http://groups.google.com/group/scalatest-users/browse_thread/thread/52b75133a5c70786/1440504527566dea?#1440504527566dea

Anda kemudian dapat menulis pernyataan seperti:

house.door should be (anInstanceOf[WoodenDoor])

dari pada

assert(house.door instanceof WoodenDoor)
Guillaume Belrose
sumber
+1 Kelihatannya sangat bagus, dan bahkan dapat dimengerti oleh orang-orang yang bukan pemrogram (dengan asumsi mereka tahu apa itu contoh :-)).
helpermethod
Jika sintaks gula adalah apa yang Anda cari, dengan beberapa refactoring Anda mungkin bisa menulis house.door harus (dibuat dari [kayu]) atau rumah. pintu harus (dibuat dari [bambu]).
Guillaume Belrose
16

Jawaban terkini tentang isInstanceOf [Type] dan saran junit bagus, tetapi saya ingin menambahkan satu hal (untuk orang yang membuka halaman ini dalam kapasitas yang tidak terkait dengan junit). Dalam banyak kasus, pencocokan pola skala akan sesuai dengan kebutuhan Anda. Saya akan merekomendasikannya dalam kasus tersebut karena memberi Anda typecasting secara gratis dan menyisakan sedikit ruang untuk kesalahan.

Contoh:

OuterType foo = blah
foo match {
  case subFoo : SubType => {
    subFoo.thingSubTypeDoes // no need to cast, use match variable
  }
  case subFoo => {
    // fallthrough code
  }
}
alexbobp.dll
sumber
Cara yang disarankan untuk menguji kecocokan pola di ScalaTest adalah dengan menggunakan inside(foo)`foo match). Lihat scalatest.org/user_guide/using_matchers#matchingAPattern
Rich Dougherty
3

Konsolidasi referensi diskusi ScalaTest Guillaume (dan diskusi lain yang ditautkan oleh James Moore) ke dalam dua metode, diperbarui untuk ScalaTest 2.x dan Scala 2.10 (untuk menggunakan ClassTag daripada manifes):

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
  )
}
Raman
sumber
2

Saya menggunakan 2.11.8 untuk melakukan penegasan dengan koleksi. Sintaks yang lebih baru adalah sebagai berikut:

val scores: Map[String, Int] = Map("Alice" -> 10, "Bob" -> 3, "Cindy" -> 8)
scores shouldBe a[Map[_, _]] 
aristotll
sumber
3
Karena penghapusan Anda tidak dapat memeriksa Mapparameter tipe. Apa yang Anda tulis sama dengan menulis scores shouldBe a[Map[_, _]]. Ini disebutkan di sini: scalatest.org/user_guide/using_matchers#checkingAnObjectsClass
Rich Dougherty