API Testing
Purpose
The Virtual Rodent backend exposes internal API endpoints used by the web interface and simulator integration.
API testing verifies that these endpoints behave correctly, enforce access restrictions, reject invalid requests and return predictable responses.
The API tests are written in Python using unittest. They start a temporary local HTTP server and communicate with the backend using real HTTP requests rather than calling endpoint functions directly.
This provides integration-level testing of the API while remaining independent from the normal development database.
Test environment
Each API test creates an isolated test environment containing:
- a temporary SQLite database;
- temporary researcher accounts;
- test paradigms;
- paradigm memberships;
- assigned and unassigned experiments;
- a local HTTP server;
- an HTTP client with cookie support; and
- CSRF state when authentication is required.
The temporary server and database are destroyed after each test.
This prevents automated API tests from modifying normal development data and ensures that tests can be repeated from a known state.
Authentication testing
Authentication tests verify that protected endpoints cannot be accessed without a valid authenticated session.
The environment preset endpoint is tested before login and must return an unauthorized response.
Authenticated requests use the login endpoint to obtain a session and CSRF token before accessing protected operations.
Authorization testing
Researchers must only be able to access experiments that belong to paradigms they have permission to use.
The test setup creates:
- one experiment assigned to the authenticated researcher; and
- another experiment belonging to a different paradigm.
The API tests verify that the assigned experiment can be accessed while the unrelated experiment returns a forbidden response.
Authorization is therefore enforced by the backend rather than relying only on the user interface.
CSRF protection
State-changing API requests require a valid CSRF token.
The automated tests authenticate normally and then intentionally send mutation requests without the token.
These requests must be rejected.
This confirms that possession of an authenticated session alone is not sufficient to perform protected mutations.
Experiment revision control
Experiment updates use revision numbers to prevent an older version of an experiment from overwriting a newer version.
The API tests submit an update using an incorrect revision and verify that the server returns a conflict response.
This supports optimistic concurrency control when experiments are being edited.
Paradigm customization restrictions
A paradigm can restrict which experiment settings a researcher is allowed to modify.
The test configuration gives the researcher permission to modify odour settings.
The API tests then attempt two changes:
- modifying a restricted light setting; and
- modifying an allowed odour setting.
The light modification must be rejected while the odour modification must succeed.
This verifies that customization permissions are enforced by the backend and cannot be bypassed by sending API requests directly.
Simulator command testing
The simulator command endpoint only accepts approved commands.
The API tests verify that:
- commands cannot be issued against an experiment the researcher cannot access;
- unsupported commands are rejected;
- valid commands are accepted; and
- experiment-specific capabilities are returned when an experiment is loaded.
An arbitrary command such as run_arbitrary_code must return a bad request.
This command whitelist prevents clients from using the API to execute unsupported simulator operations.
Replay API testing
The backend supports storing replay data for experiments.
The automated test authenticates a researcher, submits replay data for an assigned experiment and verifies that:
- the request succeeds;
- the API returns a created response; and
- a replay identifier is returned.
This confirms that replay data can pass through the API and be persisted for an authorized experiment.
Environment preset API testing
The environment preset endpoint integrates the internal API with the environment service.
The API tests verify:
- authentication is required;
- CSRF protection is required;
- valid environment data is returned correctly; and
- invalid location requests are handled correctly.
For automated testing, the real external weather service is replaced with a controlled fake service.
A successful fake response contains information such as:
- requested location;
- resolved location;
- country;
- requested date;
- requested time;
- resolved time;
- temperature;
- daylight state;
- suggested light settings;
- suggested sound settings; and
- suggested temperature.
The test verifies that the API returns the generated settings correctly.
Invalid environment requests
The environment API is also tested with a simulated location lookup failure.
The fake environment service raises the same location error used by the real implementation.
The API must convert this into an appropriate client error response rather than crashing or returning an invalid environment preset.
This verifies the failure path as well as the successful path.
External API isolation
Automated API tests do not depend on the live Open-Meteo service.
The external environment service is replaced with controlled responses when testing the backend endpoint.
This keeps the automated tests:
- deterministic;
- repeatable;
- fast;
- independent of internet connectivity; and
- independent of third-party service availability.
The real Open-Meteo integration can be checked separately using a manual integration test.
A failure of an external provider should not cause the project's normal automated test suite to fail when the Virtual Rodent code itself is functioning correctly.
Running the API tests
The backend Python environment should be activated before running the test suite.
Example:
source .venv/bin/activate
The API tests can then be executed with the project's Python test command.
For example:
python -m unittest
or, when using the configured pytest environment:
pytest
Coverage can be collected with:
pytest --cov
The exact command used for Sprint evidence should be recorded together with the resulting test output.
Expected result
A successful API test run should complete without failed tests.
Any failure must be investigated before the related feature is considered complete.
Tests must not be removed or disabled simply to obtain a passing test run.
API test coverage
The current API tests cover the following areas:
Authentication
|
+-- Login/session handling
+-- Protected endpoint access
+-- Password verification
+-- CSRF protection
Authorization
|
+-- Assigned experiment access
+-- Cross-paradigm restrictions
+-- Paradigm customization scopes
Experiment API
|
+-- Experiment retrieval
+-- Revision conflicts
+-- Controlled updates
Simulator API
|
+-- Authorized commands
+-- Command whitelist
+-- Experiment capabilities
Replay API
|
+-- Authorized replay creation
+-- Replay persistence
Environment API
|
+-- Authentication
+-- CSRF
+-- Successful preset generation
+-- Invalid location handling
+-- External service isolation
This combination provides useful API coverage across normal behaviour, failure behaviour, security controls and integration boundaries.
AI Attribution: This document was drafted and edited with AI assistance, including ChatGPT and OpenAI Codex. The team reviewed it against the implemented project.