Ir al contenido principal
Versión: 5.9.x

Fábricas de Pruebas

[Traducción Beta No Oficial]

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

En ocasiones podemos querer escribir un conjunto de pruebas genéricas para reutilizarlas con entradas específicas. En Kotest logramos esto mediante fábricas de pruebas que crean tests que pueden incluirse en una o más especificaciones.

Visión General

Imaginemos que queremos construir nuestra propia biblioteca de colecciones. Un ejemplo algo trivial, pero que sirve bien al propósito de la documentación.

Podríamos crear una interfaz IndexedSeq con dos implementaciones: List y Vector.

interface IndexedSeq<T> {

// returns the size of t
fun size(): Int

// returns a new seq with t added
fun add(t: T): IndexedSeq<T>

// returns true if this seq contains t
fun contains(t: T): Boolean
}

Si quisiéramos probar nuestra implementación de List, podríamos hacerlo así:

class ListTest : WordSpec({

val empty = List<Int>()

"List" should {
"increase size as elements are added" {
empty.size() shouldBe 0
val plus1 = empty.add(1)
plus1.size() shouldBe 1
val plus2 = plus1.add(2)
plus2.size() shouldBe 2
}
"contain an element after it is added" {
empty.contains(1) shouldBe false
empty.add(1).contains(1) shouldBe true
empty.add(1).contains(2) shouldBe false
}
}
})

Ahora, para probar Vector tendríamos que copiar y pegar las pruebas. Al añadir más implementaciones y más pruebas, es probable que nuestro conjunto de pruebas se fragmente y desincronice.

Podemos resolver esto creando una fábrica de pruebas que acepte un IndexedSeq como parámetro.

Para crear una fábrica de pruebas, usamos funciones de construcción como funSpec, wordSpec, etc. Existe una función para cada estilo de especificación.

Para convertir nuestras pruebas anteriores en una fábrica, simplemente hacemos lo siguiente:

fun <T> indexedSeqTests(name: String, empty: IndexedSeq<T>) = wordSpec {
name should {
"increase size as elements are added" {
empty.size() shouldBe 0
val plus1 = empty.add(1)
plus1.size() shouldBe 1
val plus2 = plus1.add(2)
plus2.size() shouldBe 2
}
"contain an element after it is added" {
empty.contains(1) shouldBe false
empty.add(1).contains(1) shouldBe true
empty.add(1).contains(2) shouldBe false
}
}
}

Para utilizarla, debemos incluirla una o más veces en una especificación (o varias especificaciones).

class IndexedSeqTestSuite : WordSpec({
include(indexedSeqTests("vector"), Vector())
include(indexedSeqTests("list"), List())
})
consejo

Puedes incluir fábricas de cualquier estilo en cualquier tipo de especificación. Por ejemplo, una fábrica fun spec puede incluirse en una clase string spec.

Una clase de prueba puede incluir varios tipos de fábricas, además de pruebas normales en línea. Por ejemplo:

class HugeTestFile : FunSpec({

test("first test") {
// test here
}

include(factory1("foo"))
include(factory2(1, 4))

test("another test") {
// testhere
}
})

Cada prueba incluida aparece en los resultados como si se hubiera definido individualmente.

nota

Las pruebas de las fábricas se incluyen en el orden definido en la clase de especificación.

nota

include solo se admite en el nivel superior de una especificación

Escuchadores

Las fábricas de pruebas soportan los callbacks habituales before/after test. Cualquier callback añadido a una fábrica se agregará a las especificaciones donde se incluya.

Sin embargo, solo se aplicarán a las pruebas generadas por esa fábrica. Esto permite crear fábricas independientes con sus propios métodos de ciclo de vida, garantizando que no entren en conflicto con otros.

Por ejemplo:

val factory1 = funSpec {
beforeTest {
println("Executing $it")
}
test("a") { }
test("b") { }
}
class LifecycleExample : FunSpec({
include(factory1)
test("c")
test("d")
})

Tras ejecutar el conjunto de pruebas, se imprimiría:

Executing a
Executing b

Como puedes ver, el bloque beforeTest añadido a factory1 solo aplica a las pruebas de esa fábrica, no a las definidas en la especificación que la contiene.