PyWorkout — Testing¶
PyWorkout's test suite lives in tests/ and runs on pytest. It covers the CLI in main.py; gui.py is an unfinished Tkinter frontend that is not wired into the application, so its tests skip in most environments.
For local setup, linting, and building, see Development.
Test Structure¶
tests/
├── __init__.py # Package initialization
├── test_main.py # Tests for main.py (CLI functionality)
└── test_gui.py # Tests for gui.py (GUI components)
Test Coverage¶
The test suite includes the following test categories:
Main Module Tests (test_main.py)¶
- TestWorkoutData - Tests workout data structures
-
Validates workout groups are defined correctly
-
TestMuscleGroupSelection - Tests muscle group selection
- Selection by number (1-7)
- Selection by name (abs, quads, glutes, etc.)
- Invalid selection handling
-
Quit during selection
-
TestWorkoutCommands - Tests CLI commands
list- List exercisesstart- Start workouthelp- Display helplicense- Display licensequit- Exit program-
Invalid command handling
-
TestWorkoutFlow - Tests workout flow
- Start → Next → End flow
- Skip functionality
-
Stats command
-
TestVideoFunctionality - Tests video playback
-
Video command on different platforms
-
TestWelcomeScreen - Tests welcome screen
- Welcome message display
-
Day recommendation
-
TestIntegration - Integration tests
- Complete workout scenarios
- Multiple muscle groups
GUI Module Tests (test_gui.py)¶
- TestGUIImports - Tests GUI imports
- TestPercentageFunction - Tests percentage calculations
- TestGUIComponents - Tests GUI components
Running Tests¶
Prerequisites¶
Install test dependencies:
This installs:
- pytest
- pytest-cov (coverage reporting)
- pytest-mock (mocking support)
Running All Tests¶
Run all tests with coverage:
Running Specific Test Files¶
Run main module tests:
Run GUI tests:
Running Specific Test Classes¶
Running Specific Tests¶
Coverage Reports¶
Generate Coverage Report¶
Generate HTML Coverage Report¶
Then open htmlcov/index.html in your browser.
Generate XML Coverage Report¶
Test Configuration¶
Test configuration is stored in setup.cfg:
[tool:pytest]
testpaths = tests
python_files = test_*.py
python_classes = Test*
python_functions = test_*
addopts =
-v
--strict-markers
--tb=short
--cov=.
--cov-report=term-missing
--cov-report=html
--cov-report=xml
--cov-branch
Continuous Integration¶
Tests are automatically run via GitHub Actions on:
- Push to
mainanddevelopbranches - Pull requests to
mainanddevelopbranches
The workflow tests against multiple Python versions:
- Python 3.9
- Python 3.10
- Python 3.11
- Python 3.12
See .github/workflows/tests.yml for the full workflow configuration.
Writing New Tests¶
When adding new tests, follow these guidelines:
- Naming Convention
- Test files:
test_*.py - Test classes:
Test* -
Test functions:
test_* -
Test Organization
- Group related tests in classes
- Use descriptive test names
-
Add docstrings explaining what is being tested
-
Mocking
- Use
@patchfor mocking input/output -
Mock external dependencies (filesystem, network, etc.)
-
Example Test
@patch('builtins.print')
@patch('builtins.input')
def test_abs_selection(mock_input, mock_print):
"""Test selecting abs muscle group."""
mock_input.side_effect = ['abs', 'quit']
with pytest.raises(SystemExit):
main.workout()
printed_output = [str(call) for call in mock_print.call_args_list]
assert any('Ab muscle group selected' in str(call) for call in printed_output)
Troubleshooting¶
GUI Tests Skipped¶
GUI tests may be skipped in headless environments (CI/CD). This is expected behavior as tkinter requires a display.
Import Errors¶
If you encounter import errors, ensure you're running tests from the project root:
Coverage Not Showing¶
Ensure pytest-cov is installed:
Test Results¶
Current test coverage: ~54% overall
- Main module: ~51% coverage
- Test suite: 25 tests passing
- GUI tests: 5 tests (may skip in headless environments)
Contributing¶
When contributing:
- Write tests for new features
- Ensure all tests pass before submitting PR
- Aim for >80% code coverage for new code
- Follow existing test patterns and conventions