How to Mock a GitHub Actions Workflow in Python
Build a dataclass-based model of a GitHub Actions workflow and simulate its execution to validate steps and outputs before deployment.
Python code
81 linesimport json
from dataclasses import dataclass, asdict
from typing import List, Dict, Any
@dataclass
class Step:
name: str
run: str
@dataclass
class Job:
name: str
steps: List[Step]
runs_on: str = "ubuntu-latest"
@dataclass
class Workflow:
name: str
jobs: List[Job]
def to_github_actions_yaml(self) -> Dict[str, Any]:
"""Generate a GitHub Actions workflow dictionary (simulated)."""
workflow_dict = {
"name": self.name,
"on": ["push"],
"jobs": {},
}
for job in self.jobs:
job_dict = {
"runs-on": job.runs_on,
"steps": [
{"name": step.name, "run": step.run}
for step in job.steps
],
}
workflow_dict["jobs"][job.name] = job_dict
return workflow_dict
def execute(self) -> Dict[str, List[str]]:
"""Mock-execute each step, collecting printed outputs."""
results: Dict[str, List[str]] = {}
for job in self.jobs:
outputs = []
for step in job.steps:
outputs.append(f"Running: {step.name}")
outputs.append(f"Command: {step.run}")
outputs.append(f"Result: SUCCESS")
results[job.name] = outputs
return results
if __name__ == "__main__":
workflow = Workflow(
name="CI Pipeline",
jobs=[
Job(
name="test",
steps=[
Step(name="Install deps", run="pip install -r requirements.txt"),
Step(name="Run tests", run="pytest"),
],
),
Job(
name="build",
steps=[
Step(name="Compile", run="python setup.py build"),
Step(name="Package", run="python setup.py sdist"),
],
),
],
)
generated_yaml = workflow.to_github_actions_yaml()
print("Generated workflow (JSON):")
print(json.dumps(generated_yaml, indent=2))
print("\nExecuting workflow simulation:")
print(json.dumps(workflow.execute(), indent=2, default=str))
Output
Generated workflow (JSON):
{
"name": "CI Pipeline",
"on": [
"push"
],
"jobs": {
"test": {
"runs-on": "ubuntu-latest",
"steps": [
{
"name": "Install deps",
"run": "pip install -r requirements.txt"
},
{
"name": "Run tests",
"run": "pytest"
}
]
},
"build": {
"runs-on": "ubuntu-latest",
"steps": [
{
"name": "Compile",
"run": "python setup.py build"
},
{
"name": "Package",
"run": "python setup.py sdist"
}
]
}
}
}
Executing workflow simulation:
{
"test": [
"Running: Install deps",
"Command: pip install -r requirements.txt",
"Result: SUCCESS",
"Running: Run tests",
"Command: pytest",
"Result: SUCCESS"
],
"build": [
"Running: Compile",
"Command: python setup.py build",
"Result: SUCCESS",
"Running: Package",
"Command: python setup.py sdist",
"Result: SUCCESS"
]
}
How it works
Using dataclasses gives a clean, type‑safe structure for representing workflow entities like Workflow, Job, and Step. The to_github_actions_yaml method builds a standard GitHub Actions dictionary that mirrors what you'd write in a YAML file, making it easy to inspect or convert to actual YAML later. The execute method simulates running each step by printing the step name, the command, and a placeholder status — useful for validating orchestration logic or generating logs without triggering real side effects. This pattern works because it separates the workflow definition (data) from execution (behavior), allowing easy testing and reuse.
Common mistakes
- Using `json.dumps` on dataclasses without `default=str` causes a TypeError for non‑serializable objects.
- Forgetting to set `runs_on` for jobs that need a different runner (e.g., `windows-latest`).
- Not simulating failure paths — always make the mock return SUCCESS, even when a real step might fail.
- Hardcoding workflow names or job names, making the mock inflexible for multiple environments.
Variations
- Use `yaml.safe_dump` from PyYAML to generate actual YAML text instead of a dictionary.
- Add a `fail_after` parameter to the `execute` method to randomly fail a step, testing error handling.
Real-world use cases
- Pre‑deployment validation of CI pipelines: verify step order and commands without hitting real build servers.
- Documentation and training: generate readable workflow structures for onboarding or audits.
- Testing automation that reacts to workflow events, such as a service that parses CI status messages.
Sponsored
More from Production deployment patterns
- Auto Rollback on Error Rate Exceeded in Python medium
- Automate Semantic Versioning with Conventional Commits in Python medium
- Design a Data Helper for Beginners in Python easy
- Docker healthcheck CMD mock in Python easy
- Generate a Mock Artifact Version Tag in Python easy
- Generate a docker-compose.yml with mock services in Python easy
Keep learning
Related tutorials and quizzes for this topic.