Skip to content

Latest commit

 

History

History
190 lines (143 loc) · 4.1 KB

File metadata and controls

190 lines (143 loc) · 4.1 KB

SearchDeadCode Testing Guide

Running Tests

All Tests

cargo test

Unit Tests Only

cargo test --lib

Integration Tests Only

cargo test --test integration

Specific Detector Tests

cargo test sealed_variant
cargo test write_only
cargo test unused_param
cargo test unused_intent_extra

With Verbose Output

cargo test -- --nocapture

Test Structure

tests/
├── fixtures/           # Test fixtures (sample code)
│   ├── kotlin/
│   │   ├── dead_code.kt      # Various dead code patterns
│   │   └── all_used.kt       # Clean code (no dead code)
│   ├── java/
│   │   └── DeadCode.java     # Java dead code patterns
│   └── android/
│       └── MainActivity.kt   # Android-specific patterns
└── integration/
    └── analysis_test.rs      # Integration tests

TDD Workflow

1. Write a Failing Test First

#[test]
fn test_new_detection_feature() {
    let fixture = fixtures_path().join("kotlin/new_feature.kt");
    let graph = build_graph_from_file(&fixture);
    let detector = NewFeatureDetector::new();
    let issues = detector.detect(&graph);

    // Assert expected behavior
    assert!(!issues.is_empty(), "Should detect the new pattern");
    assert_eq!(issues[0].declaration.name, "expectedDeadCode");
}

2. Create Test Fixture

Create a Kotlin/Java file in tests/fixtures/ that demonstrates the pattern:

// tests/fixtures/kotlin/new_feature.kt
class NewFeatureExample {
    // Pattern to detect goes here
}

3. Implement the Detector

Implement the minimum code to make the test pass.

4. Refactor

Refactor while keeping tests green.

Test Categories

Unit Tests (in src/)

Each detector module has #[cfg(test)] mod tests:

  • sealed_variant: Tests sealed class detection
  • write_only: Tests write-only variable detection
  • unused_param: Tests unused parameter detection
  • unused_intent_extra: Tests Android Intent extra detection
  • ignored_return: Tests pure function detection
  • redundant_override: Tests override detection

Integration Tests

Located in tests/integration/analysis_test.rs:

  • test_dead_code_kotlin_fixture: Parses Kotlin with dead code
  • test_all_used_kotlin_fixture: Parses clean Kotlin code
  • test_java_fixture: Parses Java files
  • test_write_only_detector_on_fixture: Runs write-only detector
  • test_sealed_variant_detector_on_fixture: Runs sealed detector
  • test_reachability_analysis: Tests reachability analysis
  • test_multiple_files: Tests multi-file analysis

Adding New Tests

1. Unit Test for a Detector Method

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

    #[test]
    fn test_method_name() {
        let detector = MyDetector::new();
        // Create test data
        // Assert expected behavior
    }
}

2. Integration Test for Full Pipeline

#[test]
fn test_feature_integration() {
    let fixture = fixtures_path().join("kotlin/feature.kt");
    if !fixture.exists() {
        return;
    }

    let graph = build_graph_from_file(&fixture);
    // Run analysis
    // Assert results
}

3. Fixture-Based Test

  1. Add fixture file to tests/fixtures/
  2. Write test that loads and analyzes it
  3. Assert expected findings

Coverage

To generate coverage reports:

# Install cargo-llvm-cov
cargo install cargo-llvm-cov

# Generate coverage
cargo llvm-cov

# Generate HTML report
cargo llvm-cov --html

Benchmarks

# Run benchmarks
cargo bench

# Benchmark specific feature
cargo bench parsing

Continuous Integration

Tests run automatically on:

  • Push to main branch
  • Pull requests
  • Release builds

Best Practices

  1. Write tests first - TDD ensures better design
  2. Keep fixtures small - Minimal code to test the pattern
  3. Test edge cases - Empty files, malformed code, etc.
  4. Use descriptive names - test_skip_enum_classes not test1
  5. Assert specific behavior - Check names, locations, not just counts
  6. Keep tests fast - Unit tests should complete in milliseconds