Soren Learning

Chapter 1

Introduction to Software Testing

Listen to this article

Every piece of software ever shipped has had bugs. The interesting question is not whether your code has defects — it does — but how quickly and cheaply you can find them. That is what testing is for.

What Testing Actually Is

At its simplest, a test is an executable claim about how your system behaves. You write a piece of code that asserts something should be true — "when a user logs in with correct credentials, they receive a session token" — and the test framework runs your real code against that claim. If reality disagrees with the claim, the test fails and tells you.

This is a narrower definition than most people carry around. Testing is not "clicking around the UI to see if it works." That is manual exploration, which has its place but is not what we mean here. Testing, as a practice, produces artifacts — code that runs automatically, gives binary pass/fail results, and can be run thousands of times a day.

Why Testing Matters: The Economics of Defects

The classic argument for testing is cost. The cost of fixing a defect grows — non-linearly — the later it is caught. The often-cited Capers Jones and IBM data suggests the ratios look roughly like this:

Stage caught Relative cost
While coding 1x
During code review ~5x
During QA / system test ~10x
In production 30x–100x+

The exact numbers vary by study, but the shape is consistent. A bug caught by a unit test on your laptop costs you a minute. The same bug, caught by a customer after a release, can cost you an incident response, a rollback, a support ticket, a post-mortem, and — if you are unlucky — a contract.

This is why "we don't have time for tests" is almost always false economics. You have time for some testing; the question is whether it happens before or after your users find the bug.

Verification vs. Validation

Two words that sound interchangeable but are not:

  • Verification asks: "Are we building the thing right?" Does the code do what the spec says? This is the domain of unit tests, integration tests, static analysis, and type checking.
  • Validation asks: "Are we building the right thing?" Does the spec, and the software that implements it, actually solve the user's problem? This is the domain of user testing, acceptance testing, and production analytics.

Most engineering teams are reasonably good at verification and noticeably weak at validation. You can have 100% test coverage on a feature nobody uses. Tests protect you from regressions, not from building the wrong product.

Quality Attributes: Testing Is Not Just About Functions

When people say "does it work?" they usually mean "does the happy path return the expected output?" Real quality is broader. Common quality attributes — sometimes called non-functional requirements — include:

  • Functional correctness — the code produces the right outputs for given inputs.
  • Performance — acceptable latency, throughput, and resource use under load.
  • Reliability — the system stays up under partial failure (a database blip, a slow network).
  • Security — the system resists unauthorized access, data leaks, and injection.
  • Usability — users can actually accomplish their goals.
  • Accessibility — the system works for users with disabilities (screen readers, keyboard-only, low vision).
  • Maintainability — future engineers can understand and change the code without breaking it.

Each attribute has its own testing style. Functional tests cover correctness. Load tests cover performance. Penetration tests cover security. An integrated testing strategy considers all of them — not just whether login() returns true.

The Cultural Shift: Quality as a Team Property

The traditional model of software delivery treated quality as a stage and a role. Developers wrote code, threw it over the wall to QA, QA found bugs, threw it back, and eventually something shipped. This model has two fatal problems:

  1. Feedback is slow. By the time QA finds a bug, the developer has moved on, context is cold, and fixing it costs 10x more than catching it at the keyboard.
  2. Responsibility is diffused. Developers think "QA will catch it." QA thinks "developers should have tested this." Nobody owns quality end-to-end.

Modern software development pushes quality left — earlier in the pipeline — and wider — across everyone involved. Developers write unit and integration tests. SRE teams own reliability tests. Security engineers automate vulnerability scans. Product managers write acceptance criteria. QA specialists (where they exist) focus on exploratory testing, test strategy, and the hard-to-automate edges.

The slogan is "quality is everyone's job." The operational reality is that testing becomes part of the definition of "done" for every change, not a separate phase.

Common Objections — And Why They Are Wrong

"Tests slow us down." In the short term, yes — by the time it takes to write them. In the medium term, tests are what let you refactor aggressively and ship on Friday afternoon. Teams without tests move fast until they hit the wall of fragility, then they grind to a halt.

"Tests are just duplicate code." A test and the code it tests look similar but serve different purposes. The code does something; the test describes what it should do. When they drift apart, the test tells you.

"We have good developers, we don't need tests." Even the best developers have off days, misread requirements, and make typos. Tests are not a commentary on your skill; they are a safety net for the inevitable moments when skill alone is not enough.

"Manual testing is enough." Manual testing is necessary but not sufficient. It does not scale — you cannot manually re-test 500 features every time you push a button. Automation is what makes continuous delivery possible.

What Good Looks Like

A team with a healthy testing practice can usually answer "yes" to all of these:

  • Can any engineer run the full test suite locally in under a few minutes?
  • Does the CI pipeline block merges on test failures?
  • When a production bug is found, is the first step to write a failing test that reproduces it?
  • Is test code reviewed with the same rigor as production code?
  • Do flaky tests get fixed or deleted — not ignored?
  • Does the team trust its tests enough to deploy on green?

If the answer to most of these is "yes," testing is working. If not, the next six chapters are for you.

What's Next

The rest of this series moves from this high-level "why" into the "how." The next chapter introduces the testing pyramid — the mental model that explains where different kinds of tests fit, how many of each you should have, and what happens when the pyramid gets inverted.


Next: The Testing Pyramid & Types of Tests — unit, integration, end-to-end, and why the shape matters.