{"slug": "11-10-integration-tests", "title": "11.10. Integration Tests", "summary": "In Rust, integration tests are placed in a separate `tests` directory alongside `src`, and each test file is compiled as its own crate, meaning they can only access the library's public API. The purpose of these tests is to verify that multiple parts of the library work together correctly, catching issues that unit tests might miss. To create an integration test, you import the library crate (e.g., `use RustStudy;`) and write test functions annotated with `#[test]`, without needing `#[cfg(test)]`.", "body_md": "**If you find this helpful, please like, bookmark, and follow. To keep learning along, follow this series.**\n\n## 11.10.1 What Are Integration Tests\n\nIn 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.\n\n**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.\n\nSometimes 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**.\n\n## 11.10.2 The `tests`\n\nDirectory\n\nTo create integration tests, first create a `tests`\n\ndirectory.\n\nThis directory sits alongside `src`\n\n, and `cargo`\n\nautomatically looks for integration test files there. You can create any number of integration test files in this directory. During compilation, `cargo`\n\ntreats each test file as a separate package, that is, a separate `crate`\n\n.\n\nHere is a demonstration of creating integration test files:\n\n### 1. Create the `tests`\n\nDirectory\n\nCreate a folder named `tests`\n\nnext to `src`\n\n:\n\n### 2. Create a Test File\n\nCreate a `.rs`\n\ntest file inside `tests`\n\nand give it a name. Here I used `integration_test.rs`\n\n:\n\n### 3. Move the Test Code Into the Test File\n\nUsing the code from the previous article (`lib.rs`\n\n) as an example:\n\n``` php\npub fn add_two(a: usize) -> usize {\n    internal_adder(a, 2)\n}\n\nfn internal_adder(left: usize, right: usize) -> usize {\n    left + right\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn internal() {\n        let result = internal_adder(2, 2);\n        assert_eq!(result, 4);\n    }\n}\n```\n\nBecause every integration test file is a separate crate, the file (`integration_test.rs`\n\n) must first import the contents of `lib.rs`\n\ninto scope if it wants to test that crate.\n\nIn this example, since I named the project `RustStudy`\n\n, the package name is `RustStudy`\n\nas well. If you are unsure, check the `name`\n\nfield in your `Cargo.toml`\n\n. In this example, you can write `use RustStudy;`\n\nto import it, and you can also import a specific function if you want.\n\nAfter importing, you can write the test function directly. There is no need to write `#[cfg(test)]`\n\n, because code under the `tests`\n\ndirectory is only run when you execute `cargo test`\n\n. You only need to annotate the test function with `#[test]`\n\n.\n\nThe full code looks like this (`integration_test.rs`\n\n):\n\n``` js\nuse RustStudy;\n\n#[test]\nfn it_adds_two() {\n    let result = RustStudy::add_two(2);\n    assert_eq!(result, 4);\n}\n```\n\nOutput:\n\n``` bash\n$ cargo test\n   Compiling adder v0.1.0 (file:///projects/adder)\n    Finished `test` profile [unoptimized +debuginfo] target(s) in 1.31s\n     Running unittests src/lib.rs (target/debug/deps/adder-1082c4b063a8fbe6)\n\nrunning 1 test\ntest tests::internal ... ok\n\ntest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s\n\n     Running tests/integration_test.rs (target/debug/deps/integration_test-1082c4b063a8fbe6)\n\nrunning 1 test\ntest it_adds_two ... ok\n\ntest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s\n\n   Doc-tests adder\n\nrunning 0 tests\n\ntest result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s\n```\n\nYou can see that this output shows two tests being run: one from `lib.rs`\n\n(a unit test) and one from `integration_test.rs`\n\n(an integration test).\n\n## 11.10.3 Running a Specific Integration Test\n\nTo run a specific integration test function, use `cargo test <test_name>`\n\n. To run all test functions in a specific test file, use `cargo test --test <file_name>`\n\n.\n\nFor example:\n\nNow there are two files under `tests`\n\n. If I only want to run the test functions in `integration_test.rs`\n\n, I can run:\n\n```\ncargo test --test integration_test\n```\n\n## 11.10.4 Submodules in Integration Tests\n\nBecause each file under `tests`\n\nis compiled as a separate crate, these files do not share behavior with one another, unlike the files under `src`\n\n.\n\nSo if I want to extract repeated logic in test functions into a helper function to avoid duplication, how should I write it?\n\nFor example, I create a `common.rs`\n\nfile under `tests`\n\nto store helper functions:\n\nTry running the tests:\n\n``` bash\n$ cargo test\n   Compiling adder v0.1.0 (file:///projects/adder)\n    Finished `test` profile [unoptimized +debuginfo] target(s) in 0.89s\n     Running unittests src/lib.rs (target/debug/deps/adder-1082c4b063a8fbe6)\n\nrunning 1 test\ntest tests::internal ... ok\n\ntest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s\n\n     Running tests/common.rs (target/debug/deps/common-92948b65e88960b4)\n\nrunning 0 tests\n\ntest result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s\n\n     Running tests/integration_test.rs (target/debug/deps/integration_test-92948b65e88960b4)\n\nrunning 1 test\ntest it_adds_two ... ok\n\ntest result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s\n\n   Doc-tests adder\n\nrunning 0 tests\n\ntest result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s\n```\n\nYou can see that `common.rs`\n\nappears in the test output. But since `common.rs`\n\nis only meant to store helper functions, it does not need to be tested itself. That is the wrong way to do it.\n\nThe correct approach is to create a `common`\n\ndirectory under `tests`\n\n, place a `mod.rs`\n\nfile inside it, and move the helper functions there. Then delete the old `common.rs`\n\n:\n\nThis is another naming convention that Rust understands. Rust will not treat the `common`\n\nmodule as an integration test file, and `common`\n\nwill no longer appear in the test output, because subdirectories under `tests`\n\nare not compiled as separate crates.\n\nIf you want to use the contents there in an integration test file, just write `mod <folder_name>;`\n\nat the top of the file. In this example, that would be `mod common;`\n\n. When using it, write `common::your_function`\n\n. In this example, that would be `common::setup()`\n\n.\n\n## 11.10.5 Integration Tests for Binary Crates\n\nIf a project is a binary crate, meaning it only has `src/main.rs`\n\nand no `src/lib.rs`\n\n, you cannot create integration tests under `tests`\n\n, even if you do, you cannot import functions from `main.rs`\n\ninto scope. That is because only a library crate, meaning one with `lib.rs`\n\n, can expose functions for other crates to use.\n\nA binary crate means it runs independently. Therefore, Rust binary projects usually put this logic in `lib.rs`\n\nand keep only a simple call in `main.rs`\n\n. In that way, the project is treated as a library crate and can use integration tests to check the code.", "url": "https://wpnews.pro/news/11-10-integration-tests", "canonical_source": "https://dev.to/someb1oody/1110-integration-tests-1a1d", "published_at": "2026-05-23 22:05:46+00:00", "updated_at": "2026-05-23 22:33:23.946357+00:00", "lang": "en", "topics": ["developer-tools"], "entities": [], "alternates": {"html": "https://wpnews.pro/news/11-10-integration-tests", "markdown": "https://wpnews.pro/news/11-10-integration-tests.md", "text": "https://wpnews.pro/news/11-10-integration-tests.txt", "jsonld": "https://wpnews.pro/news/11-10-integration-tests.jsonld"}}