Testing¶
This guide explains how to test the Rodrunner project.
Test Structure¶
The tests are organized into the following directories:
test_filesystem: Tests for the filesystem moduletest_irods: Tests for the iRODS client moduletest_parsers: Tests for the parsers moduletest_workflows: Tests for the Prefect workflowstest_api: Tests for the FastAPI endpoints
Test Categories¶
The tests are marked with the following categories:
unit: Unit tests that don't require external servicesintegration: Integration tests that require iRODS and/or Prefectirods: Tests that specifically require an iRODS serverapi: Tests for the API endpoints
Running Tests¶
The tests are designed to be run inside the Docker container environment, which includes an iRODS server and Prefect server.
Running All Tests¶
cd /home/bcn/repos/irods/augment-imp
python -m pytest
Running Tests with Coverage¶
cd /home/bcn/repos/irods/augment-imp
python -m pytest --cov=rodrunner
Running Specific Test Categories¶
# Run only unit tests
python -m pytest -m unit
# Run only integration tests
python -m pytest -m integration
# Run only iRODS tests
python -m pytest -m irods
# Run only API tests
python -m pytest -m api
Running Tests from a Specific Module¶
# Run tests for the filesystem module
python -m pytest tests/test_filesystem
# Run tests for a specific test file
python -m pytest tests/test_filesystem/test_find.py
# Run a specific test function
python -m pytest tests/test_filesystem/test_find.py::test_find_files_basic
Test Configuration¶
The tests use the application configuration from environment variables or config files. Make sure the following environment variables are set or a .env file is present:
IRODS_HOST=localhost
IRODS_PORT=1247
IRODS_USER=rods
IRODS_PASSWORD=rods
IRODS_ZONE=tempZone
IRODS_RESOURCE=demoResc
Test Fixtures¶
Common test fixtures are defined in conftest.py. These include:
temp_dir: A temporary directory that is cleaned up after the testapp_config: The application configurationirods_client: An iRODS client instanceapi_client: A FastAPI test clientsample_run_info_xml,sample_run_parameters_xml,sample_samplesheet_csv: Sample file contents for testingsample_sequencer_run: A sample sequencer run directory with all required files
Writing Tests¶
Writing Unit Tests¶
Unit tests should be marked with the unit marker and should not depend on external services:
import pytest
from rodrunner.filesystem.find import find_files
@pytest.mark.unit
def test_find_files_basic(temp_dir):
# Create test files
# ...
# Test finding all files
files = list(find_files(temp_dir, file_type='f'))
assert len(files) == 3
Writing Integration Tests¶
Integration tests should be marked with the integration marker and may depend on external services:
import pytest
from rodrunner.workflows.ingest import ingest_sequencer_runs
@pytest.mark.integration
def test_ingest_sequencer_runs(app_config, sample_sequencer_run, temp_dir):
# Set up a test directory with a sequencer run
# ...
# Run the workflow
results = ingest_sequencer_runs(
config=app_config,
sequencer_type="miseq",
root_dir=miseq_dir
)
# Verify the results
assert len(results) == 1
assert results[0]["success"] is True
Writing iRODS Tests¶
iRODS tests should be marked with the irods marker and depend on an iRODS server:
import pytest
import os
from rodrunner.irods.client import iRODSClient
@pytest.mark.irods
def test_collection_operations(irods_client):
# Generate a unique collection name for testing
test_coll_name = f"/tempZone/home/rods/test_collection_{os.getpid()}"
try:
# Test collection creation
assert not irods_client.collection_exists(test_coll_name)
coll = irods_client.create_collection(test_coll_name)
assert irods_client.collection_exists(test_coll_name)
finally:
# Clean up
if irods_client.collection_exists(test_coll_name):
irods_client.remove_collection(test_coll_name, recursive=True)
Writing API Tests¶
API tests should be marked with the api marker and use the FastAPI test client:
import pytest
from fastapi.testclient import TestClient
@pytest.mark.api
def test_api_root(api_client):
"""Test the API root endpoint."""
response = api_client.get("/")
assert response.status_code == 200
data = response.json()
assert "message" in data
assert data["message"] == "Welcome to the iRODS Prefect API"
Test Coverage¶
The project uses pytest-cov to measure test coverage. You can generate a coverage report with:
python -m pytest --cov=rodrunner --cov-report=term-missing --cov-report=html
This will generate a coverage report in the terminal and an HTML report in the htmlcov directory.
Continuous Integration¶
The project uses GitHub Actions for continuous integration. The CI pipeline runs the tests on every push and pull request.
The CI pipeline includes:
- Setting up the environment
- Installing dependencies
- Running the tests
- Generating a coverage report
- Uploading the coverage report to Codecov
Best Practices¶
- Write tests for all new code: Aim for high test coverage
- Use appropriate markers: Mark tests with the appropriate category
- Clean up after tests: Use fixtures and try/finally blocks to clean up resources
- Use unique names: Use unique names for test resources to avoid conflicts
- Keep tests independent: Tests should not depend on the state from other tests
- Test edge cases: Test both normal and error cases
- Use assertions effectively: Use specific assertions to check expected behavior