Case studies and Mini Project on Web App Development

Chapter 10
Testing, Debugging and Software Quality

Diploma in Full Stack Programming
Case studies and Mini Project on Web App Development   •   Diploma

Testing, Debugging and Software Quality

Introduction

A web application is not complete when its features merely appear to work on a developer’s computer. It is complete when its behaviour is sufficiently verified, its defects are controlled, its risks are understood, and it satisfies an agreed definition of done. Testing and debugging therefore form part of software engineering, not a final inspection activity.

For a full-stack application, quality must be considered across the browser, application server, APIs, databases, external services, deployment environment and human interaction. A reliable process combines automated tests with exploratory testing, code review, static analysis, observability and acceptance by stakeholders.

This chapter presents a practical quality strategy for diploma-level web development. It explains test levels, test design, debugging, automation, usability and acceptance testing, and the evaluation of reliability, maintainability and technical debt.

Learning Objectives

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

  • distinguish unit, integration, API, UI, usability and acceptance tests;
  • design useful test cases from requirements and risks;
  • apply debugging, code review and static-analysis practices;
  • construct an automated testing pipeline;
  • assess reliability, maintainability and technical debt;
  • define and evaluate a professional definition of done;
  • communicate test evidence and quality risks to a project team.

1. Quality as a Multi-Dimensional Property

Software quality is the degree to which a system satisfies stated requirements, user expectations and relevant engineering constraints. Correctness is important, but it is only one dimension. A web application can produce correct calculations and still be insecure, inaccessible, slow, difficult to maintain or confusing to use.

A useful quality model considers:

Quality attributeGuiding questionTypical evidence
Functional suitabilityDoes the system provide the required functions?Requirements tests, acceptance tests
ReliabilityDoes it operate consistently under expected conditions?Failure logs, recovery tests, monitoring
Performance efficiencyDoes it respond within acceptable limits?Response-time and load measurements
Usability and accessibilityCan intended users use it effectively?Usability sessions, accessibility checks
SecurityDoes it protect data and prevent unauthorised actions?Security tests, reviews, audit logs
MaintainabilityCan developers safely change it?Code review, complexity and testability assessment
CompatibilityDoes it work with supported browsers, devices and services?Compatibility matrix

Quality is not identical to the absence of defects. A requirement may be incomplete, a test may be weak, or an untested condition may hide a failure. Consequently, a test suite provides evidence about quality rather than a mathematical proof that the application contains no defects.

2. A Layered Testing Strategy

Testing is commonly organised into levels. The levels are complementary rather than interchangeable.

2.1 Unit Testing

A unit test verifies a small, isolated piece of code, such as a function, class method or validation rule. Dependencies are replaced with controlled test doubles when isolation is valuable. Unit tests should be fast, deterministic and numerous enough to cover important decisions.

For example, a password-validation function might be tested with valid passwords, short passwords, missing numbers and boundary lengths. A unit test should not require a real browser or production database merely to test a string rule.

Good unit tests have a clear arrangement:

  1. Arrange inputs and dependencies.
  2. Act by calling the unit.
  3. Assert the expected result or state change.

A unit test should normally verify observable behaviour rather than private implementation details. Tests that depend heavily on internal variable names or call order become expensive when the design is refactored.

2.2 Integration Testing

An integration test verifies that two or more components work together. Examples include an application service writing to a test database, an authentication module communicating with a token provider, or an API endpoint invoking business logic and persistence code.

Integration tests reveal configuration, schema, serialisation, transaction and dependency errors that unit tests may miss. They are usually slower and more sensitive to environment setup. A project should use isolated test databases or containers and should reset state between tests to prevent order-dependent failures.

2.3 API Testing

API testing examines an application’s externally accessible interface. Tests should check:

  • HTTP method and route;
  • status code;
  • response body and schema;
  • validation and error messages;
  • authentication and authorisation;
  • persistence effects;
  • pagination, filtering and sorting;
  • idempotence where relevant;
  • rate limits and security controls.

For example, a POST /orders test may verify that an authenticated customer receives a suitable success response, that invalid quantities are rejected, and that a customer cannot create an order for another account. Contract testing is especially useful when a frontend and backend are developed independently: it checks that the provider’s response remains compatible with the consumer’s expectations.

2.4 UI and End-to-End Testing

UI tests interact with the application as a user would, often through a real browser. They are appropriate for critical journeys such as registration, checkout or submitting an assessment. They can detect routing, rendering, form, browser and integration problems.

However, UI tests are slower and more fragile than unit tests. A small visual or wording change can break a selector. Therefore, a project should maintain a small set of high-value end-to-end tests and place most business-rule coverage at lower levels. Selectors based on accessible roles or stable test identifiers are preferable to selectors tied to layout details.

2.5 Usability Testing

Usability testing observes representative users attempting realistic tasks. It differs from UI automation: an automated test can confirm that a button exists, but only users can reveal that the button is misunderstood or difficult to find.

A usability session should define a task, recruit an appropriate participant, observe without leading, record errors and hesitation, and ask focused follow-up questions. Findings should be prioritised by user impact and frequency. Accessibility testing complements usability testing through keyboard navigation, semantic HTML, colour contrast, screen-reader checks and appropriate form labels.

2.6 Acceptance Testing

Acceptance testing determines whether the product satisfies business and user requirements. It is often conducted by a product owner, client, instructor or representative users. Acceptance criteria should be observable and testable. For example:

“Given an authenticated customer with an available account, when the customer submits a valid order, then the system displays an order number and stores the order with status ‘Pending’.”

This format makes preconditions, action and expected outcome explicit. Acceptance testing does not replace technical tests; it confirms that the implemented product solves the intended problem.

3. Test Design Techniques

A test case should identify an objective, preconditions, inputs, steps, expected results and evidence. Test design should be risk-based rather than based only on the number of lines of code.

Equivalence Partitioning and Boundary Values

Equivalence partitioning divides inputs into groups expected to behave similarly. For an age field accepting values from 18 through 65, useful partitions include below 18, 18–65, and above 65. Boundary-value analysis then gives special attention to 17, 18, 65 and 66, because defects frequently occur at transitions.

Decision Tables

A decision table represents combinations of conditions and actions. It is useful for rules such as discount eligibility, where membership status, order value and coupon validity jointly determine the result. The table exposes missing combinations and contradictory rules.

State-Transition Testing

Many web resources have states such as Draft, Submitted, Approved and Cancelled. State-transition tests verify permitted transitions and reject invalid ones. They should test both the normal path and attempts to bypass workflow rules through direct API calls.

Traceability and Coverage

A requirements-to-test matrix maps requirements to test cases and results. Coverage measures can help identify untested areas, but coverage percentage is not a quality score by itself. High statement coverage may still omit important input combinations, error handling, security controls or usability problems. Teams should ask what important risk remains untested, not merely whether a numerical threshold has been reached.

4. Debugging as Evidence-Based Diagnosis

Testing identifies a failure; debugging investigates its cause and supports a correction. A disciplined debugging process is more effective than changing code randomly:

  1. Reproduce the failure reliably.
  2. Record the exact inputs, environment, time and user action.
  3. Isolate the smallest failing scenario.
  4. Form a hypothesis about the cause.
  5. Use logs, breakpoints, traces and data inspection to test the hypothesis.
  6. Correct the underlying cause rather than masking the symptom.
  7. Add or improve a regression test.
  8. Re-run relevant tests and inspect for side effects.

A useful defect report includes a concise title, environment, reproduction steps, expected and actual results, severity, evidence and suspected scope. Logs should contain sufficient contextual information, such as a correlation identifier, but must not expose passwords, access tokens or unnecessary personal data.

Common causes of web defects include incorrect assumptions about null values, timezone conversion, asynchronous execution, database transaction boundaries, stale browser state, inconsistent validation between client and server, and differences between development and production configuration.

5. Code Review and Static Analysis

Code review is a structured examination by one or more developers before integration. Reviewers should assess correctness, security, readability, error handling, test quality, data access, accessibility and maintainability. A review is not a substitute for testing, because reviewers cannot execute every path; nor is testing a substitute for review, because tests may not expose poor design or vulnerable code.

Effective review practice includes small changes, a clear pull-request description, automated checks before human review, specific comments, and respectful discussion focused on the code. Authors should explain design decisions and include test evidence.

Static analysis examines source code or configuration without executing the application. Linters identify style and suspicious constructs; type checkers detect incompatible values; security scanners identify known vulnerable patterns or dependencies; formatters improve consistency. Static-analysis tools produce false positives and false negatives, so their findings require professional judgement. A project should establish which findings block merging and which are recorded for later remediation.

6. Test Automation and Continuous Integration

A practical automated pipeline usually performs the following sequence:

Software quality pipeline Code changebranch / pull request Static checkslint / types / security Automated testsunit / API / integration UI and acceptancecritical journeys Releaseor fix and repeat Fast feedback first; expensive evidence later A failure should stop or clearly gate the release decision.
Software quality pipeline from change to release decision
Figure: Software quality pipeline from change to release decision

Figure: A quality pipeline that combines automated checks with progressively broader tests.

Continuous integration runs these checks whenever changes are proposed or merged. Tests should be repeatable in a clean environment, and test data should be controlled. Flaky tests—tests that pass and fail without a relevant code change—must be investigated because they reduce trust in the pipeline. It is better to quarantine a known flaky test temporarily with an owner and deadline than to ignore it indefinitely.

7. Reliability, Maintainability and Technical Debt

Reliability concerns consistent service under specified conditions. Teams can monitor failed requests, recovery time, availability and recurring incidents. A simple availability measure is:

Availability = Uptime ÷ (Uptime + Downtime)

Uptime and downtime must refer to the same observation period and unit, such as minutes. Planned exclusions and definitions of an incident must be agreed in advance. For example, 99 hours of uptime and 1 hour of downtime produce 99 ÷ 100 = 0.99, or 99% availability. Availability alone does not describe correctness, performance or user impact.

Maintainability is the ease with which software can be understood, tested, modified and safely deployed. Evidence includes cohesive modules, meaningful names, low unnecessary coupling, clear interfaces, useful tests, documentation and manageable complexity. Maintainability is a socio-technical property: architecture, tooling, team knowledge and deployment practices all contribute.

Technical debt is the future cost created by expedient design or implementation choices. Examples include duplicated logic, obsolete dependencies, missing tests, weak monitoring and temporary workarounds. Debt is not automatically bad; a deliberate shortcut may be reasonable under a deadline if it is documented, bounded and repaid. Undocumented debt accumulates interest through slower changes, more defects and increased onboarding effort.

A debt register should record the issue, impact, owner, estimated effort, trigger for repayment and priority. Prioritisation should consider user and security risk, frequency of change, operational cost and dependency on the affected component.

8. Definition of Done

A definition of done is a shared, explicit standard for declaring work complete. A suitable web-project definition may require that:

  • acceptance criteria are satisfied and demonstrated;
  • unit, integration and relevant API tests pass;
  • critical UI journeys pass in supported browsers;
  • validation, authorisation and error handling are tested;
  • code review is approved;
  • static analysis and dependency checks meet agreed thresholds;
  • accessibility and usability risks have been assessed;
  • database migrations and rollback implications are documented;
  • logs, monitoring and operational instructions are updated;
  • known defects and technical debt are recorded with decisions;
  • the product owner accepts the result.

The definition should be realistic and continuously improved. It must not become a ceremonial checklist: each item should produce evidence or a recorded, consciously accepted exception.

9. Illustrative Case Study: Campus Equipment Booking Application

Background

A student team develops a web application through which students reserve cameras, laptops and laboratory equipment. The system includes a browser frontend, a REST API, a relational database and an administrator dashboard.

Problem

During a demonstration, two students reserve the last camera at nearly the same time. The interface reports success to both users, while the database contains only one available item. In addition, an administrator can see a reservation belonging to another department, and users report that the date-picker is difficult to operate with a keyboard.

Analysis

The first symptom indicates a concurrency or transaction problem rather than a simple display defect. The authorisation issue requires an API-level test because hiding a button in the frontend is not a security control. The keyboard complaint requires observation with representative users and accessibility inspection.

The team reproduces the race using two simultaneous API requests and records request identifiers. Code review reveals that availability is checked in one database operation and the reservation is inserted in a separate operation. The team also discovers that the API filters reservations only by item identifier, not by the authenticated user’s department.

Approach and Solution

The team adds:

  1. an integration test that sends competing reservation requests;
  2. a database transaction with an appropriate constraint or locking strategy so that only one valid reservation can succeed;
  3. an API test confirming that cross-department data is rejected or excluded;
  4. a regression test for every corrected defect;
  5. keyboard-accessible date controls with labels and visible focus indicators;
  6. an acceptance scenario covering successful booking, conflict feedback and cancellation;
  7. monitoring for failed reservation attempts and unexpected server errors.

The team reviews the change, runs static analysis, executes the complete pipeline and performs a usability session with students and an administrator.

Outcome

Only one competing request succeeds, while the other receives a clear conflict response. Unauthorised reservation data is no longer returned. Keyboard users can complete the booking journey, although the team records a future improvement to support a wider range of assistive technologies. The release is accepted because critical risks are controlled and remaining limitations are documented.

Learning Points

The case demonstrates that quality requires multiple forms of evidence. Unit tests alone would not expose the database race, API tests are needed for authorisation, and automation cannot replace usability evaluation. The definition of done connects these activities to a release decision.

10. Challenges, Ethics and Contemporary Practice

Testing effort is limited, so teams must prioritise functions whose failure could cause financial loss, privacy harm, safety problems or serious disruption. Personal data used in tests should be minimised, anonymised or synthetic. Test accounts must be protected, and production data should not be copied casually into development environments.

Security testing must be authorised and conducted within scope. Logs and test reports can contain personal or confidential information and should follow applicable privacy and data-protection requirements. Accessibility is an ethical and often legal responsibility, not an optional enhancement.

AI-assisted coding and test generation can suggest cases, identify patterns or produce test scaffolding. Its output must be reviewed because generated tests may encode incorrect assumptions, omit edge cases, reproduce insecure code or create a false impression of coverage. Teams remain accountable for the software and the data used with such tools.

Contemporary quality practice increasingly combines shift-left testing—finding problems early—with production observability and controlled shift-right validation, such as feature flags, canary releases and real-user monitoring. These practices reduce release risk but do not justify releasing inadequately tested software.

Chapter Summary

Testing web applications requires a layered strategy. Unit tests isolate logic; integration tests verify collaboration among components; API tests examine contracts, security and persistence; UI tests validate critical browser journeys; usability testing studies human interaction; and acceptance testing confirms business fitness. Test design should use boundaries, partitions, decision tables and state transitions, while risk and traceability guide coverage decisions.

Debugging is an evidence-based process of reproducing, isolating, hypothesising, correcting and regression-testing failures. Code review and static analysis provide complementary safeguards. Continuous integration creates fast, repeatable feedback, but flaky tests and weak test data must be actively managed. Reliability, maintainability and technical debt require operational and architectural evidence, not just a passing test percentage. A clear definition of done turns quality expectations into a shared release standard.

Key Terms

Unit test: A test of a small, isolated code unit.

Integration test: A test of interactions between components.

API test: A test of an application programming interface and its contract.

UI test: A test of behaviour through a user interface.

Usability testing: Observation of representative users performing tasks.

Acceptance test: A test determining whether business requirements are met.

Regression test: A test repeated to ensure a defect has not returned.

Test double: A substitute for a real dependency in a test.

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

Decision table: A structured representation of conditions and resulting actions.

State transition: A movement from one permitted system state to another.

Code review: Human examination of proposed source-code changes.

Static analysis: Automated examination of code without executing it.

Continuous integration: Frequent integration supported by automated checks.

Flaky test: A test whose result changes without a relevant code change.

Reliability: Consistent operation under specified conditions.

Maintainability: Ease of understanding, changing and safely deploying software.

Technical debt: Future cost caused by expedient or deficient technical choices.

Definition of done: Shared criteria for declaring work complete.

Observability: Ability to understand system behaviour from logs, metrics and traces.

Review Questions

Short Answer Questions

  1. What is the main difference between a unit test and an integration test?
  2. Why should API authorisation be tested independently of frontend visibility?
  3. What is the purpose of a regression test?
  4. Name two activities commonly included in static analysis.
  5. Why is test coverage percentage not, by itself, a quality score?

Long Answer Questions

  1. Explain how unit, integration, API, UI, usability and acceptance testing complement one another in a web application.
  2. Describe a disciplined debugging process and explain why reproducing the failure is important.
  3. Discuss the benefits and limitations of continuous integration and automated testing.
  4. Explain reliability, maintainability and technical debt, including appropriate evidence for evaluating each.
  5. Design a definition of done for a small online booking application and justify each criterion.

Analytical / Application Questions

  1. An API reports successful stock reservations to two users when only one item remains. Design tests that would reproduce the problem, identify its cause and verify the correction.
  2. A project has 95% automated statement coverage but frequent production failures in permissions and accessibility. Analyse why the metric is insufficient and propose a revised quality strategy.
  3. A team wants to copy real customer data into a test database to make UI tests realistic. Evaluate the technical, ethical and governance risks and recommend an alternative approach.

Multiple Choice Questions with Answers

Question 1

Which test level is most appropriate for verifying a password-validation function in isolation?

A. Unit testing

B. Usability testing

C. Acceptance testing

D. Load testing

Correct Answer: A. Unit testing

Question 2

What is the primary purpose of an API authorisation test?

A. To verify page colours

B. To verify that users can access only permitted resources

C. To measure developer productivity

D. To check source-code formatting

Correct Answer: B. To verify that users can access only permitted resources

Question 3

Which technique gives special attention to inputs at and around an allowed limit?

A. Random testing

B. Boundary-value analysis

C. Code review

D. Snapshot testing

Correct Answer: B. Boundary-value analysis

Question 4

A test that passes and fails without a relevant code change is called what?

A. A mutation test

B. A flaky test

C. A contract test

D. A smoke test

Correct Answer: B. A flaky test

Question 5

Which activity observes representative users attempting realistic tasks?

A. Static analysis

B. Unit testing

C. Usability testing

D. Dependency scanning

Correct Answer: C. Usability testing

Question 6

If uptime is 99 hours and downtime is 1 hour in the same observation period, what is availability?

A. 1%

B. 50%

C. 99%

D. 100%

Correct Answer: C. 99%

Question 7

What is the best reason to keep most business-rule tests below the UI level?

A. Lower-level tests are generally faster and less fragile

B. UI tests cannot run in browsers

C. Business rules do not need verification

D. Acceptance testing replaces all lower-level tests

Correct Answer: A. Lower-level tests are generally faster and less fragile

Question 8

Which item is most suitable for a definition of done?

A. The developer believes the feature looks complete

B. Critical tests pass and acceptance criteria are satisfied

C. The application has no possible defects

D. The code contains a fixed number of comments

Correct Answer: B. Critical tests pass and acceptance criteria are satisfied

Question 9

What should normally be added after correcting a confirmed defect?

A. A regression test

B. A new unrelated feature

C. A production password in the log

D. Removal of all automated tests

Correct Answer: A. A regression test

Question 10

Why should real customer data generally not be copied casually into test environments?

A. It always makes tests slower

B. It may expose personal or confidential information

C. It prevents unit tests from compiling

D. It eliminates the need for acceptance testing

Correct Answer: B. It may expose personal or confidential information

Case studies and Mini Project on Web App Development
Chapter 10 of 15