Creating deterministic pytest unit and integration tests for a METAR reader, mocking network calls and testing Flask endpoints for reliable continuous integration
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.
Using Claude Code For Beginners’ CLI-like slash commands can speed up local development workflows and give helpful tips about the repository layout:
Copy
* Welcome to Claude Code!/help for help, /status for your current setupcwd: /Users/jeremy/Repos/KodeKloud-METAR-ReaderTips for getting started:1. Run /init to create a CLAUDE.md file with instructions for Claude2. Use Claude to help with file analysis, editing, bash commands and git3. Be as specific as you would with another engineer for the best results4. ✓ Run /terminal-setup to set up terminal integration> Try "how do I log an error?"? for shortcuts
Integration tests exercise the decoder end-to-end for a full METAR line. These validate structured output keys and human-readable detail fields.
Copy
# test_decoder_integration.pyfrom metar_decoder import METARDecoderclass TestMETARDecodingIntegration: def setup_method(self): """Set up test fixtures before each test method.""" self.decoder = METARDecoder() def test_decode_complete_metar_clear_weather(self): """Test decoding a complete METAR with clear weather.""" metar = "KHIO 061853Z 27008KT 10SM CLR 22/16 A3012" result = self.decoder.decode_metar(metar) assert result['details']['station'] == 'KHIO' assert 'Observed at 18:53Z on day 06' in result['details']['time'] assert 'Wind from the west at 8 knots' in result['details']['wind'] assert result['details']['visibility'] == '10+ miles visibility'
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.
Copy
# test_network.pyfrom unittest import mockfrom requests.exceptions import RequestException, HTTPErrorfrom app.network import fetch_metar # hypothetical functiondef test_fetch_metar_network_error(monkeypatch): def fake_get(*args, **kwargs): raise RequestException("Network error") monkeypatch.setattr('requests.get', fake_get) result = fetch_metar('KHIO') assert result is None # or assert expected fallback behaviordef test_fetch_metar_http_error(monkeypatch): mock_response = mock.Mock() mock_response.raise_for_status.side_effect = HTTPError("HTTP 404") monkeypatch.setattr('requests.get', lambda *a, **k: mock_response) result = fetch_metar('INVALID') assert result is None # or assert expected fallback behavior
Include a concise Testing section in README.md that explains how developers run the suite locally and what mocks or fixtures to expect.
Copy
## Testing- Install test dependencies: pip3 install -r requirements.txt- Run tests: python3 -m pytest -v- Run tests with coverage: python3 -m pytest --cov=app --cov-report=term-missingNotes:- Network calls are mocked in tests. No external API calls should be made during the test run.- Flask endpoints are tested with the Flask test client and pytest fixtures.
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.
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.