Testing, Security, and Deployment
Ensure quality, secure your app, containerize, automate, and deploy to cloud platforms with confidence.
Content
Unit tests and coverage
Versions:
Watch & Learn
AI-discovered learning video
Sign in to watch the learning video for this topic.
Unit Tests and Coverage — The Safety Net for Web Apps
You already built components in React, routed pages, and talked to Flask APIs. Great — now let’s stop breaking production and actually test the things.
This lesson covers unit tests and coverage for both sides of your CS50 web app: backend (Python/Flask) and frontend (JavaScript/React). We assume you’ve already practiced component testing in React; here we connect that knowledge to unit-test design, coverage metrics, and how to enforce them during deployment.
Why unit tests + coverage matter (and why your future self will thank you)
- Unit tests check small pieces of logic in isolation — functions, methods, components. They prevent regressions and document intended behavior.
- Coverage measures how much of your code the tests exercise. It’s not justice — high coverage ≠ perfect tests — but it’s a useful safety gauge.
Imagine shipping a new React hook that fetches user data and accidentally deleting the auth header. No tests → silent failure in production. A good unit test catches that during CI and saves embarrassed Slack messages.
Quick terminology micro-explainer
- Unit test: test for a single unit (function, method, component)
- Mocking: replacing dependencies (like network calls) with fakes
- Fixtures: reusable test setup (pytest fixtures or jest beforeEach)
- Coverage types: line, branch, function, statement
Tools of the trade (CS50 stack)
- Python/Flask: pytest + pytest-cov (coverage.py under the hood)
- JavaScript/React: jest + React Testing Library + built-in coverage (Istanbul)
- CI: GitHub Actions (or Travis/Heroku pipelines) + Codecov/coveralls optional
Backend examples — pytest + coverage
Project layout (snippet):
project/
app/
__init__.py
views.py
utils.py
tests/
test_utils.py
test_views.py
pytest.ini
.coveragerc
pytest.ini (basic config):
[pytest]
python_files = tests/*.py test_*.py *_test.py
Sample unit test for a Flask endpoint using the test client and a fixture:
# tests/test_views.py
import pytest
from app import create_app
@pytest.fixture
def client():
app = create_app({'TESTING': True})
with app.test_client() as client:
yield client
def test_ping(client):
res = client.get('/ping')
assert res.status_code == 200
assert res.json == {'ping': 'pong'}
Test for a pure function with mocking:
# app/utils.py
import requests
def fetch_data(url):
r = requests.get(url)
return r.json()['value']
# tests/test_utils.py
from unittest.mock import patch
@patch('app.utils.requests.get')
def test_fetch_data(mock_get):
mock_get.return_value.json.return_value = {'value': 42}
assert fetch_data('http://example') == 42
Run coverage:
pytest --cov=app --cov-report=term-missing
# generate HTML report
pytest --cov=app --cov-report=html
# open htmlcov/index.html
You can exclude files or dirs in .coveragerc and mark lines with # pragma: no cover for generated code.
Frontend examples — jest, React Testing Library, and coverage
package.json scripts:
"scripts": {
"test": "react-scripts test --env=jsdom",
"coverage": "react-scripts test --coverage --watchAll=false"
}
Simple test for a component (building on your previous component tests):
// src/__tests__/Greeting.test.js
import { render, screen } from '@testing-library/react'
import Greeting from '../Greeting'
test('shows greeting with name', () => {
render(<Greeting name="Ava" />)
expect(screen.getByText(/hello, ava/i)).toBeInTheDocument()
})
Run coverage:
npm run coverage
# or
yarn coverage
Coverage output shows statements, branches, functions, and lines. The React scripts produce a nice HTML report in coverage/lcov-report.
Interpreting coverage: what to shoot for
- 70–85%: reasonable for small projects.
- 90%+: great but expensive — focus on meaningful tests instead of trivial ones.
- Branch coverage matters when logic has many if/else paths.
Remember: coverage is a metric, not a goal. A bogus test can bump coverage without improving quality.
Best practices: tests people actually love (or at least tolerate)
- Name tests clearly:
test_transform_ordered_user_data_when_missing_fields>test_1 - Test behavior, not implementation. Don’t assert internal variable names.
- Keep tests fast — mock network and DB calls. Use pytest fixtures and jest mocks.
- Use small, focused tests. One assertion per behavior is a good rule of thumb.
- For React, prefer React Testing Library (user-centric) over enzyme (implementation-centric).
- Use
# pragma: no coverfor generated code, and exclude migrations, config scripts. - Add a coverage threshold in CI so low coverage fails the build.
CI snippet: enforce coverage in GitHub Actions
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Python
uses: actions/setup-python@v4
with: { 'python-version': '3.10' }
- run: pip install -r requirements.txt
- run: pip install pytest pytest-cov
- run: pytest --cov=app --cov-report=xml
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with: { 'files': 'coverage.xml' }
You can do a similar workflow for Node/jest and upload coverage.
Quick checklist before deploy
- Unit tests for all core business logic
- Mock external services (auth, payment, APIs)
- Coverage run in CI, threshold set
- Coverage report published (Codecov badge on README)
- Critical paths have branch coverage
Final takeaways
- Unit tests make your app debuggable earlier and cheaper than production debugging.
- Coverage gives a measurable lens but don’t worship it — test meaningfully.
- Mock external dependencies and keep tests fast so CI runs quickly before deployment.
"Tests are the brakes and coverage is the speedometer — don’t drive without either."
If you want, I can generate a starter test suite for your current CS50 app (Flask backend + React frontend) with pytest and jest configs, plus a GitHub Actions CI file — tell me the repo layout and I’ll scaffold it.
Comments (0)
Please sign in to leave a comment.
No comments yet. Be the first to comment!