Static Analysis Testing
What it is
Section titled “What it is”Static analysis examines source code without executing it. It is the cheapest test you can run: it is fast, deterministic, and catches whole categories of defects — type errors, unused code, unreachable branches, unsafe patterns — before a single test runs.
It sits at the base of the pyramid: every issue caught here is an issue you never need a unit or E2E test to find.
When to use it / when to avoid it
Section titled “When to use it / when to avoid it”Use it always. Static analysis belongs in the editor, in a pre-commit hook and in CI. It is the first gate in every pipeline.
Tune, do not remove, when
- Rules produce false positives → downgrade to warnings, or scope them
- Legacy code cannot pass → ratchet (fail only on new violations), do not disable globally
Static analysis cannot check runtime behaviour, data-dependent logic, or integration contracts — those still need dynamic tests.
Frameworks & tools
Section titled “Frameworks & tools”| Tool | Kind | Ecosystem |
|---|---|---|
TypeScript (tsc --noEmit) |
Type checker | JS/TS |
| mypy / pyright | Type checker | Python |
| ESLint | Linter | JS/TS |
| Biome | Linter + formatter | JS/TS |
| Ruff | Linter + formatter | Python |
golangci-lint / go vet |
Linter | Go |
| Error Prone / Checkstyle | Linter | Java |
| Roslyn analyzers | Linter | .NET |
| Clippy | Linter | Rust |
| SonarQube / SonarCloud | Quality platform | Multi-language |
| CodeQL | Semantic SAST | Multi-language |
| Semgrep | Pattern-based SAST | Multi-language |
| Bandit (Python), gosec (Go) | Security linters | per-language |
Quick setup
Section titled “Quick setup”npm install -D typescript eslint # or: npm install -D @biomejs/biomenpx tsc --noEmitnpx eslint .pip install mypy ruffmypy src/ruff check .go vet ./...golangci-lint run<!-- Maven: run Checkstyle + Error Prone in the build -->mvn -q checkstyle:checkdotnet build /p:TreatWarningsAsErrors=truedotnet format --verify-no-changesExample
Section titled “Example”// `tsc` flags this before any test runs:function greet(name: string): string { return `Hello, ${name}`;}greet(42); // error TS2345: number is not assignable to stringdef greet(name: str) -> str: return f"Hello, {name}"
greet(42) # mypy: Argument 1 has incompatible type "int"var n int = "x" // compile error: cannot use "x" as intString s = 42; // compile error: incompatible typesint n = "x"; // error CS0029: cannot implicitly convert string to intAnti-patterns & best practices
Section titled “Anti-patterns & best practices”- Run it in the editor and CI. Feedback must be immediate and mandatory.
- Fail the build on errors. “We’ll fix it later” means never.
- Ratchet, do not silence.
# type: ignore,// @ts-ignoreand// nolintshould be rare and justified — never to make a red pipeline green. - Layer type checking and linting. They catch different classes of defects.
- Add semantic SAST (CodeQL/Semgrep) for security-relevant code.
Self-assessment quiz
Section titled “Self-assessment quiz”Self-assessment quiz
Pick one answer per question, then press Check answers.