Skip to content
Logo

Security Testing

Engineer/DeveloperSecurity SpecialistOperations & StrategyDevOpsSRE

Authored by:

Patrick Collins
Patrick Collins
Cyfrin
matta
matta
The Red Guild | SEAL

🔑 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

  1. Unit Testing: foundation coverage for functions, access control, and expected state changes.
  2. Integration Testing: forked and multi-system behavior vs real protocol state.
  3. Fuzz Testing: stateless and stateful (invariant) fuzzing.
  4. Static Analysis: pattern-based analysis without execution.
  5. Formal Verification: symbolic / mathematical property checking.
  6. Mutation Testing: suite quality via killed vs surviving mutants.

Further Reading