Ir al contenido principal
Versión: 5.4.x

Ganchos del ciclo de vida

[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 →

Es muy común en las pruebas querer realizar alguna acción antes y después de un test, o antes y después de todos los tests en el mismo archivo. Es en estos ganchos del ciclo de vida donde se ejecutaría cualquier lógica de configuración/desmontaje necesaria para una prueba.

Kotest ofrece una amplia variedad de ganchos que pueden definirse directamente dentro de un spec. Para casos más avanzados, como crear plugins distribuibles o ganchos reutilizables, se pueden usar extensiones.

Al final de esta sección se incluye un listado de los ganchos disponibles y cuándo se ejecutan.

Existen varias formas de utilizar ganchos en Kotest:

Métodos DSL

La primera y más sencilla es utilizar los métodos DSL disponibles dentro de un spec, que crean y registran automáticamente un TestListener. Por ejemplo, podemos invocar beforeTest o afterTest (entre otros) directamente junto a nuestros tests.

class TestSpec : WordSpec({
beforeTest {
println("Starting a test $it")
}
afterTest { (test, result) ->
println("Finished spec with result $result")
}
"this test" should {
"be alive" {
println("Johnny5 is alive!")
}
}
})

Internamente, estos métodos DSL crearán una instancia de TestListener, sobrescribiendo las funciones apropiadas y asegurando que este listener de pruebas quede registrado para su ejecución.

Puedes usar afterProject como método DSL para crear una instancia de ProjectListener, pero no existe beforeProject porque cuando el framework llega a esta etapa de detección de specs, ¡el proyecto ya ha comenzado!

Métodos DSL con funciones

Dado que estos métodos DSL aceptan funciones, podemos extraer lógica a una función y reutilizarla en varios lugares. El tipo BeforeTest usado en la definición de función es un alias de suspend (TestCase) -> Unit para mantener la simplicidad. Existen alias para los tipos de cada callback.

val startTest: BeforeTest = {
println("Starting a test $it")
}

class TestSpec : WordSpec({

// used once
beforeTest(startTest)

"this test" should {
"be alive" {
println("Johnny5 is alive!")
}
}
})

class OtherSpec : WordSpec({

// used twice
beforeTest(startTest)

"this test" should {
"fail" {
fail("boom")
}
}
})

Sobrescribir funciones callback en un Spec

El segundo método, relacionado, es sobrescribir las funciones callback directamente en el Spec. Esto es esencialmente una variación del primer método.

class TestSpec : WordSpec() {
override fun beforeTest(testCase: TestCase) {
println("Starting a test $testCase")
}

init {
"this test" should {
"be alive" {
println("Johnny5 is alive!")
}
}
}
}
CallbackDescription
beforeContainerInvoked directly before each test with type TestType.Container is executed, with the TestCase instance as a parameter. If the test is marked as ignored / disabled / inactive, then this callback won't be invoked.
afterContainerInvoked immediately after a TestCase with type TestType.Container has finished, with the TestResult of that test. If a test case was skipped (ignored / disabled / inactive) then this callback will not be invoked for that particular test case.

The callback will execute even if the test fails.
beforeEachInvoked directly before each test with type TestType.Test is executed, with the TestCase instance as a parameter. If the test is marked as ignored / disabled / inactive, then this callback won't be invoked.
afterEachInvoked immediately after a TestCase with type TestType.Test has finished, with the TestResult of that test. If a test case was skipped (ignored / disabled / inactive) then this callback will not be invoked for that particular test case.

The callback will execute even if the test fails.
beforeAnyInvoked directly before each test with any TestType is executed, with the TestCase instance as a parameter. If the test is marked as ignored / disabled / inactive, then this callback won't be invoked.
afterAnyInvoked immediately after a TestCase with any TestType has finished, with the TestResult of that test. If a test case was skipped (ignored / disabled / inactive) then this callback will not be invoked for that particular test case.

The callback will execute even if the test fails.
beforeTestInvoked directly before each test is executed with the TestCase instance as a parameter. If the test is marked as ignored / disabled / inactive, then this callback won't be invoked.

This callback has the same behavior as beforeAny.
afterTestInvoked immediately after a TestCase has finished with the TestResult of that test. If a test case was skipped (ignored / disabled / inactive) then this callback will not be invoked for that particular test case.

The callback will execute even if the test fails.

This callback has the same behavior as afterAny.
beforeSpecInvoked after the Engine instantiates a spec to be used as part of a test execution.

The callback is provided with the Spec instance that the test will be executed under.

If a spec is instantiated multiple times - for example, if InstancePerTest or InstancePerLeaf isolation modes are used, then this callback will be invoked for each instance created, just before the first test (or only test) is executed for that spec.

This callback should be used if you need to perform setup each time a new spec instance is created.

If you simply need to perform setup once per class file, then use prepareSpec. This callback runs before any beforeTest functions are invoked.

When running in the default SingleInstance isolation mode, then this callback and prepareSpec are functionally the same since all tests will run in the same spec instance.
afterSpecIs invoked after the TestCases that are part of a particular spec instance have completed.

If a spec is instantiated multiple times - for example, if InstancePerTest or InstancePerLeaf isolation modes are used, then this callback will be invoked for each instantiated spec, after the tests that are applicable to that spec instance have returned.

This callback should be used if you need to perform cleanup after each individual spec instance. If you need to perform cleanup once per class file, then use finalizeSpec.

This callback runs after any afterTest callbacks have been invoked.

When running in the default SingleInstance isolation mode, then this callback and finalizeSpec are functionally the same since all tests will run in the same spec instance.
In case there is any exception in beforeSpec, afterSpec will be skipped
prepareSpecCalled once per spec, when the engine is preparing to execute the tests for that spec. The KClass instance of the spec is provided as a parameter.

Regardless of how many times the spec is instantiated, for example, if InstancePerTest or InstancePerLeaf isolation modes are used, this callback will only be invoked once. If there are no active tests in a spec, then this callback will still be invoked.

When running in the default SingleInstance isolation mode, then this callback and beforeSpec are functionally the same since all tests will run in the same spec instance.
finalizeSpecCalled once per Spec, after all tests have completed for that spec.

Regardless of how many times the spec is instantiated, for example, if InstancePerTest or InstancePerLeaf isolation modes are used, this callback will only be invoked once.

The results parameter contains every TestCase, along with the result of that test, including tests that were ignored (which will have a TestResult that has TestStatus.Ignored).

When running in the default SingleInstance isolation mode, then this callback and afterSpec are functionally the same since all tests will run in the same spec instance.
beforeInvocationInvoked before each 'run' of a test, with a flag indicating the iteration number. This callback is useful if you have set a test to have multiple invocations via config and want to do some setup / teardown between runs.

If you are running a test with the default single invocation then this callback is effectively the same as beforeTest.

Note: If you have set multiple invocations _and multiple threads, then these callbacks will be invoked concurrently._
afterInvocationInvoked after each 'run' of a test, with a flag indicating the iteration number. This callback is useful if you have set a test to have multiple invocations via config and want to do some setup / teardown between runs.

If you are running a test with the default single invocation then this callback is effectively the same as afterTest.

Note: If you have set multiple invocations _and multiple threads, then these callbacks will be invoked concurrently._