Como fazer uma instância de verificação com Scala (Teste)

100

Estou tentando incorporar ScalaTest em meu projeto Java; substituindo todos os testes JUnit por ScalaTests. A certa altura, quero verificar se o injetor de Guice injeta o tipo correto. Em Java, tenho um teste como este:

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

Mas tenho um problema para fazer o mesmo com o 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)
        }
    }
}

Ele reclama que o valor instanceofnão é membro de Door/ Window/ Roof. Não posso usar instanceofassim no Scala?

método auxiliar
fonte

Respostas:

114

Scala não é Java. Scala simplesmente não tem o operador, em instanceofvez disso, tem um método paramétrico chamado isInstanceOf[Type].

Você também pode gostar de assistir a um curso intensivo do ScalaTest .

agilesteel
fonte
6
bem, isso realmente não responde à pergunta. ScalaTest tem suporte integrado para verificação de tipo. Veja a resposta de @ martin-g
maasg de
Como fazer se "Tipo" for uma característica?
Lobo
Não tenho certeza se eu entendi corretamente, mas deve ser o mesmo: isInstanceOf[TraitName].
agilesteel
88

Com o Scalatest 2.2.x (talvez até anterior), você pode usar:

anInstance mustBe a[SomeClass]
martin-g
fonte
4
Esta é a abordagem recomendada nas versões recentes do ScalaTests
maasg de
6
também disponível a[Type]para que você possa estar gramaticalmente correto;)
Samuel
Eu estava procurando por isso! :)
Atais
22
tiger shouldBe a [Tiger]é a sintaxe atual scalatest.org/at_a_glance/FlatSpec
jhegedus
2
@jhegedus mustBetambém está correto, se você usar doc.scalatest.org/3.0.1/#org.scalatest.MustMatchers que deseja para o FreeSpec.
Tobi
30

Se você quiser ser menos JUnit-esque e se quiser usar os matchers do ScalaTest, você pode escrever seu próprio matcher de propriedade que corresponda ao tipo (apagamento do tipo de barra).

Achei este tópico muito útil: http://groups.google.com/group/scalatest-users/browse_thread/thread/52b75133a5c70786/1440504527566dea?#1440504527566dea

Você pode escrever afirmações como:

house.door should be (anInstanceOf[WoodenDoor])

ao invés de

assert(house.door instanceof WoodenDoor)
Guillaume Belrose
fonte
+1 Isso parece muito bom, e até mesmo compreensível para pessoas que não são programadoras (assumindo que eles saibam o que é uma instância :-)).
método auxiliar de
Se sintaxe sugar é o que você procura, com alguma refatoração você pode escrever house.door deve ser (madeOf [Madeira]) ou house.door deve ser (madeOf [Bamboo]).
Guillaume Belrose
16

As respostas atuais sobre isInstanceOf [Type] e conselhos junit são boas, mas quero acrescentar uma coisa (para as pessoas que acessaram esta página por motivos não relacionados a junit). Em muitos casos, a correspondência de padrões do scala atenderá às suas necessidades. Eu recomendaria nesses casos porque dá a você o typecasting de graça e deixa menos espaço para erros.

Exemplo:

OuterType foo = blah
foo match {
  case subFoo : SubType => {
    subFoo.thingSubTypeDoes // no need to cast, use match variable
  }
  case subFoo => {
    // fallthrough code
  }
}
alexbobp
fonte
A maneira recomendada de testar uma correspondência de padrão no ScalaTest é usar em inside(foo)vez de `correspondência foo). Consulte scalatest.org/user_guide/using_matchers#matchingAPattern
Rich Dougherty
3

Consolidando a referência de discussão ScalaTest de Guillaume (e outra discussão vinculada a James Moore) em dois métodos, atualizados para ScalaTest 2.xe Scala 2.10 (para usar ClassTag em vez de manifesto):

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
fonte
2

Eu uso 2.11.8 para fazer a declaração com coleções. A sintaxe mais recente é a seguinte:

val scores: Map[String, Int] = Map("Alice" -> 10, "Bob" -> 3, "Cindy" -> 8)
scores shouldBe a[Map[_, _]] 
Aristotll
fonte
3
Devido ao apagamento, você não pode verificar os Mapparâmetros de tipo de. O que você escreveu é o mesmo que escrever scores shouldBe a[Map[_, _]]. Isso é mencionado aqui: scalatest.org/user_guide/using_matchers#checkingAnObjectsClass
Rich Dougherty