Comment faire une instance de vérification avec Scala (test)

100

J'essaye d'incorporer ScalaTest dans mon projet Java; remplacer tous les tests JUnit par des ScalaTests. À un moment donné, je veux vérifier si l'injecteur de Guice injecte le bon type. En Java, j'ai un test comme celui-ci:

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

Mais j'ai un problème à faire de même avec 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)
        }
    }
}

Il se plaint que la valeur instanceofn'est pas membre de Door/ Window/ Roof. Puis-je utiliser instanceofcette méthode dans Scala?

méthode d'aide
la source

Réponses:

114

Scala n'est pas Java. Scala n'a tout simplement pas l'opérateur à la instanceofplace, il a une méthode paramétrique appelée isInstanceOf[Type].

Vous pourriez également apprécier de regarder un cours intensif ScalaTest .

agilesteel
la source
6
eh bien, cela ne répond pas vraiment à la question. ScalaTest a un support intégré pour la vérification de type. Voir la réponse de @ martin-g
maasg
Comment faire si "Type" c'est un trait?
Lobo
Je ne sais pas si je comprends bien, mais il devrait être le même: isInstanceOf[TraitName].
agilesteel
88

Avec Scalatest 2.2.x (peut-être même plus tôt), vous pouvez utiliser:

anInstance mustBe a[SomeClass]
martin-g
la source
4
C'est l'approche recommandée sur les versions récentes de ScalaTests
maasg le
6
également disponible a[Type]pour que vous puissiez être grammaticalement correct;)
Samuel
Je cherchais ça! :)
Atais le
22
tiger shouldBe a [Tiger]est la syntaxe actuelle scalatest.org/at_a_glance/FlatSpec
jhegedus
2
@jhegedus mustBeest également correct, si vous utilisez doc.scalatest.org/3.0.1/#org.scalatest.MustMatchers que vous voulez pour FreeSpec.
Tobi
30

Si vous voulez être moins JUnit-esque et si vous voulez utiliser les matchers de ScalaTest, vous pouvez écrire votre propre correspondance de propriété qui correspond au type (effacement du type de barre).

J'ai trouvé ce fil assez utile: http://groups.google.com/group/scalatest-users/browse_thread/thread/52b75133a5c70786/1440504527566dea?#1440504527566dea

Vous pouvez ensuite écrire des assertions comme:

house.door should be (anInstanceOf[WoodenDoor])

au lieu de

assert(house.door instanceof WoodenDoor)
Guillaume Belrose
la source
+1 Cela a l'air très agréable, et même compréhensible pour les non-programmeurs (en supposant qu'ils savent ce qu'est une instance :-)).
helpermethod
Si le sucre de syntaxe est ce que vous recherchez, avec un peu de refactorisation, vous pourrez peut-être écrire que house.door devrait être (madeOf [Wood]) ou house.door devrait être (madeOf [Bamboo]).
Guillaume Belrose
16

Les réponses actuelles à propos de isInstanceOf [Type] et des conseils junit sont bonnes, mais je veux ajouter une chose (pour les personnes qui sont arrivées sur cette page dans une capacité non liée à junit). Dans de nombreux cas, la correspondance de motifs scala répondra à vos besoins. Je le recommanderais dans ces cas, car il vous donne le typage gratuitement et laisse moins de place à l'erreur.

Exemple:

OuterType foo = blah
foo match {
  case subFoo : SubType => {
    subFoo.thingSubTypeDoes // no need to cast, use match variable
  }
  case subFoo => {
    // fallthrough code
  }
}
alexbobp
la source
La méthode recommandée pour tester une correspondance de modèle dans ScalaTest est d'utiliser à la inside(foo)place de `foo match). Voir scalatest.org/user_guide/using_matchers#matchingAPattern
Rich Dougherty
3

Consolidation de la référence de discussion ScalaTest de Guillaume (et d'une autre discussion liée à par James Moore) en deux méthodes, mises à jour pour ScalaTest 2.x et Scala 2.10 (pour utiliser ClassTag plutôt que 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
  )
}
Raman
la source
2

J'utilise 2.11.8 pour faire l'assertion avec des collections. La nouvelle syntaxe est la suivante:

val scores: Map[String, Int] = Map("Alice" -> 10, "Bob" -> 3, "Cindy" -> 8)
scores shouldBe a[Map[_, _]] 
aristotll
la source
3
En raison de l'effacement, vous ne pouvez pas vérifier les Mapparamètres de type de. Ce que vous avez écrit équivaut à écrire scores shouldBe a[Map[_, _]]. Ceci est mentionné ici: scalatest.org/user_guide/using_matchers#checkingAnObjectsClass
Rich Dougherty