Security Testing
🔑 Key Takeaway: No single test type proves smart contracts safe. Combine coverage-focused unit and integration tests, fuzzing, static analysis, and—where warranted—formal methods, then measure the suite with mutation testing.
Security testing aims to find vulnerabilities and behavioral regressions before attackers or production users do. Full freedom from defects is not a realistic guarantee; layered testing raises confidence and reduces missed classes of bug.
This framework focuses on approaches commonly applied to smart contracts (Solidity examples appear in child pages). Types overlap—for example a unit test can also be a fuzz test.
Testing types
- Unit testing: individual components or functions
- Integration testing: interaction between components or external systems (often fork tests)
- Fuzz testing: random or unexpected inputs to break assumptions
- Static analysis: examine code without executing it
- Formal verification: mathematical methods to prove properties of algorithms and protocols
- Mutation testing: evaluate whether the suite detects intentional faults
Goal
Identify vulnerabilities and weaknesses while confirming behavior still holds after change. Choice of depth depends on asset risk, complexity, and resources—there is no universal single method.
Smart contracts: when to use each type
- Unit testing: always; aim for high path coverage
- Integration testing: always; often combined with fork testing
- Fuzz testing: always where practical; many unit tests can become fuzzer targets
- Static analysis: always; tools such as Slither and Aderyn are common baselines
- Formal verification: situation-dependent—especially math-heavy logic, critical invariants, or parity with a reference model
- Mutation testing: use to measure whether existing tests would catch realistic faults
Evaluating the test suite
- Coverage analysis: code and branch coverage reduce blind spots (coverage alone does not prove meaningful assertions).
- Mutation testing: introduce small code mutations; tests that still pass indicate weak assertions or missing cases.
What this framework covers
- Unit Testing: foundation coverage for functions, access control, and expected state changes.
- Integration Testing: forked and multi-system behavior vs real protocol state.
- Fuzz Testing: stateless and stateful (invariant) fuzzing.
- Static Analysis: pattern-based analysis without execution.
- Formal Verification: symbolic / mathematical property checking.
- Mutation Testing: suite quality via killed vs surviving mutants.
Related frameworks
- Secure Software Development: reviews and coding standards
- DevSecOps: pipeline automation of tests and scanners
- External Security Reviews: independent audits beyond internal testing
- Threat Modeling: which behaviors and assets tests must protect
- Supply Chain: tooling trust and dependency risk in the test stack
Further Reading
- Cyfrin Updraft Security Testing (curriculum referenced by several child pages)
- Foundry Book
- Trail of Bits — Building secure contracts