Skip to content

Commit

Permalink
Adding JVM SpecInterceptor reclassifying aborted tests as Ignored (#3268
Browse files Browse the repository at this point in the history
)

* Adding JVM SpecInterceptor reclassifying aborted tests as Ignored

* Adding tests for TestResult.Success and TestResult.Failure
  • Loading branch information
Kantis committed Oct 30, 2022
1 parent 2f57f2e commit c10b832
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 1 deletion.
@@ -0,0 +1,10 @@
package io.kotest.engine

import io.kotest.common.KotestInternal
import io.kotest.engine.spec.interceptor.SpecInterceptor

/**
* Returns the [SpecInterceptor]s that should be used for this platform.
*/
@KotestInternal
internal expect fun specInterceptorsForPlatform(): List<SpecInterceptor>
Expand Up @@ -31,6 +31,7 @@ import io.kotest.engine.spec.interceptor.SpecRefInterceptor
import io.kotest.engine.spec.interceptor.SpecStartedInterceptor
import io.kotest.engine.spec.interceptor.SystemPropertySpecFilterInterceptor
import io.kotest.engine.spec.interceptor.TagsExcludedSpecInterceptor
import io.kotest.engine.specInterceptorsForPlatform
import io.kotest.mpp.Logger
import io.kotest.mpp.bestName
import kotlin.reflect.KClass
Expand Down Expand Up @@ -98,7 +99,7 @@ class SpecExecutor(
ProjectContextInterceptor(context.toProjectContext()),
SpecExtensionInterceptor(context.configuration.registry),
ConfigurationInContextInterceptor(context.configuration),
)
) + specInterceptorsForPlatform()

val initial: suspend (Spec) -> Result<Map<TestCase, TestResult>> = {
try {
Expand Down
Expand Up @@ -10,6 +10,7 @@ import io.kotest.engine.interceptors.SpecSortEngineInterceptor
import io.kotest.engine.interceptors.TestDslStateInterceptor
import io.kotest.engine.interceptors.TestEngineInitializedInterceptor
import io.kotest.engine.interceptors.TestEngineStartedFinishedInterceptor
import io.kotest.engine.spec.interceptor.SpecInterceptor

@KotestInternal
internal actual fun testEngineInterceptors(): List<EngineInterceptor> {
Expand All @@ -24,3 +25,7 @@ internal actual fun testEngineInterceptors(): List<EngineInterceptor> {
TestEngineInitializedInterceptor,
)
}

@KotestInternal
internal actual fun specInterceptorsForPlatform(): List<SpecInterceptor> =
listOf()
Expand Up @@ -10,6 +10,7 @@ import io.kotest.engine.interceptors.SpecSortEngineInterceptor
import io.kotest.engine.interceptors.TestDslStateInterceptor
import io.kotest.engine.interceptors.TestEngineInitializedInterceptor
import io.kotest.engine.interceptors.TestEngineStartedFinishedInterceptor
import io.kotest.engine.spec.interceptor.SpecInterceptor

@KotestInternal
internal actual fun testEngineInterceptors(): List<EngineInterceptor> {
Expand All @@ -24,3 +25,7 @@ internal actual fun testEngineInterceptors(): List<EngineInterceptor> {
TestEngineInitializedInterceptor,
)
}

@KotestInternal
internal actual fun specInterceptorsForPlatform(): List<SpecInterceptor> =
listOf()
Expand Up @@ -4,6 +4,7 @@ import io.kotest.common.KotestInternal
import io.kotest.engine.interceptors.DumpConfigInterceptor
import io.kotest.engine.interceptors.EmptyTestSuiteInterceptor
import io.kotest.engine.interceptors.EngineInterceptor
import io.kotest.engine.interceptors.MarkAbortedExceptionsAsSkippedTestInterceptor
import io.kotest.engine.interceptors.ProjectExtensionEngineInterceptor
import io.kotest.engine.interceptors.ProjectListenerEngineInterceptor
import io.kotest.engine.interceptors.ProjectTimeoutEngineInterceptor
Expand All @@ -12,6 +13,7 @@ import io.kotest.engine.interceptors.TestDslStateInterceptor
import io.kotest.engine.interceptors.TestEngineInitializedInterceptor
import io.kotest.engine.interceptors.TestEngineStartedFinishedInterceptor
import io.kotest.engine.interceptors.WriteFailuresInterceptor
import io.kotest.engine.spec.interceptor.SpecInterceptor

@KotestInternal
actual fun testEngineInterceptors(): List<EngineInterceptor> {
Expand All @@ -28,3 +30,7 @@ actual fun testEngineInterceptors(): List<EngineInterceptor> {
TestEngineInitializedInterceptor,
)
}

@KotestInternal
internal actual fun specInterceptorsForPlatform(): List<SpecInterceptor> =
listOf(MarkAbortedExceptionsAsSkippedTestInterceptor)
@@ -0,0 +1,34 @@
package io.kotest.engine.interceptors

import io.kotest.common.JVMOnly
import io.kotest.common.KotestInternal
import io.kotest.core.spec.Spec
import io.kotest.core.test.TestCase
import io.kotest.core.test.TestResult
import io.kotest.engine.spec.interceptor.SpecInterceptor
import org.opentest4j.TestAbortedException

/**
* Writes failed specs to a file so that the [io.kotest.engine.spec.FailureFirstSorter]
* can use the file to run failed specs first.
*
* Note: This is a JVM only feature.
*/
@JVMOnly
internal object MarkAbortedExceptionsAsSkippedTestInterceptor : SpecInterceptor {

override suspend fun intercept(
spec: Spec,
fn: suspend (Spec) -> Result<Map<TestCase, TestResult>>
): Result<Map<TestCase, TestResult>> {
return fn(spec).map { success ->
success.mapValues { (_, result) ->
if (result.errorOrNull is TestAbortedException) {
TestResult.Ignored
} else {
result
}
}
}
}
}
@@ -0,0 +1,64 @@
package com.sksamuel.kotest.engine.interceptors

import io.kotest.core.descriptors.Descriptor
import io.kotest.core.descriptors.DescriptorId
import io.kotest.core.names.TestName
import io.kotest.core.spec.style.FreeSpec
import io.kotest.core.test.TestCase
import io.kotest.core.test.TestResult
import io.kotest.core.test.TestType
import io.kotest.engine.interceptors.MarkAbortedExceptionsAsSkippedTestInterceptor
import io.kotest.matchers.collections.shouldContainExactly
import io.kotest.matchers.result.shouldBeSuccess
import org.opentest4j.TestAbortedException
import kotlin.time.Duration.Companion.milliseconds

class AbortedExceptionTest : FreeSpec({

val fakeTestCase = TestCase(
Descriptor.TestDescriptor(
Descriptor.SpecDescriptor(DescriptorId("dummy"), DummySpec::class),
DescriptorId("test")
), TestName("dummy"), DummySpec(), {}, type = TestType.Test
)

"Test should be marked as Ignored" {
val result = MarkAbortedExceptionsAsSkippedTestInterceptor.intercept(DummySpec()) {
Result.success(
mapOf(fakeTestCase to TestResult.Error(1.milliseconds, TestAbortedException()))
)
}

result.shouldBeSuccess()
.values
.shouldContainExactly(TestResult.Ignored)
}

"Failure is not reclassified" {
val assertionError = AssertionError("blah")
val result = MarkAbortedExceptionsAsSkippedTestInterceptor.intercept(DummySpec()) {
Result.success(
mapOf(fakeTestCase to TestResult.Failure(1.milliseconds, assertionError))
)
}

result.shouldBeSuccess()
.values
.shouldContainExactly(TestResult.Failure(1.milliseconds, assertionError))
}

"Successful test is not reclassified" {
val result = MarkAbortedExceptionsAsSkippedTestInterceptor.intercept(DummySpec()) {
Result.success(
mapOf(fakeTestCase to TestResult.Success(1.milliseconds))
)
}

result.shouldBeSuccess()
.values
.shouldContainExactly(TestResult.Success(1.milliseconds))
}
})

private class DummySpec : FreeSpec()

0 comments on commit c10b832

Please sign in to comment.