Skip to main content
Annie Mei uses Rust’s built-in testing framework along with code quality tools to maintain high standards.

Running Tests

Rust’s testing framework is built into cargo:

Run All Tests

This runs:
  • Unit tests (in #[cfg(test)] modules)
  • Integration tests (in tests/ directory)
  • Documentation tests (in doc comments)

Run Specific Tests

Test a specific module:
Run tests matching a pattern:
Run a single test function:

Show Test Output

By default, Rust captures stdout/stderr. To see print statements:
Show all output including passing tests:

Writing Tests

Unit Tests

Unit tests live in the same file as the code being tested, in a #[cfg(test)] module:
src/commands/ping.rs
See src/commands/ping.rs:50-78 for the complete implementation.

Test Patterns

Annie Mei follows a testable architecture pattern:
  1. Core logic - Transport-agnostic, pure functions
  2. Adapter - Thin wrapper that calls Serenity APIs
Example from src/commands/ping.rs:
This separation allows testing handle_ping() without mocking Discord APIs.

Integration Tests

Integration tests go in the tests/ directory:
tests/integration_test.rs

Mocking External APIs

For commands that call external APIs (AniList, MAL, Spotify), mock the responses:
See src/commands/anime/command.rs:136-209 for complete examples.

Code Quality Tools

Formatting with rustfmt

Format all code according to Rust style guidelines:
Check formatting without modifying files:
Always run cargo fmt before committing code. This is a required convention.

Linting with Clippy

Run the Clippy linter to catch common mistakes:
Fix warnings automatically (when possible):
Treat warnings as errors:
Fix all Clippy warnings before committing. This ensures code quality.

Type Checking

Fast type checking without building:
This is much faster than cargo build and catches most errors.

Code Coverage

Generate code coverage reports using cargo-tarpaulin:

Install tarpaulin

Generate Coverage Report

This creates an HTML report at tarpaulin-report.html. For CI/CD, output in XML format:

Benchmarking

Benchmark performance-critical code:
benches/fuzzy_bench.rs
Run benchmarks:

Pre-Commit Workflow

Before committing, run this checklist:
1

Format Code

2

Run Linter

Fix all warnings.
3

Run Tests

Ensure all tests pass.
4

Check Types

Verify no type errors.
Consider using a git pre-commit hook to automate this workflow:
.git/hooks/pre-commit
Make it executable:

CI/CD Testing

Annie Mei uses GitHub Actions for automated testing. The workflow:
  1. Run cargo fmt -- --check
  2. Run cargo clippy -- -D warnings
  3. Run cargo test
  4. Build release binary
See .github/workflows/ for workflow definitions.

Test-Driven Development

Follow TDD for new features:
1

Write a Failing Test

Start with a test that captures the desired behavior:
2

Run the Test

Verify it fails:
3

Implement the Feature

Write minimal code to make the test pass:
4

Run the Test Again

Verify it passes:
5

Refactor

Improve the implementation while keeping tests green:

Debugging Tests

Use println! or dbg! in tests:
Run with output visible:

Test-Specific Logging

Enable logging in tests:

Running Single Tests in Debug Mode

This shows full stack traces on panics.

Best Practices

Test Naming

Use descriptive test names:
Format: function_scenario_expectedBehavior

Arrange-Act-Assert

Structure tests clearly:

Test Independence

Each test should be independent:
  • Don’t rely on test execution order
  • Clean up resources after tests
  • Avoid shared mutable state

Edge Cases

Test boundary conditions:
  • Empty strings
  • Null values (None)
  • Maximum/minimum values
  • Invalid input

Next Steps

Adding Commands

Learn how to write testable command handlers

Architecture

Understand testable design patterns

Rust Testing Book

Official Rust testing documentation