Why Software Testing Exists: Evidence, Not Certainty
📑 On this page
- A concrete example: checkout
- Why exhaustive testing is difficult
- Tests make expectations executable
- Preventing regressions
- Tests support design
- Verification and validation
- The test oracle problem
- Positive and negative cases
- Boundary values
- Deterministic tests
- Test isolation
- Automated and exploratory testing
- Testing at different levels
- Coverage
- Testing in production
- Risk-based testing
- A failed test is information
- Maintaining the suite
- Knowledge check
- The one idea to remember
Software can behave correctly for a thousand cases and still fail on the next one.
A test exercises selected behavior under selected conditions. Passing results increase confidence, but they do not mathematically prove that every possible input, environment, timing, and interaction is correct.
Testing produces evidence about covered risks; it does not turn uncertainty into certainty.
The practical goal is to learn important failures early enough to correct them.
A concrete example: checkout
A checkout test verifies that a declined card shows a useful error and does not create an order.
That is valuable evidence, but it does not prove:
- keyboard users can complete checkout,
- inventory remains correct during simultaneous purchases,
- the page performs well during a sale,
- every payment-provider response is handled,
- or logs avoid exposing card data.
Different risks require different forms of testing and review.
Why exhaustive testing is difficult
Even a simple form can combine:
- many input values,
- browsers and devices,
- network speeds,
- account states,
- locales,
- time zones,
- permissions,
- and service failures.
The number of combinations grows rapidly. Teams therefore choose representative, boundary, high-risk, and historically troublesome cases rather than attempt every possible state.
Tests make expectations executable
A useful test states what the system should do in a concrete situation.
For example:
Given a coupon expires at midnight,
when checkout occurs after the expiry instant,
then the discount is not applied.The test can run repeatedly as the implementation changes. It becomes executable evidence that one expectation still holds.
Preventing regressions
A regression is behavior that used to work but breaks after a change.
Automated tests run known expectations repeatedly, making it easier to detect when a new feature damages an old one. This is especially important in shared systems where a local edit can affect distant consumers.
Tests make change cheaper by shortening the feedback loop.
Tests support design
Testing can reveal design problems before runtime defects appear.
Code that is difficult to test may have:
- hidden dependencies,
- excessive responsibilities,
- unclear inputs and outputs,
- global mutable state,
- or tightly coupled infrastructure.
Testability is not the only design goal, but clear boundaries often improve both testing and maintainability.
Verification and validation
Verification asks whether the software was built according to its specified behavior.
Validation asks whether the software solves the right user problem.
A perfectly implemented feature can still be confusing or unnecessary. Automated checks are strong at selected verification tasks; user research and product feedback contribute to validation.
The test oracle problem
A test needs an oracle: a way to decide what the correct result should be.
For a tax calculation, the oracle may come from a precise rule. For image quality, recommendation usefulness, or AI output, correctness may be subjective or multidimensional.
Weak expectations can make a test pass while the product remains poor.
Positive and negative cases
Positive tests confirm accepted behavior.
Negative tests confirm that invalid or unauthorized actions are rejected safely. A file upload feature should test valid files, but also oversized content, unsupported formats, malformed files, and access attempts from the wrong user.
Failure behavior is part of the product contract.
Boundary values
Defects often appear at transitions:
- zero versus one,
- just below versus exactly at a limit,
- the last day of a month,
- empty versus missing,
- or maximum storage capacity.
Boundary-value testing selects cases around these edges because they provide more information than many ordinary middle values.
Deterministic tests
A deterministic test produces the same result from the same controlled conditions.
Flakiness can come from:
- real time,
- random values,
- asynchronous races,
- shared data,
- network services,
- or reliance on test order.
Flaky tests weaken trust. Teams begin rerunning failures instead of investigating them, which can hide real defects.
Test isolation
Tests should control the state relevant to their result.
If one test leaves database records that alter another, failures depend on execution order. Isolation can come from transactions, unique identifiers, reset fixtures, temporary resources, or independent environments.
Isolation does not require replacing every real dependency; it means preventing accidental cross-test influence.
Automated and exploratory testing
Automated tests are repeatable and fast for known expectations.
Exploratory testing uses human observation and curiosity to discover risks the team did not encode in advance. A tester may notice confusing wording, inconsistent navigation, or an unexpected workflow combination.
Strong quality practice uses both: automation protects known ground while exploration searches beyond it.
Testing at different levels
Common levels include:
- unit tests for focused logic,
- integration tests for boundaries,
- end-to-end tests for critical workflows,
- performance tests for defined workloads,
- security tests for threats,
- accessibility tests for inclusive use,
- and usability tests for comprehension.
No single level replaces the others because each supplies different evidence.
Coverage
Code coverage reports which statements or branches executed during tests.
High coverage can reveal untested areas, but it does not show whether assertions were meaningful. A test may execute a calculation without checking its result.
Coverage is a diagnostic signal, not a quality score that should be optimized blindly.
Testing in production
Some behavior cannot be understood fully before production scale and real-world diversity.
Teams use:
- monitoring,
- canary releases,
- feature flags,
- synthetic probes,
- controlled experiments,
- and incident feedback.
This does not justify careless release. It recognizes that production observation is one layer in a broader testing strategy.
Risk-based testing
Testing effort should reflect impact and likelihood.
High attention belongs to areas such as:
- payments,
- authorization,
- irreversible data changes,
- public APIs,
- safety controls,
- and high-volume workflows.
A decorative icon does not need the same evidence as a money transfer, though both should meet their relevant standards.
A failed test is information
A failure may indicate:
- a product defect,
- an outdated expectation,
- a broken environment,
- flaky timing,
- or an incorrect test.
The response is investigation, not automatically changing code until green or deleting the test. Tests are models of expected behavior and models can be wrong.
Maintaining the suite
Test code is production-supporting code.
It needs:
- clear names,
- focused setup,
- stable data,
- useful failure output,
- removal of obsolete expectations,
- and reasonable execution time.
A slow, opaque suite becomes a release bottleneck and encourages bypass.
Knowledge check
- Why can a passing checkout test not prove checkout is universally correct?
- What is the difference between verification and validation?
- Why are boundary values especially useful?
- What does code coverage fail to measure?
- How do automated and exploratory testing complement each other?
The one idea to remember
Testing increases confidence by repeatedly checking selected behavior under selected conditions. Choose tests according to risk, keep their evidence trustworthy, and remember that no passing suite eliminates the need for review, observation, and user feedback.