Testing Strategies with Copilot
Transform your testing workflow with GitHub Copilot's intelligent test generation capabilities and proven strategies.
Why Use Copilot for Testing?β
- β‘ Accelerates repetitive tasks β Writing boilerplate tests
- π Supports TDD β Generate tests before implementation
- π Improves coverage β Suggests both happy paths and edge cases
- π οΈ Integrates smoothly β Works inside your IDE with
/testsor inline chat
Best Practices for Test Generationβ
1. Highlight Relevant Codeβ
Select the function/class before prompting Copilot for accurate context.
# Select this function first
def validate_price(price: float):
if price <= 0:
raise ValueError("Price must be greater than 0")
if price > 1000:
raise ValueError("Price must be less than or equal to 1000")
# Then use: /tests create tests for validate_price
2. Be Specific in Promptsβ
Name specific behaviors you want to test.
# β Generic: /tests
# β
Specific: /tests create tests for withdrawal scenarios including insufficient funds
3. Provide Context with Docstringsβ
Add docstringsβCopilot uses them for accurate test generation.
def calculate_discount(price: float, discount_percent: float) -> float:
"""
Calculate discounted price for products.
Args:
price: Original price (must be positive)
discount_percent: Discount percentage (0-100)
Returns:
Discounted price
Raises:
ValueError: If price is negative or discount > 100%
"""
# Implementation here
4. Review and Iterateβ
Always validate Copilot's output and ask for improvements.
# After generating tests, ask:
# "Add edge cases for boundary values"
# "Include tests for concurrent access"
# "What other scenarios should I test?"
Practical Examplesβ
Example A: Python Unit Testsβ
Function to Test:
def validate_email(email: str) -> bool:
"""Validate email format and domain."""
import re
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
return re.match(pattern, email) is not None
Prompt:
/tests create comprehensive tests for validate_email including edge cases
Generated Tests:
import unittest
from email_validator import validate_email
class TestValidateEmail(unittest.TestCase):
def test_valid_emails(self):
"""Test valid email formats."""
valid_emails = [
"user@example.com",
"test.email+tag@domain.co.uk",
"user123@test-domain.com"
]
for email in valid_emails:
with self.subTest(email=email):
self.assertTrue(validate_email(email))
def test_invalid_emails(self):
"""Test invalid email formats."""
invalid_emails = [
"invalid.email",
"@domain.com",
"user@",
"user space@domain.com"
]
for email in invalid_emails:
with self.subTest(email=email):
self.assertFalse(validate_email(email))
def test_edge_cases(self):
"""Test edge cases."""
self.assertFalse(validate_email(""))
self.assertFalse(validate_email(None))
Example B: JavaScript/Jest Testsβ
Function to Test:
function calculateShipping(weight, distance, express = false) {
if (weight <= 0) throw new Error("Weight must be positive");
if (distance <= 0) throw new Error("Distance must be positive");
let cost = weight * 2 + distance * 0.5;
return express ? cost * 1.5 : cost;
}
Prompt:
/tests generate Jest tests for calculateShipping with all scenarios
Generated Tests:
const { calculateShipping } = require('./shipping');
describe('calculateShipping', () => {
describe('Happy Path', () => {
test('calculates basic shipping cost', () => {
expect(calculateShipping(2, 100)).toBe(54); // 2*2 + 100*0.5
});
test('calculates express shipping with surcharge', () => {
expect(calculateShipping(2, 100, true)).toBe(81); // 54 * 1.5
});
});
describe('Edge Cases', () => {
test('handles minimum values', () => {
expect(calculateShipping(0.1, 0.1)).toBe(0.25);
});
});
describe('Error Handling', () => {
test('throws error for invalid weight', () => {
expect(() => calculateShipping(-1, 100)).toThrow('Weight must be positive');
});
test('throws error for invalid distance', () => {
expect(() => calculateShipping(2, -50)).toThrow('Distance must be positive');
});
});
});
Template-Driven API Testingβ
For consistent API test generation, use structured templates:
API Test Templateβ
**Prompt Template:**
Generate comprehensive API tests for [ENDPOINT] covering:
**API Details:**
- Endpoint: [URL]
- Method: [GET/POST/PUT/DELETE]
- Auth: [Bearer token/None]
- Request Schema: [JSON schema]
- Response Schema: [JSON schema]
**Test Scenarios:**
1. Happy path (200/201 responses)
2. Authentication (401 Unauthorized)
3. Authorization (403 Forbidden)
4. Invalid input (400 Bad Request)
5. Not found (404)
6. Rate limiting (429)
7. Schema validation
8. State changes verification
Example API Test Generation πβ
Prompt:
Generate comprehensive API tests for Payment API:
Endpoint: POST /api/payments
Auth: Bearer token
Request: {"amount": 1200, "currency": "USD", "customer_id": "uuid"}
Response: {"transaction_id": "uuid", "status": "success/failed", "message": "string"}
Include all error scenarios and edge cases.
Generated Test Structure:
describe('POST /api/payments', () => {
describe('Authentication & Authorization', () => {
test('returns 401 for missing token', async () => {
// Test implementation
});
test('returns 403 for invalid permissions', async () => {
// Test implementation
});
});
describe('Happy Path', () => {
test('processes valid payment successfully', async () => {
// Test implementation
});
});
describe('Validation', () => {
test('returns 400 for missing customer_id', async () => {
// Test implementation
});
test('returns 400 for invalid amount', async () => {
// Test implementation
});
});
});
Advanced Testing Techniquesβ
Test Coverage Analysisβ
# Use coverage tools with Copilot-generated tests
npm run test -- --coverage # JavaScript
pytest --cov=src tests/ # Python
# Ask Copilot: "What test cases am I missing for 100% coverage?"
Property-Based Testingβ
# Ask Copilot to generate property-based tests
from hypothesis import given, strategies as st
@given(st.floats(min_value=0.01, max_value=1000))
def test_price_calculation_properties(price):
"""Property: discounted price should always be less than original."""
discounted = calculate_discount(price, 10)
assert discounted < price
Integration Test Generationβ
# Prompt: "Generate integration tests for user registration flow"
def test_user_registration_integration():
"""Test complete user registration process."""
# POST /register
# Verify database record
# Check welcome email sent
# Confirm user can login
Quick Testing Checklistβ
Before Generating Tests:
- Function/class selected and highlighted
- Docstrings and comments added
- Related files open for context
- Clear prompt with specific scenarios
After Generation:
- Review all test cases for accuracy
- Run tests to ensure they pass
- Check coverage reports
- Ask "What am I missing?" for edge cases
Pro Testing Workflow
- Write function with docstring π
- Use
/testswith specific scenarios π― - Review and run generated tests βΆοΈ
- Iterate with "Add tests for..." prompts π
- Check coverage and ask for missing cases π
Master more advanced Copilot features in our Agent Mode guide! π€