Skip to main content

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 /tests or 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
  1. Write function with docstring πŸ“
  2. Use /tests with specific scenarios 🎯
  3. Review and run generated tests ▢️
  4. Iterate with "Add tests for..." prompts πŸ”„
  5. Check coverage and ask for missing cases πŸ“Š

Master more advanced Copilot features in our Agent Mode guide! πŸ€–