Allure Kotlin extensions reference
These are the functions provided by the Allure Kotlin extensions. All of them are top-level functions in the io.qameta.allure.kotlin.extensions package, except for the coroutine functions in io.qameta.allure.kotlin.coroutines. You can import the functions one by one or all at once:
import io.qameta.allure.kotlin.extensions.*The functions add information to the test, fixture or step that is currently running, in the same way as the Runtime API of your test framework's integration, for example, Allure JUnit Jupiter. Calls made while no test or fixture is running have no effect.
Metadata
Assign a test's description, links and other metadata.
Description
description(description: String)descriptionHtml(descriptionHtml: String)
Set the test's description. description() accepts Markdown, descriptionHtml() accepts HTML.
import io.qameta.allure.kotlin.extensions.description
import org.junit.jupiter.api.Test
class TestMyWebsite {
@Test
fun testAuthentication() {
description("This test attempts to log into the website using a login and a password. Fails if any error happens.\n\nNote that this test does not test 2-Factor Authentication.")
// ...
}
}Label
label(name: String, value: String)
Add a label with the given name and value to the test.
import io.qameta.allure.kotlin.extensions.label
import org.junit.jupiter.api.Test
class TestMyWebsite {
@Test
fun testAuthentication() {
label(name = "component", value = "authentication")
label(name = "owner", value = "John Doe")
// ...
}
}Link
link(url: String)link(name: String, url: String)link(name: String, type: String, url: String)issue(name: String, url: String)tms(name: String, url: String)
Add a link related to the test. issue() and tms() add links of the issue and tms types.
import io.qameta.allure.kotlin.extensions.issue
import io.qameta.allure.kotlin.extensions.link
import io.qameta.allure.kotlin.extensions.tms
import org.junit.jupiter.api.Test
class TestMyWebsite {
@Test
fun testAuthentication() {
link(name = "Website", url = "https://dev.example.com/")
issue(name = "AUTH-123", url = "https://issues.example.com/AUTH-123")
tms(name = "TMS-456", url = "https://tms.example.com/TMS-456")
// ...
}
}Behavior-based hierarchy
epic(value: String)feature(value: String)story(value: String)
Assign the names of the epic, feature and user story to the test, as part of Allure's behavior-based hierarchy.
import io.qameta.allure.kotlin.extensions.epic
import io.qameta.allure.kotlin.extensions.feature
import io.qameta.allure.kotlin.extensions.story
import org.junit.jupiter.api.Test
class TestMyWebsite {
@Test
fun testAuthentication() {
epic("Web interface")
feature("Essential features")
story("Authentication")
// ...
}
}Suite-based hierarchy
suite(value: String)
Assign the name of the suite, as part of Allure's suite-based hierarchy. To set the other levels of the hierarchy, use label() with the parentSuite or subSuite label name.
import io.qameta.allure.kotlin.extensions.suite
import org.junit.jupiter.api.Test
class TestMyWebsite {
@Test
fun testAuthentication() {
suite("Tests for essential features")
// ...
}
}Test steps
step(name: String = "step", body: StepScope.() -> T): Tstep(name: String, status: Status = Status.PASSED)
Define a test step.
The first function runs the code in body as a step with the given name and returns the value that the code returns. If the code throws an exception, the step is marked as failed (for assertion errors) or broken (for other exceptions), and the exception is passed on. Steps can contain other steps.
The second function adds a step that has already finished, with the given name and status.
Inside body, the following functions are available:
name(name: String)- change the name of the step, for example, to include a value that becomes known during the step.parameter(name: String, value: T, excluded: Boolean? = null, mode: Parameter.Mode? = null): T- add a parameter to the step. The arguments are the same as for the test parameters.
import io.qameta.allure.kotlin.extensions.step
import io.qameta.allure.model.Status
import org.junit.jupiter.api.Test
class TestOrders {
@Test
fun testCreateOrder() {
val orderId = step("Create order") {
parameter(name = "region", value = "eu-west")
val id = createOrder()
name("Create order $id")
id
}
step("Check the order") {
step("Order exists")
step("Delivery date is set", Status.SKIPPED)
verifyOrder(orderId)
}
}
}Stages
stage(name: String)
Start a stage: a named group of steps for a phase of the test, such as preparing data or checking results. A stage is shown as a step. It has no explicit end: it contains the steps and attachments that follow it, until the next stage starts or the step, test or fixture that contains it ends. A stage started inside a step becomes a part of that step.
import io.qameta.allure.kotlin.extensions.stage
import io.qameta.allure.kotlin.extensions.step
import org.junit.jupiter.api.Test
class TestOrders {
@Test
fun testCreateOrder() {
stage("Prepare data")
step("Create a customer")
step("Add products to the cart")
stage("Submit the order")
step("Open the checkout page")
step("Confirm the order")
stage("Verify the result")
step("Order status is created")
}
}Parametrized tests
parameter(name: String, value: T, excluded: Boolean? = null, mode: Parameter.Mode? = null): T
Add a parameter with the given name and value to the test, and return the value. Allure Report shows the parameters on the test page. Different values of a parameter make different tests in the history, unless the parameter is excluded.
excluded- iftrue, the parameter is not used to tell tests apart in the history. Use it for values that change on every run, such as timestamps.mode- how the parameter is shown in the report:Parameter.Mode.DEFAULTshows the parameter and its value,Parameter.Mode.MASKEDshows the parameter but hides its value (use it for passwords, tokens and other sensitive values),Parameter.Mode.HIDDENdoesn't show the parameter at all. Note that the values of masked and hidden parameters are still stored in the test results directory.
The parameters added this way are shown together with the ones that your test framework's integration reports, for example, the arguments of a parameterized test.
import io.qameta.allure.kotlin.extensions.parameter
import io.qameta.allure.model.Parameter
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.ValueSource
class TestMyWebsite {
@ParameterizedTest
@ValueSource(strings = ["johndoe", "janedoe"])
fun testAuthentication(login: String) {
val browser = parameter("browser", "firefox")
parameter(name = "password", value = "qwerty", mode = Parameter.Mode.MASKED)
parameter(name = "startedAt", value = System.currentTimeMillis(), excluded = true)
// ...
}
}Attachments
attachment(name: String, content: String, type: String = "text/plain", fileExtension: String? = null)attachment(name: String, content: ByteArray, type: String = "application/octet-stream", fileExtension: String? = null)attachment(name: String, content: InputStream, type: String = "application/octet-stream", fileExtension: String? = null)attachmentAsync(name: String, content: CompletionStage<out InputStream>, type: String = "application/octet-stream", fileExtension: String? = null): CompletableFuture<Void>addHttpExchange(name: String, exchange: HttpExchange)
Add an attachment with the given name and content. Like in other Allure Java integrations, each attachment is shown as a step with the attachment's name.
The type is the media type of the content. It defines how Allure Report shows the attachment. If fileExtension is not set, the file extension is chosen based on the type. Pass an empty string to save the file without an extension.
attachmentAsync() doesn't wait for the content. It returns a future that completes when the attachment is written. The test, fixture or step that the attachment belongs to waits for it before it ends.
addHttpExchange() adds an HTTP exchange attachment that you built yourself.
import io.qameta.allure.kotlin.extensions.attachment
import io.qameta.allure.kotlin.extensions.attachmentAsync
import org.junit.jupiter.api.Test
import java.util.concurrent.CompletableFuture
class TestMyWebsite {
@Test
fun testAuthentication() {
attachment(name = "response", content = """{"status": "ok"}""", type = "application/json")
attachment(name = "screenshot", content = takeScreenshot(), type = "image/png")
attachmentAsync(
name = "server log",
content = CompletableFuture.supplyAsync { downloadServerLog() },
type = "text/plain",
fileExtension = "log",
)
// ...
}
}Global errors
globalError(throwable: Throwable)globalError(statusDetails: StatusDetails)
Report an error that doesn't belong to a single test, such as an environment that is not available. See Global errors and attachments.
import io.qameta.allure.kotlin.extensions.globalError
import io.qameta.allure.model.StatusDetails
globalError(IllegalStateException("Test database snapshot is outdated"))
globalError(StatusDetails().setMessage("Payment sandbox is not available"))Coroutines
The functions in this section are provided by the allure-kotlin-coroutines module.
Allure remembers the running test and step separately for each thread. Coroutines can switch threads, for example, after withContext(Dispatchers.IO), and the thread they continue on may not know which test is running. Steps and attachments added there may get lost, or end up in a different test if several tests run in parallel. The functions below make sure they end up in the right test and step.
Suspending steps
step(name: String = "step", body: suspend StepScope.() -> T): T
Same as step() from allure-kotlin-extensions, but the code in body can suspend. The step stays the current step when the code switches threads, so the steps and attachments added inside it are shown in it.
If the coroutine is cancelled, the step is marked as broken, and the cancellation exception is passed on.
import io.qameta.allure.kotlin.coroutines.step
import io.qameta.allure.kotlin.extensions.attachment
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import org.junit.jupiter.api.Test
class TestOrders {
@Test
fun testLoadOrder() {
runBlocking {
step("Load order") {
val order = withContext(Dispatchers.IO) {
orderClient.load()
}
parameter("orderId", order.id)
attachment(name = "order", content = order.toString())
}
}
}
}This function has the same name as step() from io.qameta.allure.kotlin.extensions. If a file needs both, import one of them under a different name, for example, import io.qameta.allure.kotlin.extensions.step as syncStep.
Passing the current test to coroutines
withAllureContext(lifecycle: AllureLifecycle = Allure.getLifecycle(), body: suspend CoroutineScope.() -> T): TallureContext(): CoroutineContext
When you start coroutines that run on other threads, such as launch(Dispatchers.IO), run them inside withAllureContext(). It remembers the test, fixture or step that is running when it is called and passes it to all coroutines started inside it. Steps started in parallel coroutines are shown next to each other, not inside each other.
import io.qameta.allure.kotlin.coroutines.step
import io.qameta.allure.kotlin.coroutines.withAllureContext
import io.qameta.allure.kotlin.extensions.attachment
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.Test
class TestReports {
@Test
fun testBuildReports() {
runBlocking {
withAllureContext {
coroutineScope {
launch(Dispatchers.IO) {
attachment(name = "worker output", content = loadOutput())
}
launch(Dispatchers.Default) {
step("Calculate summary") {
calculateSummary()
}
}
}
}
}
}
}Alternatively, add allureContext() to the context of a single coroutine:
launch(Dispatchers.IO + allureContext()) {
// ...
}Make sure that the coroutines finish before the test, fixture or step that started them ends, for example, by starting them in coroutineScope { } as above. Don't use GlobalScope or other ways to start coroutines that can outlive the test.
Annotations and coroutines
The @Step and @Attachment annotations work in Kotlin code in the same way as in Java, and they need AspectJ, as described in the documentation of your test framework's integration. The functions on this page don't need AspectJ.
Don't use @Step on suspend functions. Such steps get an extra parameter with internal data, and the steps added after the function switches threads may not appear in the step. Use the suspending step() function instead.