Setting up a Cargo workspace is the cleanest way to manage both your aggregator library and the aggregator_app binary in one place.
Ⅰ. Setting Up a Cargo workspace
1. Create a new workspace folder
Make a parent folder (say aggregator_workspace):
mkdir aggregator_workspace
cd aggregator_workspace
2. Create the workspace manifest
Inside it, create a Cargo.toml file:
[workspace]
members = [
"aggregator",
"aggregator_app",
]
This tells Cargo that both crates are part of one workspace.
3. Add your crates
Now create the two crates inside the workspace:
cargo new aggregator --lib
cargo new aggregator_app
Now the folder structure looks like this:
aggregator_workspace
├── Cargo.toml # Workspace manifest
├── aggregator # Library crate
│ ├── Cargo.toml
│ └── src/lib.rs
└── aggregator_app # Binary crate
├── Cargo.toml
└── src/main.rs
4. Define the library
Edit aggregator/src/lib.rs:
pub fn summarize(text: &str) -> String {
format!("Summary: {}", text)
}
5. Link the binary to the library
In aggregator_app/Cargo.toml, add the dependency:
[dependencies]
aggregator = { path = "../aggregator" }
6. Use it in the binary
Edit aggregator_app/src/main.rs:
use aggregator::summarize;
fn main() {
let text = "Rust makes systems programming fun and safe!";
let summary = summarize(text);
println!("{}", summary);
}
7. Build and run
From the workspace root:
cargo run -p aggregator_app
Output:
Summary: Rust makes systems programming fun and safe!
✅ Now you have:
- aggregator → library crate
- aggregator_app → binary crate
- managed together in one workspace.
Ⅱ. How to Test the Library
Let’s extend the workspace so you can test your aggregator library while also running the app. There are two ways to test library, one is adding tests inside the library and the other is adding separate integration tests in a tests/ directory
1. Add tests inside the library
Edit aggregator/src/lib.rs:
/// Summarize a given text by prefixing it.
pub fn summarize(text: &str) -> String {
format!("Summary: {}", text)
}
// Unit tests go in a special `tests` module.
#[cfg(test)]
mod tests {
// Bring outer functions into scope
use super::*;
#[test]
fn test_summarize_simple() {
let text = "Hello Rust";
let result = summarize(text);
assert_eq!(result, "Summary: Hello Rust");
}
#[test]
fn test_summarize_empty() {
let text = "";
let result = summarize(text);
assert_eq!(result, "Summary: ");
}
}
2. Run the tests
From the workspace root:
cargo test -p aggregator
Output (example):
running 2 tests
test tests::test_summarize_simple ... ok
test tests::test_summarize_empty ... ok
test result: ok. 2 passed; 0 failed
3. Run the app
From the same root:
cargo run -p aggregator_app
Output:
Summary: Rust makes systems programming fun and safe!
4. (Optional) Integration tests
You can also add separate integration tests in a tests/ directory inside the aggregator crate:
aggregator/
├── Cargo.toml
├── src/lib.rs
└── tests
└── integration_test.rs
tests/integration_test.rs:
use aggregator::summarize;
#[test]
fn integration_summary() {
let text = "Integration testing is easy!";
let result = summarize(text);
assert_eq!(result, "Summary: Integration testing is easy!");
}
Run all tests in the workspace:
cargo test
✅ Now you have:
- Unit tests inside src/lib.rs
- Integration tests in tests/
- Ability to run tests and app from the same workspace.












