# Testing content-driven web app backends

Testing the backend of a web application is a critical part of the development
process and any ongoing monitoring. Also, see testing for the
[frontend](https://developers.google.com/solutions/content-driven/frontend/testing).

## Test-driven development

In [Test-Driven
Development](https://en.wikipedia.org/wiki/Test-driven_development)
(TDD), application requirements are translated into test cases before an
application is fully implemented. During development, these tests are written
first and successively implemented as the application is built. Clear
requirements (ie. test cases) ensure that the final code is well structured,
meets all requirements, and is correct, which is especially important during the
early stages of development.

## Continuous Integration and Automated Testing

Continuous integration (CI) testing automatically runs tests against any code
changes, such as during code reviews or when code has been merged into your code
repository. Automated tests improve the overall quality and confidence in the
submitted code by reducing the risks of breakages or regressions during
development. It is recommended to set up an automated testing system for your
environment to ensure the health of your application. Use a system supported by
your architecture, platform, and language and seamlessly integrated into your
development pipeline; for example, use [GitHub Actions for a CI
workflow](https://docs.github.com/en/actions/automating-builds-and-tests/about-continuous-integration)
or a [custom CI pipeline built-in the
cloud](https://cloud.google.com/solutions/continuous-integration), customized
for your configuration.

Learn more [about the principles behind automated
testing](https://dora.dev/devops-capabilities/technical/test-automation/)
and how to improve your tests. Learn more [about continuous integration
testing](https://dora.dev/devops-capabilities/technical/continuous-integration/)
and the best practices for implementing, setting up, and measuring success.

As the next step, consider an [automated continuous delivery (CD)
pipeline](https://developers.google.com/solutions/content-driven/backend/deployment#cd-and-ci) to
automatically deploy changes and updates to your application.

## Unit testing

[Unit testing](https://en.wikipedia.org/wiki/Unit_testing) refers
to testing small, self-contained parts of code in isolation. Use a unit testing
framework that is recommended and popular for your backend language or
framework. For example, for a monolithic Java-based application, use JUnit, or
for a JavaScript-based serverless application (including Dart or TypeScript),
use a framework built for Javascript testing, such as
[Jest](https://jestjs.io/).

Most modern backend frameworks have dedicated resources for testing. Consider
integrating these features into your CI pipeline to automate testing. Ensure
that your unit tests provide good [code
coverage](https://en.wikipedia.org/wiki/Code_coverage) of your
application. Most testing frameworks provide features to analyze and report on
your test coverage and allow for integration into your build pipeline.

## Integration testing

[Integration
testing](https://en.wikipedia.org/wiki/Integration_testing) refers
to testing larger modules or parts of your application together. Compared to
unit testing (which focuses on individual parts of code), integration testing
focuses on the integration of individual parts of your architecture. This may
also include end-to-end flows covering multiple steps and modules across the
application.

Integration tests may cover different modules of your application that may
require interaction with external services, such as data storage, filesystems,
or payments. Consider structuring your application to support abstractions for
these services through [dependency
injection](https://en.wikipedia.org/wiki/Dependency_injection) or
similar features provided by your backend framework.

## Behavior and functional testing

Approaching the backend (or individual modules or components) as an opaque box,
[functional
testing](https://en.wikipedia.org/wiki/Functional_testing) focuses
on the input and output of the system. While behavioral testing may be more
common for the frontend, it also plays a vital role in confirming the end-to-end
integrity of a backend system. These types of tests confirm that the system
reacts and behaves as expected to different inputs.

## Regression testing

[Regression
testing](https://en.wikipedia.org/wiki/Regression_testing) refers
to tests that confirm that the application still behaves as expected. Tests
successfully completed previously are re-run for any new changes to ensure that
the changes have not reintroduced any previous issues. As bugs get fixed in an
application, unit or integration tests should be added to ensure the bug doesn't
recur. Regression tests should be integrated into the usual testing and build
pipeline.

## Smoke testing

[Smoke
testing](https://en.wikipedia.org/wiki/Smoke_testing_(software)),
also called build verification testing, focuses on verifying the most critical
functions of your backend application. Extending beyond integration testing,
which abstracts some features and external dependencies, smoke testing covers
the critical use cases for your application. Smoke testing can serve as an
additional layer of verification before an application is promoted to the
staging environment to ensure accurate behavior. Smoke tests may consist of
automated unit tests or manual functional tests conducted by a QA team.

## Production and staging environments

A staging environment is a copy of your production environment, sandboxed to
facilitate testing. A dedicated deployment reduces the risk of issues with the
production environment and makes it easier to conduct quality assurance. The
staging environment lets you test a system close to the live production
environment.

Having a 1-for-1 copy of the production environment may not be feasible due to
factors such as cost or the complexity of the backend architecture. Consider
what parts of the backend are the most critical and optimize those for a staging
environment.

Testing against data used in production offers a great benefit to test how the
application behaves with real-world data. Be sure to consider the privacy
implications and data storage needs for such a staging environment, and
carefully design the data used by your backend system. Access to such an
environment should be tightly controlled, especially if production data is used.

Consider the scale of your system and whether a standing environment is
appropriate for your application. Rolling staging environments that can be
automatically deployed through a [continuous delivery
system](https://developers.google.com/solutions/content-driven/backend/deployment#cd-and-ci) also offer
additional opportunities to test daily or weekly builds and give them additional
scrutiny before release.

Another approach is to rely more heavily on continuous integration tests and
automated systems rather than a fully deployed staging environment. Consider
your team's workflow, system health, code coverage, and technical requirements.