# 11.10. Integration Tests

> Source: <https://dev.to/someb1oody/1110-integration-tests-1a1d>
> Published: 2026-05-23 22:05:46+00:00

**If you find this helpful, please like, bookmark, and follow. To keep learning along, follow this series.**

## 11.10.1 What Are Integration Tests

In Rust, integration tests live completely outside the library being tested. Integration tests call the library the same way other code does, which also means they can only call public APIs.

**The purpose of integration tests is to verify that multiple parts of the library work together correctly.** This differs from unit tests, which are smaller and more focused. Unit tests test a single module in isolation and can also test private interfaces.

Sometimes code that works fine on its own can still fail when used together. Integration tests exist to find and solve such problems as early as possible. Therefore, **integration test coverage is important**.

## 11.10.2 The `tests`

Directory

To create integration tests, first create a `tests`

directory.

This directory sits alongside `src`

, and `cargo`

automatically looks for integration test files there. You can create any number of integration test files in this directory. During compilation, `cargo`

treats each test file as a separate package, that is, a separate `crate`

.

Here is a demonstration of creating integration test files:

### 1. Create the `tests`

Directory

Create a folder named `tests`

next to `src`

:

### 2. Create a Test File

Create a `.rs`

test file inside `tests`

and give it a name. Here I used `integration_test.rs`

:

### 3. Move the Test Code Into the Test File

Using the code from the previous article (`lib.rs`

) as an example:

``` php
pub fn add_two(a: usize) -> usize {
    internal_adder(a, 2)
}

fn internal_adder(left: usize, right: usize) -> usize {
    left + right
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn internal() {
        let result = internal_adder(2, 2);
        assert_eq!(result, 4);
    }
}
```

Because every integration test file is a separate crate, the file (`integration_test.rs`

) must first import the contents of `lib.rs`

into scope if it wants to test that crate.

In this example, since I named the project `RustStudy`

, the package name is `RustStudy`

as well. If you are unsure, check the `name`

field in your `Cargo.toml`

. In this example, you can write `use RustStudy;`

to import it, and you can also import a specific function if you want.

After importing, you can write the test function directly. There is no need to write `#[cfg(test)]`

, because code under the `tests`

directory is only run when you execute `cargo test`

. You only need to annotate the test function with `#[test]`

.

The full code looks like this (`integration_test.rs`

):

``` js
use RustStudy;

#[test]
fn it_adds_two() {
    let result = RustStudy::add_two(2);
    assert_eq!(result, 4);
}
```

Output:

``` bash
$ cargo test
   Compiling adder v0.1.0 (file:///projects/adder)
    Finished `test` profile [unoptimized +debuginfo] target(s) in 1.31s
     Running unittests src/lib.rs (target/debug/deps/adder-1082c4b063a8fbe6)

running 1 test
test tests::internal ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

     Running tests/integration_test.rs (target/debug/deps/integration_test-1082c4b063a8fbe6)

running 1 test
test it_adds_two ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests adder

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
```

You can see that this output shows two tests being run: one from `lib.rs`

(a unit test) and one from `integration_test.rs`

(an integration test).

## 11.10.3 Running a Specific Integration Test

To run a specific integration test function, use `cargo test <test_name>`

. To run all test functions in a specific test file, use `cargo test --test <file_name>`

.

For example:

Now there are two files under `tests`

. If I only want to run the test functions in `integration_test.rs`

, I can run:

```
cargo test --test integration_test
```

## 11.10.4 Submodules in Integration Tests

Because each file under `tests`

is compiled as a separate crate, these files do not share behavior with one another, unlike the files under `src`

.

So if I want to extract repeated logic in test functions into a helper function to avoid duplication, how should I write it?

For example, I create a `common.rs`

file under `tests`

to store helper functions:

Try running the tests:

``` bash
$ cargo test
   Compiling adder v0.1.0 (file:///projects/adder)
    Finished `test` profile [unoptimized +debuginfo] target(s) in 0.89s
     Running unittests src/lib.rs (target/debug/deps/adder-1082c4b063a8fbe6)

running 1 test
test tests::internal ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

     Running tests/common.rs (target/debug/deps/common-92948b65e88960b4)

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

     Running tests/integration_test.rs (target/debug/deps/integration_test-92948b65e88960b4)

running 1 test
test it_adds_two ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests adder

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
```

You can see that `common.rs`

appears in the test output. But since `common.rs`

is only meant to store helper functions, it does not need to be tested itself. That is the wrong way to do it.

The correct approach is to create a `common`

directory under `tests`

, place a `mod.rs`

file inside it, and move the helper functions there. Then delete the old `common.rs`

:

This is another naming convention that Rust understands. Rust will not treat the `common`

module as an integration test file, and `common`

will no longer appear in the test output, because subdirectories under `tests`

are not compiled as separate crates.

If you want to use the contents there in an integration test file, just write `mod <folder_name>;`

at the top of the file. In this example, that would be `mod common;`

. When using it, write `common::your_function`

. In this example, that would be `common::setup()`

.

## 11.10.5 Integration Tests for Binary Crates

If a project is a binary crate, meaning it only has `src/main.rs`

and no `src/lib.rs`

, you cannot create integration tests under `tests`

, even if you do, you cannot import functions from `main.rs`

into scope. That is because only a library crate, meaning one with `lib.rs`

, can expose functions for other crates to use.

A binary crate means it runs independently. Therefore, Rust binary projects usually put this logic in `lib.rs`

and keep only a simple call in `main.rs`

. In that way, the project is treated as a library crate and can use integration tests to check the code.
