Module 1: Introduction to Git and Version Control for Testing
Understand why version control is critical for test automation projects. Learn the fundamental concepts of Git, set up your environment, and make your first commits with test scripts. Explore how Git solves common problems test engineers face: tracking changes in test cases, collaborating on automation frameworks, and maintaining test data.
Collaborating on Test Frameworks: Your First Team Workflow
Why This Matters
You’ve been writing test automation scripts and committing them to Git. Everything works smoothly—until another test engineer joins your project. Suddenly, you’re both modifying the same test framework. You update the page object file at 2 PM, push your changes, and by 3 PM your teammate has overwritten your work. Or worse: your CI/CD pipeline breaks because someone committed untested code directly to the main branch, and now the entire team’s test suite is failing.
This is the reality of team-based test automation without proper collaboration workflows.
In professional test engineering environments, you’ll rarely work alone. Your team might include:
- Multiple automation engineers working on different test suites
- Manual testers transitioning to automation who need guidance
- Developers contributing integration tests
- DevOps engineers maintaining test infrastructure
Without a structured collaboration workflow, you’ll encounter:
- Lost work: Changes getting overwritten by teammates
- Broken builds: Untested code pushed directly to production branches
- Quality issues: Test scripts merged without peer review
- Configuration conflicts: Multiple people editing the same test data files simultaneously
- Audit problems: No clear approval trail for test changes
This lesson teaches you the branching and pull request workflow—the industry standard for collaborative test automation development. You’ll learn how professional test engineering teams work together without stepping on each other’s toes, maintain high code quality through reviews, and keep their test frameworks stable.
What You’ll Learn
By the end of this lesson, you’ll be able to participate effectively in a collaborative test automation team using Git workflows that mirror real-world practices at companies like Google, Microsoft, and Amazon.
Your Learning Journey
Branching Strategies - You’ll understand why working directly on the main branch is problematic and learn different branching strategies teams use. We’ll focus on feature branching, where each test development task gets its own isolated branch. You’ll learn when to create branches, how to name them effectively, and how to keep them organized.
Creating Feature Branches - You’ll practice creating branches for specific test automation tasks—adding new test cases, updating page objects, or refactoring test data. You’ll see the complete workflow from creating a branch through completing your work, with hands-on examples using realistic test automation scenarios.
Pull Requests - You’ll learn how to submit your test code changes for team review using pull requests. We’ll cover writing effective PR descriptions that explain what tests you’ve added or modified, why changes were necessary, and what reviewers should focus on. You’ll understand how PRs act as quality gates for your test framework.
Code Review Skills - You’ll develop the ability to review other test engineers’ code effectively. This includes checking for test completeness, identifying potential flaky tests, verifying proper assertions, and providing constructive feedback. You’ll learn what makes a good code review comment and how to balance thoroughness with efficiency.
Merge Conflict Resolution - You’ll encounter the inevitable situation where your test changes conflict with a teammate’s work—perhaps you both modified the same test fixture or updated the same configuration file. We’ll walk through identifying conflicts, understanding conflict markers, choosing the correct resolution, and testing the merged result.
Workflow Best Practices - You’ll learn the habits that distinguish professional test engineering teams: keeping branches short-lived, writing atomic commits, synchronizing with the main branch regularly, and maintaining a clean commit history. These practices prevent problems before they occur.
Each concept builds on the previous one, taking you from solo developer to effective team collaborator. Let’s begin by understanding why branches are essential for team-based test automation.
Core Content
Core Content: Collaborating on Test Frameworks
1. Core Concepts Explained
Understanding Version Control for Test Automation
When working on test automation frameworks as a team, version control becomes essential. Multiple team members need to work on different test scripts, page objects, and utilities simultaneously without overwriting each other’s work.
Git Workflow Fundamentals:
The typical Git workflow for test automation follows this pattern:
graph LR
A[Clone Repository] --> B[Create Feature Branch]
B --> C[Write Tests]
C --> D[Commit Changes]
D --> E[Push to Remote]
E --> F[Create Pull Request]
F --> G[Code Review]
G --> H[Merge to Main]
Setting Up Your Local Environment
Step 1: Install Git
# Verify Git installation
git --version
# If not installed, download from git-scm.com
# Windows: Download installer
# Mac: brew install git
# Linux: sudo apt-get install git
Step 2: Configure Git Identity
# Set your name (appears in commit history)
git config --global user.name "Your Name"
# Set your email (should match GitHub/GitLab account)
git config --global user.email "your.email@example.com"
# Verify configuration
git config --list
Cloning and Initializing a Test Repository
Cloning an Existing Repository:
# Clone via HTTPS
git clone https://github.com/your-team/test-automation-framework.git
# Clone via SSH (recommended for frequent pushes)
git clone git@github.com:your-team/test-automation-framework.git
# Navigate into the repository
cd test-automation-framework
# Install dependencies
npm install
Terminal Output Example:
$ git clone https://github.com/your-team/test-automation-framework.git
Cloning into 'test-automation-framework'...
remote: Enumerating objects: 156, done.
remote: Counting objects: 100% (156/156), done.
remote: Compressing objects: 100% (98/98), done.
Receiving objects: 100% (156/156), 45.23 KiB | 2.12 MiB/s, done.
Resolving deltas: 100% (67/67), done.
Branching Strategy for Test Development
Creating Feature Branches:
# Always start from the latest main branch
git checkout main
git pull origin main
# Create a new branch for your test feature
git checkout -b feature/login-tests
# Verify you're on the correct branch
git branch
$ git branch
main
* feature/login-tests
2. Practical Code Examples
Example 1: Adding New Test Files to Version Control
Scenario: You’ve created a new login test suite.
// tests/login.spec.js
const { test, expect } = require('@playwright/test');
test.describe('Login Functionality', () => {
test('should login with valid credentials', async ({ page }) => {
await page.goto('https://practiceautomatedtesting.com/login');
// Fill login form
await page.fill('#username', 'testuser@example.com');
await page.fill('#password', 'SecurePass123!');
await page.click('button[type="submit"]');
// Verify successful login
await expect(page.locator('.welcome-message')).toBeVisible();
await expect(page).toHaveURL(/.*dashboard/);
});
test('should show error for invalid credentials', async ({ page }) => {
await page.goto('https://practiceautomatedtesting.com/login');
await page.fill('#username', 'invalid@example.com');
await page.fill('#password', 'wrongpassword');
await page.click('button[type="submit"]');
// Verify error message appears
await expect(page.locator('.error-message')).toContainText('Invalid credentials');
});
});
Stage and Commit Your Changes:
# Check status to see untracked files
git status
# Add the new test file
git add tests/login.spec.js
# Commit with a descriptive message
git commit -m "Add login functionality test suite
- Add test for successful login
- Add test for invalid credentials handling
- Verify error messages and redirects"
Example 2: Updating Existing Test Configuration
Before:
// playwright.config.js
module.exports = {
testDir: './tests',
timeout: 30000,
use: {
headless: true,
viewport: { width: 1280, height: 720 },
},
};
After:
// playwright.config.js
module.exports = {
testDir: './tests',
timeout: 30000,
retries: 2, // Added retry logic for flaky tests
use: {
headless: true,
viewport: { width: 1280, height: 720 },
screenshot: 'only-on-failure', // Added screenshot capture
video: 'retain-on-failure', // Added video recording
},
reporter: [
['html', { outputFolder: 'test-results' }], // Added HTML reporter
['junit', { outputFile: 'test-results/junit.xml' }]
],
};
# Check what changed
git diff playwright.config.js
# Stage the modified file
git add playwright.config.js
# Commit the configuration update
git commit -m "Configure test retries and failure recording
- Add 2 retries for flaky test handling
- Enable screenshots on test failure
- Enable video recording on failure
- Add HTML and JUnit reporters"
Example 3: Creating and Pushing Your Branch
# Push your feature branch to remote
git push origin feature/login-tests
# If this is the first push, set upstream
git push -u origin feature/login-tests
$ git push -u origin feature/login-tests
Enumerating objects: 8, done.
Counting objects: 100% (8/8), done.
Delta compression using up to 8 threads
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 1.23 KiB | 1.23 MiB/s, done.
Total 5 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 1 local object.
To https://github.com/your-team/test-automation-framework.git
* [new branch] feature/login-tests -> feature/login-tests
Branch 'feature/login-tests' set up to track remote branch 'feature/login-tests' from 'origin'.
Example 4: Creating a Pull Request
Once your tests are pushed, create a pull request on GitHub/GitLab.
Pull Request Template Example:
## Description
Added comprehensive login functionality tests
## Tests Added
- ✅ Successful login with valid credentials
- ✅ Error handling for invalid credentials
- ✅ Password field masking verification
## Test Coverage
- Covers requirements: REQ-LOGIN-001, REQ-LOGIN-002
## How to Test
```bash
npm test -- login.spec.js
Checklist
- Tests pass locally
- Added appropriate assertions
- Followed naming conventions
- Updated documentation (if needed)
<!-- SCREENSHOT_NEEDED: BROWSER
URL: https://github.com/username/repo/pulls
Description: Pull request view showing test status checks passing
Placement: After PR template example -->
### Example 5: Handling Pull Request Reviews
**Viewing Review Comments:**
```bash
# Fetch latest changes from remote
git fetch origin
# View comments and make changes locally
# After making requested changes:
git add tests/login.spec.js
git commit -m "Address PR feedback: Add timeout handling"
git push origin feature/login-tests
Addressing Merge Conflicts:
# Update your branch with latest main
git checkout main
git pull origin main
git checkout feature/login-tests
git merge main
# If conflicts occur, Git will mark them in files
Example Conflict Resolution:
// tests/login.spec.js
<<<<<<< HEAD
test('should login with valid credentials', async ({ page }) => {
await page.goto('https://practiceautomatedtesting.com/login');
=======
test('should successfully authenticate user', async ({ page }) => {
await page.goto('https://practiceautomatedtesting.com/auth/login');
>>>>>>> main
// ... rest of test
});
Resolve by choosing or combining changes:
// tests/login.spec.js
test('should login with valid credentials', async ({ page }) => {
await page.goto('https://practiceautomatedtesting.com/auth/login');
// ... rest of test
});
# After resolving conflicts
git add tests/login.spec.js
git commit -m "Resolve merge conflict with main branch"
git push origin feature/login-tests
Example 6: Syncing with Team Changes
Keeping Your Branch Updated:
# Regularly pull changes from main
git checkout main
git pull origin main
# Rebase your feature branch (cleaner history)
git checkout feature/login-tests
git rebase main
# Or merge (preserves branch history)
git merge main
3. Common Mistakes and How to Avoid Them
Mistake 1: Committing Sensitive Data
❌ Wrong:
// config/credentials.js
module.exports = {
username: 'admin@company.com',
password: 'MyRealPassword123!',
apiKey: 'sk_live_123456789'
};
✅ Correct:
// config/credentials.js
module.exports = {
username: process.env.TEST_USERNAME,
password: process.env.TEST_PASSWORD,
apiKey: process.env.API_KEY
};
# Create .gitignore to exclude sensitive files
echo ".env" >> .gitignore
echo "credentials.json" >> .gitignore
git add .gitignore
git commit -m "Add gitignore for sensitive data"
Mistake 2: Large Binary Files
Problem: Committing screenshots, videos, or reports bloats the repository.
Solution:
# Add to .gitignore
echo "screenshots/" >> .gitignore
echo "test-results/" >> .gitignore
echo "videos/" >> .gitignore
echo "*.mp4" >> .gitignore
echo "*.png" >> .gitignore
Mistake 3: Vague Commit Messages
❌ Wrong:
git commit -m "fixed stuff"
git commit -m "updates"
git commit -m "changes"
✅ Correct:
git commit -m "Fix timeout issue in checkout test
- Increase wait time for payment processing
- Add explicit wait for confirmation page
- Resolves issue #234"
Mistake 4: Working Directly on Main Branch
❌ Wrong:
git checkout main
# Make changes directly
git commit -m "Add new tests"
git push origin main # Dangerous!
✅ Correct:
git checkout main
git pull origin main
git checkout -b feature/new-tests
# Make changes
git commit -m "Add new tests"
git push origin feature/new-tests
# Create PR for review
Debugging Common Git Issues
Issue: Accidentally committed to wrong branch
# Move commits to correct branch
git log # Note the commit hash
git checkout correct-branch
git cherry-pick <commit-hash>
git checkout wrong-branch
git reset --hard HEAD~1 # Remove last commit
Issue: Need to undo last commit
# Keep changes, undo commit
git reset --soft HEAD~1
# Discard changes and commit
git reset --hard HEAD~1
Issue: Pull request has conflicts
# Update branch with main
git checkout feature/your-branch
git fetch origin
git rebase origin/main
# Fix conflicts in files
git add .
git rebase --continue
git push --force-with-lease origin feature/your-branch
Best Practices Summary
- Always pull before starting new work to avoid conflicts
- Commit frequently with meaningful messages
- Keep branches short-lived (1-3 days max)
- Run tests locally before pushing
- Review your own changes before creating PR
- Respond to feedback promptly and professionally
- Delete merged branches to keep repository clean
# Clean up after merge
git checkout main
git pull origin main
git branch -d feature/login-tests # Delete local branch
git push origin --delete feature/login-tests # Delete remote branch
Hands-On Practice
Hands-On Exercise
🎯 Exercise: Build a Collaborative Test Framework with Git Workflow
In this exercise, you’ll simulate a team workflow by creating a shared test framework structure, implementing branching strategies, and practicing code reviews.
Task Overview
Create a basic test automation framework for a fictional e-commerce application, implementing proper Git workflows, code standards, and collaboration practices.
Prerequisites
- Git installed and configured
- GitHub/GitLab account
- Python 3.x and pytest installed (or your preferred language/framework)
- A code editor
Step-by-Step Instructions
Part 1: Repository Setup (15 minutes)
-
Create the main repository
mkdir ecommerce-test-framework cd ecommerce-test-framework git init
-
Create initial framework structure
mkdir -p tests/api tests/ui tests/data config utils touch README.md .gitignore requirements.txt touch config/config.yaml utils/helpers.py
-
Create a README.md with framework guidelines
# E-Commerce Test Framework ## Setup ## Running Tests ## Contribution Guidelines - Branch naming: feature/*, bugfix/*, test/* - Commit message format: [TYPE] Brief description - All PRs require one review
-
Add .gitignore
__pycache__/ *.pyc .pytest_cache/ reports/ .env
-
Commit and push to remote
git add . git commit -m "[SETUP] Initialize test framework structure" git branch -M main # Create remote repository and push git remote add origin <your-repo-url> git push -u origin main
Part 2: Feature Branch Workflow (20 minutes)
-
Create a feature branch for login tests
git checkout -b feature/login-tests
-
Create a login test file (
tests/ui/test_login.py
)import pytest class TestLogin: """Test suite for login functionality""" def test_successful_login(self): """Verify user can login with valid credentials""" # TODO: Implement test assert True, "Implement login test" def test_invalid_credentials(self): """Verify error message with invalid credentials""" # TODO: Implement test assert True, "Implement negative test" @pytest.mark.skip(reason="Waiting for password reset feature") def test_forgot_password(self): """Verify forgot password functionality""" pass
-
Create a helper utility (
utils/helpers.py
)def generate_test_user(username_prefix="test_user"): """Generate test user data""" import random return { "username": f"{username_prefix}_{random.randint(1000, 9999)}", "password": "Test@123", "email": f"{username_prefix}@test.com" } def log_test_step(step_description): """Log test execution steps""" print(f"[TEST STEP] {step_description}")
-
Commit with descriptive message
git add tests/ui/test_login.py utils/helpers.py git commit -m "[FEATURE] Add login test suite with helper utilities" git push origin feature/login-tests
Part 3: Code Review Simulation (15 minutes)
-
Create a Pull Request (on GitHub/GitLab)
- Title: “Add login test suite”
- Description: Include what was added, testing done, and checklist
PR Template:
## Changes - Added login test suite with positive and negative scenarios - Created helper utilities for test data generation ## Testing - [ ] All tests pass locally - [ ] Code follows style guidelines - [ ] Documentation updated ## Checklist - [ ] Branch is up-to-date with main - [ ] No merge conflicts - [ ] Tests are properly documented
-
Self-review checklist:
- Are test names descriptive?
- Is the code properly documented?
- Are there any hardcoded values that should be in config?
- Can another team member understand the tests?
-
Make improvements based on review
# Add improvements to the same branch git add . git commit -m "[REFACTOR] Extract credentials to config file" git push origin feature/login-tests
Part 4: Merge Conflict Resolution (15 minutes)
-
Simulate a conflict scenario
# Switch to main and make a change git checkout main echo "pytest==7.4.0" > requirements.txt git add requirements.txt git commit -m "[DEPS] Add pytest dependency" # Switch back to feature branch git checkout feature/login-tests echo "pytest==7.3.0\nselenium==4.10.0" > requirements.txt git add requirements.txt git commit -m "[DEPS] Add test dependencies"
-
Attempt to merge and resolve conflict
git checkout main git merge feature/login-tests # Conflict occurs! # Resolve in requirements.txt, keeping both dependencies # Use the newer pytest version
-
Complete the merge
git add requirements.txt git commit -m "[MERGE] Resolve dependency conflicts"
Part 5: Team Standards Implementation (10 minutes)
-
Create a pre-commit hook (
.git/hooks/pre-commit
)#!/bin/bash echo "Running pre-commit checks..." # Check for TODO comments if git diff --cached | grep -i "TODO"; then echo "Warning: TODO comments found" fi # Run tests (optional for quick feedback) # pytest tests/ -v echo "Pre-commit checks passed!"
-
Make the hook executable
chmod +x .git/hooks/pre-commit
-
Document the workflow (add to README.md)
## Development Workflow 1. Create feature branch from main 2. Implement tests following naming conventions 3. Run tests locally 4. Commit with descriptive messages 5. Push and create PR 6. Address review comments 7. Merge after approval
Expected Outcome
By the end of this exercise, you should have:
✅ A well-structured test framework repository
✅ Practiced feature branch workflow
✅ Created and reviewed a pull request
✅ Resolved a merge conflict
✅ Implemented team collaboration standards
✅ Documentation for team members to follow
Verification Checklist
- Repository has clear folder structure
- README.md contains contribution guidelines
- At least one feature branch was created and merged
- Commit messages follow consistent format
- Test files follow naming conventions
- Helper utilities are reusable
- .gitignore excludes generated files
Key Takeaways
🎯 Main Learnings:
-
Branching Strategy Matters: Feature branches keep main stable and allow parallel development. Always branch from main, work on features independently, and merge back through pull requests.
-
Code Reviews Improve Quality: PRs aren’t just bureaucracy—they catch bugs, ensure consistency, share knowledge, and maintain code standards. Even in small teams, reviews provide valuable second perspectives.
-
Clear Documentation Enables Collaboration: README files, commit messages, and inline comments are your team’s async communication. Good documentation reduces onboarding time and prevents misunderstandings.
-
Merge Conflicts Are Normal: Conflicts happen in active teams. The key is communicating about what you’re working on, pulling changes regularly, and knowing how to resolve conflicts methodically without panic.
-
Standards Create Consistency: Agreed-upon naming conventions, folder structures, and workflows help team members understand and contribute to any part of the codebase without friction.
Next Steps
What to Practice
-
Enhance Your Framework
- Add API tests alongside UI tests
- Implement a proper configuration management system
- Create shared fixtures in
conftest.py
- Add CI/CD pipeline (GitHub Actions/GitLab CI)
-
Advanced Git Workflows
- Practice rebasing vs merging strategies
- Try Git hooks for automated quality checks
- Experiment with release branching strategies
- Learn to cherry-pick commits
-
Team Collaboration Skills
- Contribute to an open-source test project
- Practice writing helpful PR review comments
- Learn to break down large features into smaller PRs
Related Topics to Explore
- CI/CD Integration: Automate your test framework with GitHub Actions or Jenkins
- Test Reporting: Implement Allure or ReportPortal for collaborative test results
- Code Quality Tools: Integrate linters (pylint, flake8) and formatters (black) into your workflow
- Test Data Management: Learn strategies for sharing and versioning test data across teams
- Parallel Testing: Explore pytest-xdist or Selenium Grid for distributed test execution
- Infrastructure as Code: Version control your test environment configurations with Docker/Terraform
📚 Recommended Resources
- “Git for Teams” by Emma Jane Hogbin Westby
- Atlassian’s Git Workflow Guides
- Test Automation University courses on framework design
- Your team’s actual projects—real experience beats tutorials!