Testing & Debugging (Unit, Integration, Selenium)

Chapter 2
Testing Theory, Principles, and Test Design

Bachelors Program in Full Stack Development
Testing & Debugging (Unit, Integration, Selenium)   •   Bachelor

Testing Theory, Principles, and Test Design

Introduction

Software testing is a systematic process of evaluating a software product or component and determining whether it satisfies specified requirements and supports its intended use. In full stack development, testing spans the browser, front-end components, APIs, business services, databases, authentication mechanisms, queues, and deployment configuration. Unit, integration, and Selenium-based system tests are not isolated activities; they are different levels of evidence in a broader quality strategy.

Testing cannot prove that software contains no defects. It provides information about risk, quality, behavior, and readiness by executing software, reviewing artifacts, and analysing results. Effective test design therefore requires more than writing many test cases. It requires selecting tests that are likely to reveal important failures, designing reliable expected results, and maintaining traceability between requirements, risks, tests, and defects.

Learning Objectives

By the end of this chapter, students should be able to:

  • explain fundamental testing principles;
  • apply the pesticide paradox and defect-clustering concepts;
  • use risk-based thinking to prioritize tests;
  • distinguish test oracles, test conditions, and traceability;
  • design tests using equivalence partitioning and boundary-value analysis;
  • represent business rules with decision tables;
  • test event-driven behavior using state-transition models;
  • reduce combinations through pairwise testing;
  • apply statement, branch, condition, and path-oriented white-box coverage;
  • evaluate the strengths and limitations of different test designs.

1. Testing as an Evidence-Based Engineering Activity

A test consists of inputs, preconditions, execution steps, and an expected result. A test fails when the observed result differs from the expected result or when the system violates an explicitly stated quality condition. A failure is an observable incorrect behavior; a defect or bug is a fault in a work product that can cause such a failure. A human mistake, such as misunderstanding a requirement, may introduce a defect.

Testing has several purposes:

  1. Verification: checking whether the product was built according to specified requirements and design.
  2. Validation: checking whether the product solves the users’ or stakeholders’ problem.
  3. Defect prevention: identifying ambiguous requirements, design weaknesses, and coding risks before execution.
  4. Risk information: informing release and maintenance decisions.
  5. Confidence building: supplying evidence that important behaviors work under defined conditions.

Testing differs from debugging. Testing exposes failures and supplies evidence about their location and impact. Debugging investigates the cause, changes the software, and verifies the correction. A successful retest shows that the specific failure has been corrected; regression testing checks that the correction has not damaged existing behavior.

Important testing terminology

TermMeaning
Test caseDefined inputs, conditions, actions, and expected results
Test conditionA testable aspect of a requirement, risk, or behavior
Test oracleA source used to determine whether an observed result is correct
Test dataValues and records used during testing
FailureObservable deviation from expected behavior
DefectA flaw in a work product that may cause a failure
Regression testA test repeated after change to detect unintended effects
CoverageThe extent to which a specified test element has been exercised

2. Fundamental Principles of Testing

The following principles guide professional testing practice.

Testing shows the presence, not the absence, of defects

A test can demonstrate that a particular input and execution path produced an incorrect result. Passing tests do not establish that all other inputs or paths are correct. Claims such as “the system is bug-free” are therefore not justified by ordinary testing evidence.

Exhaustive testing is impossible

The number of combinations of inputs, user roles, browsers, devices, network conditions, data states, and execution paths is usually too large to test completely. Test design must use selection strategies such as equivalence partitioning, boundary analysis, risk prioritization, and pairwise testing.

Early testing saves time and cost

Defects discovered in requirements or architecture are generally cheaper to correct than defects discovered after deployment. Reviews, static analysis, unit tests, contract tests, and continuous integration move feedback earlier in the development lifecycle.

Defects cluster

A relatively small number of components often contain a large proportion of discovered defects. Complex code, recently modified code, code with many dependencies, and historically unreliable modules deserve increased attention. This principle is a heuristic, not a guarantee: apparently stable components can still contain severe defects.

The pesticide paradox

If the same tests are repeated, they eventually lose effectiveness because they continue to exercise the same behaviors and may fail to expose new classes of defects. Test suites should therefore evolve. New data, exploratory testing, changed environments, mutation testing, and tests derived from recent incidents can reveal weaknesses that a static suite misses.

The metaphor does not mean that existing regression tests should be discarded. Stable tests protect known behavior; they should be supplemented and periodically reviewed.

Testing is context dependent

Safety-critical software, an online game, a banking API, and a student project have different risks, regulations, users, and acceptable failure consequences. There is no universally optimal test process or coverage threshold.

Absence-of-errors is a fallacy

A product may satisfy its documented requirements and still be unusable, inaccessible, insecure, or unsuitable for its real users. Testing must consider both conformance and fitness for purpose.

3. Risk-Based Thinking and Defect Clustering

Risk-based testing allocates effort according to the likelihood and consequence of failure. A practical qualitative model is:

Risk exposure = Likelihood × Impact

Likelihood expresses how plausibly a failure may occur; impact expresses the harm if it occurs. These are usually ranked, for example from 1 (low) to 5 (high), rather than treated as precise probabilities. The product is a prioritization aid, not a scientific prediction.

For example, a payment authorization defect may have likelihood 3 and impact 5, giving a relative exposure score of 15. A cosmetic alignment defect may have likelihood 4 and impact 1, giving 4. The payment behavior receives earlier and deeper testing. Teams should also consider detectability, regulatory obligations, business reputation, privacy, and safety; a simple multiplication cannot represent every concern.

Risk analysis commonly examines:

  • critical business functions;
  • sensitive data and authorization boundaries;
  • complex algorithms and integrations;
  • frequently changed modules;
  • third-party services;
  • unusual environments and failure recovery;
  • areas with a history of defects.

Defect clustering connects naturally with risk-based planning. If production data show that most failures arise in an order-pricing service, the test team should investigate its rules, interfaces, test data, and observability rather than distribute effort evenly across all components.

4. Test Oracles and Traceability

A test oracle determines whether an actual result is acceptable. The oracle may be a formal requirement, a business rule, a mathematical property, a reference implementation, a trusted database, a previous approved result, or a human expert.

Examples include:

  • Requirement oracle: “An account cannot withdraw more than its available balance.”
  • Metamorphic oracle: sorting a list twice should produce the same result as sorting it once.
  • Reference oracle: compare a new implementation with a trusted implementation.
  • Invariant oracle: after a transfer, total money across the two accounts remains constant, subject to defined fees.
  • User- interface oracle: keyboard focus must remain visible and follow a logical order.

An oracle problem occurs when it is difficult to know what the correct output should be. This is common in recommendation systems, image recognition, generative AI, and complex simulations. Properties, sampling, human review, and differential testing can reduce—but not eliminate—the problem.

Traceability links requirements to test conditions, test cases, results, and defects. A requirements-to-tests matrix might contain the following:

RequirementRiskTest identifiersResult
R-12: only verified users may payHighT-31, T-32, T-33Pass, pending security review
R-18: total includes taxHighT-40–T-43One failure
R-21: invalid email is rejectedMediumT-51–T-54Pass

Traceability supports impact analysis, auditability, coverage discussion, and release decisions. It should not become a bureaucratic list of test cases with no connection to risk or behavior. Links must be maintained when requirements change.

5. Black-Box Test Design Techniques

Black-box techniques derive tests from externally visible behavior without requiring knowledge of internal code. They are valuable at unit, API, integration, and system levels.

5.1 Equivalence partitioning

Equivalence partitioning divides input or output values into groups expected to be processed similarly. One or more representatives are selected from each partition. Partitions should be based on behavior, not merely on convenient numerical ranges.

Suppose an age field accepts integers from 18 through 65 inclusive. Useful partitions are:

  • less than 18: invalid;
  • 18 through 65: valid;
  • greater than 65: invalid;
  • non-integer, blank, or malformed values: invalid if the interface permits them.

Representative tests could be 17, 30, 66, blank, and “abc”. Partitioning reduces test volume, but it relies on the assumption that values within a partition behave equivalently. That assumption must be challenged when business rules contain hidden subranges.

5.2 Boundary-value analysis

Defects frequently occur at transitions between valid and invalid regions, because developers may use > instead of ≥, or confuse inclusive and exclusive limits. For a valid interval from 18 to 65, boundary tests include 17, 18, 19, 64, 65, and 66. A robust test set commonly includes the boundary, its nearest valid neighbor, and its nearest invalid neighbor.

For a password length rule of 8–20 characters inclusive, test lengths 7, 8, 9, 19, 20, and 21. Also test actual character content, because length alone does not establish validity.

5.3 Decision tables

Decision tables represent combinations of conditions and the actions expected for each combination. They are effective when rules involve multiple independent conditions.

Example: a discount applies when the customer is a member and the order total is at least £100.

RuleMember?Total ≥ £100?Discount?
1NoNoNo
2NoYesNo
3YesNoNo
4YesYesYes

The table exposes missing combinations and contradictions. In a real system, additional conditions—coupon validity, product exclusions, region, and date—may make the table large. Rules can then be simplified using “don’t care” symbols only when a condition truly cannot affect the action.

5.4 State-transition testing

State-transition testing models a system as states, events, guards, and resulting transitions. It is suitable for authentication, shopping carts, subscriptions, workflows, and asynchronous jobs.

An account might have states Unverified, Active, Locked, and Closed. An incorrect password event may keep an Active account active until a threshold is reached, then transition it to Locked. Tests should cover valid transitions, invalid events, repeated events, and recovery paths such as account unlocking. A frequent defect is testing each state independently while missing an illegal sequence of events.

Useful transition coverage questions include:

  • Has every state been entered?
  • Has every valid transition been executed?
  • Have invalid events been rejected?
  • Have transition guards and repeated events been tested?
  • Is persistence correct after restart or network interruption?

5.5 Pairwise testing

Pairwise, or 2-way combinatorial, testing selects combinations so that every pair of values from relevant factors appears at least once. It is useful when many configuration factors exist, such as browser, operating system, payment type, language, and user role. It does not guarantee detection of defects requiring interactions among three or more factors, nor does it replace risk-based tests for critical combinations.

For example, factors might be Browser {Chrome, Firefox}, OS {Windows, Linux}, and Role {User, Admin}. An all-combinations design contains 2 × 2 × 2 = 8 combinations. A pairwise design may use fewer rows while ensuring every pair of factor values occurs. Tools can generate such suites, but the resulting cases must be reviewed for impossible or unsafe combinations.

6. White-Box Testing and Coverage

White-box testing uses internal structure such as statements, branches, conditions, and control-flow paths. Coverage is a measurement of what the tests exercised, not a direct measurement of correctness.

Statement coverage

Statement coverage is:

Statement coverage = Executed statements ÷ Total executable statements × 100%

The numerator counts distinct executable statements reached by the test suite; the denominator counts executable statements in the selected scope. Assumptions include a clearly defined build and instrumentation method. A suite can achieve high statement coverage while missing an important branch.

Branch coverage

Branch coverage measures decision outcomes, such as true and false results of an if statement. For a decision with two outcomes:

Branch coverage = Executed branch outcomes ÷ Total branch outcomes × 100%

Consider:

if userIsVerified:
    if balance ≥ amount:
        approve()
    else:
        rejectInsufficientFunds()
else:
    rejectUnverified()

Tests should include an unverified user, a verified user with sufficient balance, and a verified user without sufficient balance. These execute all three meaningful outcomes and reveal behavior that a single happy-path test cannot.

Condition coverage and path concerns

Condition coverage requires each atomic Boolean condition to evaluate to true and false, although it may not require every decision outcome in every combination. Modified condition/decision coverage is stronger and is used in some regulated domains, but its exact definition and independence criteria must be specified.

Path coverage seeks to execute distinct control-flow paths. Complete path coverage is often infeasible because loops can create an enormous or unbounded number of paths. Test designers normally select basis paths, loop boundary cases, and risk-important paths. Coverage targets must be interpreted with code review, mutation testing, data-flow analysis, and defect history.

Coverage metrics can be misleading when tests execute code without checking meaningful outcomes. A test that calls an API and ignores the response increases execution coverage but provides weak evidence. Assertions, suitable oracles, and failure diagnostics are essential.

7. An Integrated Test-Design Process

A practical process for a new feature is:

  1. Read the requirement and identify ambiguity.
  2. Identify users, business rules, interfaces, data, and failure consequences.
  3. Build equivalence partitions and boundary lists.
  4. Express combinations in a decision table.
  5. Model states and events where behavior is sequential.
  6. Identify internal decisions for white-box tests.
  7. Prioritize tests using risk and defect history.
  8. Define reliable oracles and test data.
  9. Link tests to requirements and risks.
  10. Automate stable, repeatable checks at the appropriate level.
  11. Add exploratory, accessibility, security, performance, and recovery tests where relevant.
  12. Review failures, update regression tests, and remove obsolete cases.

Automation should not be confused with quality. Automated tests are valuable when they are deterministic, maintainable, fast enough for feedback, isolated where appropriate, and explicit about expected behavior. Selenium tests are particularly useful for critical user journeys, but they should not replace unit and API tests: browser tests are generally slower and more vulnerable to environmental instability.

8. Illustrative Case: Online Course Enrolment

Background

Consider an illustrative university course-enrolment service. A student may enrol when the course is open, places remain, prerequisites are satisfied, and the student has no financial or disciplinary block. The service exposes an API and a web interface.

Problem

The initial implementation passed its happy-path test but admitted students into full courses and sometimes displayed success after a database timeout. These failures affected capacity planning and student trust.

Analysis

A risk review rated capacity enforcement and transaction consistency as high impact. A decision table identified four conditions: course open, capacity available, prerequisite satisfied, and student blocked. Equivalence partitions were created for capacity: negative or corrupt value, zero, one remaining place, and more than one. Boundary tests focused on zero and one. A state model represented Requested, Enrolled, Rejected, and Pending states, including timeout and retry events.

White-box inspection identified branches for authorization, prerequisite checking, capacity checking, and persistence failure. Tests were designed for each branch and for the interaction between two simultaneous enrolment requests. The test oracle required that a successful response, an enrolment record, and a decremented capacity agree transactionally.

Approach and outcome

Unit tests checked the capacity and prerequisite rules. Integration tests exercised the service with a transactional database. API tests verified status codes and error bodies. Selenium tests checked that the browser showed a clear result and did not report success after a failed request. A concurrency test attempted two enrolments for the final place; exactly one was allowed.

The team also added traceability from the capacity requirement to the decision-table rules, API tests, database tests, and Selenium scenario. The resulting suite found the original defect and a second defect in retry handling. The final solution used an atomic database operation and an explicit Pending state for uncertain network outcomes.

Learning points

The case demonstrates that a happy-path test is inadequate, risk guides depth, boundaries expose off-by-one defects, state models reveal temporal failures, and an oracle must check system consistency rather than only a screen message. It also illustrates why tests should be distributed across levels rather than implemented solely through the browser.

9. Limitations, Ethics, and Contemporary Practice

Test selection is affected by time, data availability, tooling, and human judgment. Coverage targets can encourage superficial tests, while excessive end-to-end testing can produce slow and fragile pipelines. Test doubles may hide integration defects, whereas uncontrolled external dependencies reduce repeatability. Teams should state these limitations when reporting quality.

Testing also has ethical and governance responsibilities. Production data may contain personal or financial information; teams should use masked or synthetic data, control access, and retain only what is necessary. Security testing must be authorized and conducted within agreed boundaries. Accessibility testing should include keyboard use, screen readers where feasible, color contrast, focus behavior, and meaningful error messages. AI-generated test cases or code require human review because they may reproduce biased assumptions, miss critical boundaries, or expose confidential data to external services.

Contemporary practice combines unit and integration automation, contract testing, continuous integration, observability, mutation testing, property-based testing, exploratory testing, and production monitoring. These techniques complement rather than replace sound test design. The central professional question remains: what evidence is needed to make this decision, given the risks and intended use of the system?

Chapter Summary

Testing is an evidence-based activity that reveals failures, evaluates conformance and fitness for purpose, and informs risk decisions. Its principles include the impossibility of exhaustive testing, early testing, defect clustering, the pesticide paradox, context dependence, and the fallacy that an absence of detected errors proves quality. Risk-based testing prioritizes high-consequence and high-likelihood behavior. Test oracles define how correctness is judged, while traceability connects requirements, risks, tests, results, and defects.

Equivalence partitioning reduces redundant inputs; boundary-value analysis targets transition errors; decision tables expose combinations of business rules; state-transition testing addresses event sequences; and pairwise testing reduces configuration combinations while preserving pair interactions. White-box measures such as statement, branch, and condition coverage reveal exercised structure but do not guarantee meaningful assertions or correctness. Effective full stack testing combines these techniques at unit, integration, API, and browser levels, supported by ethical data handling, maintainable automation, and continuous review.

Key Terms

Testing: Systematic evaluation of software and related work products.

Verification: Checking whether specified requirements and designs were followed.

Validation: Checking whether the product satisfies intended user needs.

Defect: A flaw in a work product that may cause incorrect behavior.

Failure: An observable deviation from expected behavior.

Regression testing: Repeating tests after change to detect unintended effects.

Test oracle: A source for deciding whether an actual result is correct.

Traceability: Links among requirements, risks, tests, results, and defects.

Risk-based testing: Prioritizing testing according to likelihood and impact.

Defect clustering: The tendency for defects to be concentrated in a small number of components.

Pesticide paradox: Reduced effectiveness of an unchanged test suite against new defects.

Equivalence partitioning: Dividing inputs into behaviorally similar classes.

Boundary-value analysis: Testing values at and around input limits.

Decision table: A structured representation of condition combinations and actions.

State transition: A change from one system state to another caused by an event.

Pairwise testing: Selecting cases so every value pair across factors is exercised.

Statement coverage: The proportion of executable statements reached by tests.

Branch coverage: The proportion of decision outcomes exercised by tests.

Test data: Values and records supplied to the system under test.

Exploratory testing: Simultaneous learning, test design, and execution guided by risk.

Review Questions

Short Answer Questions

  1. Why can testing demonstrate the presence but not the absence of defects?
  2. Explain the pesticide paradox and state one way to address it.
  3. What is the purpose of a test oracle?
  4. Distinguish statement coverage from branch coverage.
  5. Why are boundary values important in test design?

Long Answer Questions

  1. Explain the principal testing principles and show how they influence a full stack test strategy.
  2. Describe how equivalence partitioning, boundary-value analysis, and decision tables can be combined for a business rule.
  3. Explain state-transition testing and apply it to an authentication workflow.
  4. Discuss the benefits and limitations of pairwise testing in browser and deployment matrices.
  5. Evaluate why high code coverage does not necessarily indicate high software quality.

Analytical / Application Questions

  1. An enrolment field accepts 1–6 modules, inclusive. Design equivalence partitions and boundary-value tests, including malformed input.
  2. A payment is approved only when the account is verified, the card is valid, and the amount does not exceed the limit. Construct a decision table and identify the minimum behaviorally distinct tests.
  3. A service has three configuration factors: browser, operating system, and user role. Propose a pairwise strategy, then identify one risk that still requires a targeted three-way test.

Multiple Choice Questions with Answers

Question 1

Which principle states that repeating an unchanged set of tests may stop revealing new classes of defects?

A. Absence-of-errors fallacy

B. Pesticide paradox

C. Defect clustering

D. Early testing

Correct Answer: B. Pesticide paradox

Question 2

For an inclusive valid age range of 18 through 65, which value is an invalid boundary-neighbor test?

A. 18

B. 19

C. 65

D. 66

Correct Answer: D. 66

Question 3

What is the primary purpose of a test oracle?

A. To generate random test data

B. To measure execution speed

C. To determine whether an actual result is acceptable

D. To replace debugging

Correct Answer: C. To determine whether an actual result is acceptable

Question 4

Which technique is most appropriate for representing combinations of business conditions and resulting actions?

A. Decision table testing

B. Statement coverage

C. Pairwise testing

D. Mutation testing

Correct Answer: A. Decision table testing

Question 5

A test suite executes 45 of 50 executable statements. What is its statement coverage?

A. 5%

B. 45%

C. 90%

D. 95%

Correct Answer: C. 90%

Question 6

What does pairwise testing guarantee when correctly constructed?

A. Every possible complete configuration

B. Every pair of selected factor values

C. Every control-flow path

D. Every boundary value

Correct Answer: B. Every pair of selected factor values

Question 7

Which testing technique is especially suitable for workflows involving states, events, and sequences?

A. State-transition testing

B. Equivalence partitioning

C. Statement counting

D. Static formatting

Correct Answer: A. State-transition testing

Question 8

Why is a high coverage percentage insufficient evidence of correctness?

A. Coverage tools cannot execute code

B. Coverage measures exercised structure, not necessarily meaningful assertions or valid behavior

C. Coverage applies only to documentation

D. Coverage always decreases after automation

Correct Answer: B. Coverage measures exercised structure, not necessarily meaningful assertions or valid behavior

Question 9

A payment defect has likelihood 3 and impact 5 on qualitative scales. What relative risk exposure results from the stated model?

A. 2

B. 8

C. 15

D. 53

Correct Answer: C. 15

Question 10

Which is the best example of traceability?

A. Linking a requirement to its risks, tests, results, and defects

B. Running only browser tests for every feature

C. Deleting tests after they pass

D. Using the same test data permanently

Correct Answer: A. Linking a requirement to its risks, tests, results, and defects

Testing & Debugging (Unit, Integration, Selenium)
Chapter 2 of 14