Back
Christof Jori

5 min read · 17 June 2024
Last reviewed

Next
Made on your device, with no Instagram connection. We copy the post link for Instagram’s Link sticker.

What Test-Driven Development Can and Cannot Prove

Test-driven development (TDD) is a way to develop software through short feedback cycles. A developer writes a test for the next behavior, sees it fail, implements enough code to make it pass, and then refactors while keeping the suite green. The method can make assumptions and expected behavior visible early. It does not make software defect-free, and it does not replace the other controls needed for a production system.

Building a Software Product?

 Book Free Consultation

What the TDD cycle actually promises

Martin Fowler describes the core loop as writing a test for the next piece of functionality, writing functional code until that test passes, and refactoring the code into a clearer structure. Teams often summarize this as red, green, refactor. The test should fail first for a meaningful reason. Otherwise, a passing result may show only that the test never exercised the intended behavior.

TDD provides a development discipline, not a coverage guarantee. A developer can omit an important scenario, assert the wrong outcome, mock away a risky integration, or preserve a flawed requirement perfectly. The useful claim is narrower: behavior represented by a meaningful test can receive fast regression feedback when the suite runs reliably.

The famous moth was not the origin of the word

In 1947, engineers working on Harvard's Mark II found a moth in a component and taped it into their logbook with the note "first actual case of bug being found." Grace Hopper was among the people working with the Mark II team. The episode helped popularize the computing terms "bug" and "debug," but it did not create the word "bug." The surviving logbook is not confidently attributed to Hopper personally.

The Mark II moth recorded in a Harvard logbook in 1947

The Mark II moth incident was recorded in 1947.

Where TDD can help

TDD is particularly useful when a team can express behavior through small, deterministic examples. It can help clarify interfaces, expose awkward coupling, support safe refactoring, and keep previously fixed behavior under automated review. It also creates concrete material for code review: reviewers can compare the stated behavior, the implementation, and the boundaries the test does not cover.

The economic result is context-dependent. TDD requires design and maintenance effort, and a brittle or slow suite can become a delivery cost of its own. Whether it saves money depends on defect risk, change frequency, system lifetime, test scope, feedback speed, and the cost of failure. A responsible business case measures escaped defects, lead time, flaky-test rate, suite duration, maintenance effort, and recovery outcomes instead of promising a universal saving.

Christof Jori

"Use tests to make important assumptions executable, then verify the risks those tests cannot cover."

Why passing tests do not prove correctness

A test suite evaluates selected inputs and expected outcomes. It cannot by itself prove the absence of defects. A green suite may still miss concurrency failures, malformed external data, dependency behavior, authorization gaps, production configuration, or an incorrect business rule. Coverage percentages also need interpretation: executing a line does not show that every important state transition or invariant was tested.

Choose techniques by risk. Unit tests are useful for local behavior. Contract and integration tests cover boundaries between components. Property-based tests and fuzzing explore inputs the team did not enumerate manually. Static analysis can find classes of implementation weakness without executing the program. Reviews, threat modeling, penetration testing, operational monitoring, and incident exercises address different parts of the system.

What changes for smart contracts?

Smart contracts can control valuable assets, expose public entry points, compose with external contracts, and operate under protocol-specific rules. Those characteristics raise the cost of an authorization, accounting, oracle, upgrade, or economic-design error. They do not make TDD a complete security method.

For EVM systems, a production verification plan can combine example-based unit tests with invariant or property tests, fuzzing, static analysis, forked-network integration tests, access-control review, compiler and dependency checks, and manual assessment of business logic and economic attacks. Front ends, APIs, wallets, indexers, databases, and operational controls need their own testing scope. An audit is additional evidence, not a guarantee that no exploit exists.

Illustration of testing effort across a software lifecycle

Testing effort and defect cost vary by system; treat the illustration as a concept, not a measured curve.

A practical review checklist

  • Behavior: Can the team state the important acceptance criteria and invariants before implementation?
  • Failure modes: Which malformed inputs, unavailable dependencies, permission errors, retries, and partial failures matter?
  • Test boundaries: What is real, mocked, simulated, or explicitly outside the suite?
  • Feedback: Does the suite run quickly and reliably enough to influence daily decisions?
  • Security: Which risks require static analysis, fuzzing, review, audit, monitoring, or operational controls beyond TDD?
  • Evidence: What launch gates and production signals show that the system behaves acceptably?

How to assess an engineering partner

Do not screen a team with a single ideological question such as whether it always uses TDD. Ask it to explain the testing strategy for your specific risks. A credible answer should identify what will be unit-tested, what needs integration or end-to-end evidence, how external systems will be represented, how flaky tests are handled, which security techniques supplement the suite, and which evidence blocks a release.

A project without automated tests does not inevitably die, just as a project with a large suite does not inevitably succeed. The decision is about risk and feedback. Test the behavior whose failure matters, keep the suite trustworthy, and use complementary controls for the parts a test cannot prove.

Sources

Final thoughts

TDD can turn intended behavior into fast, repeatable feedback. Its value comes from selecting meaningful tests and keeping the suite reliable. It cannot prove that software is correct or secure, so production teams should pair it with the testing, review, security, and operational controls that match the system's actual risks.

Build the product, not just the backlog

If this article maps to a real product decision, Wavect can help you scope, build, harden, or lead the software work with senior founder-level judgment.

Useful service paths:

Inbox, without the noise

Follow the work that matters to you

Get a short email when we publish something new. Follow the whole blog or only the problems you care about.

What would you like to receive?
Choose your topics

Free, double opt-in, no tracking pixels.

Back
Christof Jori

5 min read · 17 June 2024
Last reviewed

Next

Get the next Delivery and QA field note

One concise email when we publish. No tracking pixels, and no inbox filler.

Free, double opt-in, no tracking pixels.