Skip to main content
In this lesson we create Python unit tests for a METAR decoder application. We use pytest and unittest.mock to validate parsing functions, full METAR decoding, Flask routes, network behavior, and edge cases. The test suite uses realistic mock METAR strings to assert human-readable outputs and deterministic decoding behavior.
A presentation slide titled "Creating Unit Tests for our Project" with a large "Demo" label on a dark curved shape at the right. The slide has a light background and a small "© Copyright KodeKloud" note in the bottom-left.
Overview
  • Test runner: pytest (with optional pytest-cov for coverage).
  • Use unittest.mock (or pytest-mock) to stub network calls and simulate HTTP errors.
  • Validate METARDecoder atomic parsing methods and full METAR integration outputs.
  • Use the Flask test client to exercise web endpoints, form validation, and error handling.
  • Include edge-case tests for malformed input, extreme values, and normalization behavior.
Using an AI assistant to bootstrap tests
  • The assistant inspected app.py, recommended a layered test strategy, and produced a pytest-style scaffold with realistic mock METAR strings.
  • Suggested test strategy:
    1. Unit tests for METARDecoder methods (atomic parsing helpers).
    2. Integration tests for end-to-end METAR decoding.
    3. Flask route tests using the Flask test client.
    4. Network/mocking tests for fetch routines and HTTP exceptions.
    5. Edge-case tests (malformed METARs, extreme values, missing fields).
Recommended test structure High-level test classes and responsibilities
  • TestMETARDecoder: unit tests for wind direction, visibility, cloud parsing, weather phenomena, and temperature conversions.
  • TestMETARDecodingIntegration: full METAR strings decoded into expected human-readable descriptions.
  • TestFetchMETAR: mock network responses (success, RequestException, HTTPError).
  • TestFlaskRoutes: exercise endpoints, forms, and error templates using Flask’s test client.
  • TestEdgeCases: malformed METAR components, extreme wind/temperature values, missing data.
Sample tests (representative, cleaned and positioned correctly)
  • Use pytest fixtures for setup and mocking. Below are representative examples that show proper structure and assertions.
Network and HTTP error tests (mocking requests)
Edge-case tests: wind normalization
Installing test dependencies and running tests
  • Add pytest to your test requirements (e.g., requirements-test.txt or requirements.txt).
  • Install and run:
For coverage reports:
Troubleshooting failing tests
  • Example failing summary from an initial run:
Common causes and fixes
  • Ordering of decoded weather phenomena: produce deterministic ordering in decoder output (e.g., sort the list) or assert using sets when order is not important.
  • Cloud parsing: support multiple cloud groups (e.g., SCT008 BKN015 OVC025) and return a combined description.
  • Mock exception types: use requests.exceptions.RequestException and requests.exceptions.HTTPError for network tests.
  • Wind direction wrapping: normalize degrees with modulo 360 before converting to compass text.
  • Assert expectations must reflect the decoder’s contract (exact phrasing vs. set membership).
Example fixes applied to tests and mocks
  • Use appropriate request exception classes and explicit mock behavior:
METARDecoder parsing snippet (context)
  • Typical decoding flow: iterate parts of the METAR string, call helper methods for visibility, weather, clouds, etc.
Re-running tests and coverage
  • After making fixes and adjustments, run the full test suite and generate coverage:
  • Example final results after fixes:
What the test suite validates
  1. Individual METAR components:
    • Wind direction conversion (degrees → compass direction strings).
    • Visibility parsing (e.g., 10SM → “10+ miles visibility”).
    • Cloud layer decoding (CLR, SCT015, BKN040).
    • Weather phenomena decoding (-RA, +TSRA, VCFG).
    • Temperature conversion (Celsius → Fahrenheit).
  2. Complete METAR integration strings:
    • Example METARs used in tests:
      • KHIO 061853Z 27008KT 10SM CLR 22/16 A3012 (clear)
      • KORD 061851Z 09014KT 3SM -RA SCT008 BKN015 OVC025 18/17 A2992 (rain)
      • PANC 061853Z 36010KT 10SM CLR M15/M20 A2985 (below zero temps)
      • KBOS 061854Z 08015KT 2SM +TSRA BKN008 OVC020 20/19 A2995 (thunderstorms)
  3. API & network layer:
    • Mocked requests for success and simulated network/HTTP errors.
  4. Flask routes:
    • Form validation, responses, and error rendering via the Flask test client.
  5. Edge cases:
    • Malformed METAR components, extreme wind/temperature values, missing data.
Documentation and repo updates
  • Update requirements-test.txt or requirements.txt to include:
    • pytest
    • pytest-cov (optional for coverage)
    • any test helpers (e.g., requests-mock)
  • Update README with a “Testing” section describing:
    • How to install test dependencies,
    • How to run pytest and generate coverage,
    • What the tests cover,
    • Sample mock METAR strings used in tests.
Example git commands after adding tests
Run tests frequently as you make parsing changes. Use deterministic ordering for lists (like weather phenomena) in decoder output or assert against sets when order is not important.
Summary
  • A layered pytest suite (unit → integration → endpoint → network → edge cases) gives comprehensive coverage for METAR decoding.
  • Use fixtures, deterministic outputs, and explicit mocks for network behavior to make tests reliable and fast.
  • The generated scaffold from an AI assistant accelerates test creation, but always adapt assertions to reflect your decoder’s exact output contract (phrasing, ordering, return types).

Watch Video