Skip to main content
In this lesson we add deterministic, fast unit and integration tests for the METAR reader application. We’ll use pytest to validate METAR decoding logic, mock external network calls to avoid hitting APIs during tests, and exercise Flask endpoints using the Flask test client. The goal is to make tests reliable, easy to run, and useful for continuous integration.
A presentation slide with the title "Creating Unit Tests for our Project." A large "Demo" label appears on a dark curved panel on the right.
Using Claude Code For Beginners’ CLI-like slash commands can speed up local development workflows and give helpful tips about the repository layout:

Test plan (concise)

  • Use pytest for unit and integration testing.
  • Mock network requests (requests.get) to simulate API responses and errors.
  • Unit test METAR decoding functions: wind direction, visibility, clouds, weather phenomena, temperature conversion, edge cases.
  • Integration tests to decode complete METAR strings and check structured output.
  • Add Flask route tests to verify endpoint responses and error handling.
  • Add test-only dependencies to requirements.txt and document test instructions in README.
  • Run tests locally and produce coverage reports for CI.

Unit tests: METAR decoder

Below are cleaned-up unit tests for basic METAR components. These tests focus on pure functions so they remain fast and deterministic.

Integration-style test for a complete METAR

Integration tests exercise the decoder end-to-end for a full METAR line. These validate structured output keys and human-readable detail fields.

Network-dependent tests: mocking requests

Network-dependent behavior is tested by mocking requests.get and forcing exceptions or specific response behavior. Use pytest monkeypatch or unittest.mock for predictable tests.

Edge-case tests

Include tests for input wrapping and unusual formats. These ensure the decoder tolerates out-of-range values and uncommon METAR encodings.

Test dependencies

Add the test runner and helper libraries to your requirements. Lock versions as needed for reproducibility.
Install dependencies and run tests:
If tests fail, iterate on either the tests or the implementation. Example fixes typically discovered during test-driven debugging include:
  • Use requests.exceptions.HTTPError and RequestException for mocked errors.
  • Normalize negative and out-of-range wind-direction inputs.
  • Return singular “mile” for 1SM visibility results.
  • Enhance cloud parsing to support multiple cloud layers.
  • Make weather-phenomena ordering idempotent and deterministic.

Coverage

Use pytest-cov to report coverage and identify untested logic paths:

Typical Git workflow for tests

Commit and push your test files and README changes as part of feature branches:

README updates: add a Testing section

Include a concise Testing section in README.md that explains how developers run the suite locally and what mocks or fixtures to expect.
Run tests in a virtual environment to keep dependencies isolated: python3 -m venv .venv && source .venv/bin/activate Then install the requirements and run pytest.

Verification checklist

  • Tests cover decoding of METAR components (wind, visibility, clouds, weather phenomena, temperature).
  • Integration tests validate decoded outputs for realistic METAR examples.
  • Network layer is tested with mocks for successful responses, HTTP errors, and network exceptions.
  • Flask routes are tested for both normal and error flows using the Flask test client.
  • Edge cases (malformed input, extreme values, missing data) are included.
  • Tests are run with coverage to identify untested areas.
This testing strategy yields a maintainable, fast test suite that protects the METAR decoder from regressions and helps ensure correct aviation semantics. Review generated tests to ensure they assert correct behavior (not just the current implementation) and update the decoder as needed.

Watch Video