---
title: Rust Cargo Test
description: Learn how to integrate Allure with Rust tests by using the official allure-cargotest crate and cargo test to generate rich, interactive test reports.
---

# Getting started with Rust Cargo Test

[![allure-cargotest crates.io latest version](https://img.shields.io/crates/v/allure-cargotest?style=flat "allure-cargotest crates.io latest version")](https://crates.io/crates/allure-cargotest)

Generate beautiful HTML reports using [Allure Report](https://allurereport.org/docs/) and your Rust tests.

Info:
The main user-facing crate is [`allure-cargotest`](https://github.com/allure-framework/allure-rust/tree/main/crates/allure-cargotest). If you are building your own integration for a custom runner or framework, use [`allure-rust-commons`](https://github.com/allure-framework/allure-rust/tree/main/crates/allure-rust-commons) instead. Both crates live in the official `allure-rust` repository.

## Setting up

### 1. Prepare your project

1. Make sure a recent stable Rust toolchain is installed.

   The official `allure-rust` workspace is published for Rust 1.74 and newer and uses the Rust 2021 edition.

1. Open a terminal and go to the project directory. For example:

   ```bash
   cd /home/user/myproject
   ```

1. Install Allure Report. The official `allure-rust` repository documents the workflow with the [Allure 3 CLI](/docs/v3/install/).

1. Add the `allure-cargotest` integration:

   ```bash
   cargo add allure-cargotest --dev
   ```

1. Annotate your tests with `#[allure_test]`. You can also mark helper functions with `#[step]` so they appear as separate steps in the report.

   ```rust
   use allure_cargotest::{allure_test, step};

   #[step]
   fn open_login_page() {
       // your step implementation
   }

   #[allure_test]
   #[test]
   fn login_works() {
       allure.epic("Web interface");
       allure.feature("Authentication");
       allure.story("Login with username and password");
       allure.parameter("browser", "firefox");

       open_login_page();
       allure.attachment("page.html", "text/html", "<html>...</html>");
   }
   ```

### 2. Run tests

Run your tests the same way as usual:

```bash
cargo test
```

By default, `allure-cargotest` writes the results to `target/allure-results`.

To use a different directory, set `ALLURE_RESULTS_DIR` before the test run:

```bash
ALLURE_RESULTS_DIR=./allure-results cargo test
```

If the results directory already exists, the new files are added to the existing ones, so that a future report will be based on all of them.

### 3. Generate a report

After the test run, generate and open the report with the Allure CLI:

```bash
allure generate ./target/allure-results --output ./target/allure-report --clean
allure open ./target/allure-report
```

If you changed the results directory with `ALLURE_RESULTS_DIR`, use that path in the `allure generate` command.

## Writing tests

Rust Cargo Test extends plain `cargo test` output with richer reporting features. You can use it to:

- add [descriptions, owners, links, and other metadata](#add-metadata),
- organize tests into [behavior-based and suite-based hierarchies](#organize-tests),
- split the execution into [nested steps](#divide-a-test-into-steps),
- describe [parameters and attachments](#add-parameters-and-attachments),
- run only selected tests through a [test plan file](#select-tests-via-a-test-plan-file).

### Add metadata

Inside a function marked with `#[allure_test]`, the macro injects an `allure` facade that you can use to enrich the test result:

```rust
use allure_cargotest::allure_test;

#[allure_test(name = "Login works", id = "AUTH-1")]
#[test]
fn login_works() {
    allure.description("This test verifies login with a username and a password.");
    allure.owner("John Doe");
    allure.tag("smoke");
    allure.severity("critical");
    allure.issue("AUTH-123", "https://jira.example.com/browse/AUTH-123");
    allure.tms("TMS-456", "https://tms.example.com/cases/TMS-456");
}
```

### Organize tests

Allure supports both behavior-based and suite-based hierarchies. For example:

```rust
use allure_cargotest::allure_test;

#[allure_test]
#[test]
fn login_works() {
    allure.epic("Web interface");
    allure.feature("Authentication");
    allure.story("Login with username and password");

    allure.parent_suite("UI tests");
    allure.suite("Authentication");
    allure.sub_suite("Positive scenarios");
}
```

When you use `#[allure_test]`, `allure-cargotest` also derives suite labels from the Rust module path automatically. Explicit calls to `allure.parent_suite(...)`, `allure.suite(...)`, or `allure.sub_suite(...)` override the synthetic labels with the same name.

### Divide a test into steps

You can declare reusable step functions with `#[step]`:

```rust
use allure_cargotest::{allure_test, step};

#[step(name = "Open login page")]
fn open_login_page() {
    // ...
}

#[step(name = "Submit credentials")]
fn submit_credentials() {
    // ...
}

#[allure_test]
#[test]
fn login_works() {
    open_login_page();
    submit_credentials();
}
```

You can also create steps directly from the runtime API:

```rust
use allure_cargotest::allure_test;

#[allure_test]
#[test]
fn login_works() {
    allure.step_with("Open login page", || {
        // ...
    });

    let _guard = allure.step("Check profile page");
    // ...
}
```

### Add parameters and attachments

Parameters and attachments are stored in the generated Allure results and rendered in the report:

```rust
use allure_cargotest::allure_test;

#[allure_test]
#[test]
fn login_works() {
    allure.parameter("browser", "firefox");
    allure.parameter("environment", "staging");
    allure.attachment(
        "request.json",
        "application/json",
        br#"{"username":"demo","rememberMe":true}"#,
    );
}
```

### Select tests via a test plan file

`allure-cargotest` supports the standard Allure test plan mechanism via the `ALLURE_TESTPLAN_PATH` environment variable.

Create a JSON file such as:

```json
{
  "version": "1.0",
  "tests": [{ "id": "AUTH-1" }, { "selector": "auth::tests::login_works" }]
}
```

Then run the tests with:

```bash
ALLURE_TESTPLAN_PATH=./testplan.json cargo test
```

Entries with `id` match tests annotated with `#[allure_test(id = "...")]`. Entries with `selector` match the full Rust test name, including its module path.

## Building a custom integration

If you need to integrate Allure with a custom Rust test runner or framework, use `allure-rust-commons`:

```bash
cargo add allure-rust-commons
```

At that level, you create a writer, initialize a runtime, start a test case, and stop it when execution ends:

```rust
use allure_rust_commons::{AllureRuntime, FileSystemResultsWriter, StartTestCaseParams, Status};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let writer = FileSystemResultsWriter::new("target/allure-results")?;
    let runtime = AllureRuntime::new(writer);
    let lifecycle = runtime.lifecycle();

    lifecycle.start_test_case(
        StartTestCaseParams::new("login_works").with_full_name("auth::login_works"),
    );
    // ... update metadata, add steps, and add attachments ...
    lifecycle.stop_test_case(Status::Passed, None);

    Ok(())
}
```

See [Reference](/docs/rust-reference/) for the main macros and runtime APIs, or [Configuration](/docs/rust-configuration/) for the supported environment variables.
