15 Prompts for Writing Unit and Integration Tests with pytest, Jest, and unittest

Introduction

Testing is the backbone of reliable software. Yet, writing unit and integration tests often feels like a chore — repetitive, time-consuming, and easy to skip. As a developer who relies on AI daily, I've curated a set of battle-tested prompts that generate high-quality tests for Python (pytest, unittest) and JavaScript/TypeScript (Jest). These prompts save hours, reduce boilerplate, and help you cover edge cases you might overlook.

According to the 2023 Stack Overflow Survey, over 70% of professional developers write tests, yet many admit to insufficient coverage due to time constraints. Using AI prompts for test generation isn't about replacing your expertise — it's about accelerating the boring parts so you can focus on logic and edge cases.

Each prompt below includes a real usage example with code. I've used these in production projects, from microservices to React frontends. They work.

1. Basic pytest Unit Test for a Pure Function

Prompt:
"Write a pytest test suite for a pure function that calculates the factorial of a non-negative integer. Include tests for edge cases (0, 1, large numbers) and negative input."

Example:

# factorial.py
def factorial(n: int) -> int:
    if n < 0:
        raise ValueError("Negative input not allowed")
    if n == 0:
        return 1
    return n * factorial(n - 1)

# test_factorial.py
import pytest
from factorial import factorial

def test_factorial_zero():
    assert factorial(0) == 1

def test_factorial_one():
    assert factorial(1) == 1

def test_factorial_small():
    assert factorial(5) == 120

def test_factorial_large():
    assert factorial(10) == 3628800

def test_factorial_negative():
    with pytest.raises(ValueError, match="Negative input not allowed"):
        factorial(-1)

Why it works: The prompt specifies edge cases and error handling, which are common blind spots.

2. Integration Test with pytest and Mock Database

Prompt:
"Write a pytest integration test for a user registration function that interacts with a PostgreSQL database. Use pytest-mock to mock the database cursor and connection."

Example:

# user_service.py
import psycopg2

def register_user(username: str, email: str) -> int:
    conn = psycopg2.connect("dbname=test")
    cur = conn.cursor()
    cur.execute("INSERT INTO users (username, email) VALUES (%s, %s) RETURNING id", (username, email))
    user_id = cur.fetchone()[0]
    conn.commit()
    conn.close()
    return user_id

# test_user_service.py
import pytest
from unittest.mock import patch, MagicMock
from user_service import register_user

@patch('user_service.psycopg2.connect')
def test_register_user(mock_connect):
    mock_conn = MagicMock()
    mock_cursor = MagicMock()
    mock_connect.return_value = mock_conn
    mock_conn.cursor.return_value = mock_cursor
    mock_cursor.fetchone.return_value = (1,)

    user_id = register_user("alice", "alice@example.com")

    assert user_id == 1
    mock_cursor.execute.assert_called_once_with(
        "INSERT INTO users (username, email) VALUES (%s, %s) RETURNING id",
        ("alice", "alice@example.com")
    )

Why it works: Mocking external dependencies makes tests fast and deterministic.

3. Jest Unit Test for a React Component

Prompt:
"Write a Jest unit test with React Testing Library for a simple Button component that accepts onClick and disabled props."

Example:

// Button.jsx
import React from 'react';

const Button = ({ onClick, disabled, children }) => (
  <button onClick={onClick} disabled={disabled}>
    {children}
  </button>
);

export default Button;

// Button.test.jsx
import { render, screen, fireEvent } from '@testing-library/react';
import Button from './Button';

test('calls onClick when clicked and not disabled', () => {
  const handleClick = jest.fn();
  render(<Button onClick={handleClick}>Click me</Button>);
  fireEvent.click(screen.getByText('Click me'));
  expect(handleClick).toHaveBeenCalledTimes(1);
});

test('does not call onClick when disabled', () => {
  const handleClick = jest.fn();
  render(<Button onClick={handleClick} disabled>Click me</Button>);
  fireEvent.click(screen.getByText('Click me'));
  expect(handleClick).not.toHaveBeenCalled();
});

Why it works: The prompt covers both happy path and disabled state, which is a common oversight.

4. unittest Test for a Class with Setup/Teardown

Prompt:
"Write a unittest test suite for a FileManager class that opens, reads, and closes files. Use setUp and tearDown to create and remove temporary files."

Example:

# file_manager.py
class FileManager:
    def read_file(self, path: str) -> str:
        with open(path, 'r') as f:
            return f.read()

# test_file_manager.py
import unittest
import tempfile
import os
from file_manager import FileManager

class TestFileManager(unittest.TestCase):
    def setUp(self):
        self.manager = FileManager()
        self.temp_file = tempfile.NamedTemporaryFile(delete=False, mode='w')
        self.temp_file.write("Hello, world!")
        self.temp_file.close()

    def tearDown(self):
        os.unlink(self.temp_file.name)

    def test_read_file(self):
        content = self.manager.read_file(self.temp_file.name)
        self.assertEqual(content, "Hello, world!")

if __name__ == '__main__':
    unittest.main()

Why it works: Proper setup and teardown ensure tests are isolated and don't leave junk files.

5. Parameterized pytest Test for Multiple Inputs

Prompt:
"Write a parameterized pytest test for a function that checks if a string is a palindrome. Test at least 5 cases including empty string, single character, even-length, odd-length, and non-palindrome."

Example:

# palindrome.py
def is_palindrome(s: str) -> bool:
    return s == s[::-1]

# test_palindrome.py
import pytest
from palindrome import is_palindrome

@pytest.mark.parametrize("input_str, expected", [
    ("", True),
    ("a", True),
    ("aa", True),
    ("aba", True),
    ("ab", False),
    ("racecar", True),
    ("hello", False),
])
def test_is_palindrome(input_str, expected):
    assert is_palindrome(input_str) == expected

Why it works: Parameterization reduces code duplication and makes it easy to add more cases.

6. Integration Test with Jest and Axios Mock

Prompt:
"Write a Jest integration test for an async function that fetches user data from an API using axios. Mock axios to return a specific response."

Example:

// userApi.js
import axios from 'axios';

export async function fetchUser(userId) {
  const response = await axios.get(`https://api.example.com/users/${userId}`);
  return response.data;
}

// userApi.test.js
import axios from 'axios';
import { fetchUser } from './userApi';

jest.mock('axios');

test('fetches user data successfully', async () => {
  const mockData = { id: 1, name: 'Alice' };
  axios.get.mockResolvedValue({ data: mockData });

  const result = await fetchUser(1);
  expect(result).toEqual(mockData);
  expect(axios.get).toHaveBeenCalledWith('https://api.example.com/users/1');
});

test('handles API failure', async () => {
  axios.get.mockRejectedValue(new Error('Network error'));
  await expect(fetchUser(1)).rejects.toThrow('Network error');
});

Why it works: Mocking axios makes tests fast and independent of network availability.

7. pytest Fixture for Shared Resources

Prompt:
"Write a pytest test suite using fixtures to share a database connection across multiple tests. Include tests for creating and deleting records."

Example:

# conftest.py
import pytest
import psycopg2

@pytest.fixture
def db_connection():
    conn = psycopg2.connect("dbname=test")
    yield conn
    conn.close()

# test_db.py
from conftest import db_connection

def test_create_record(db_connection):
    cur = db_connection.cursor()
    cur.execute("INSERT INTO test_table (name) VALUES ('test') RETURNING id")
    record_id = cur.fetchone()[0]
    db_connection.commit()
    assert record_id > 0

def test_delete_record(db_connection):
    cur = db_connection.cursor()
    cur.execute("DELETE FROM test_table WHERE id = 1")
    db_connection.commit()
    assert cur.rowcount == 1

Why it works: Fixtures provide reusable setup and teardown, reducing boilerplate.

8. Jest Snapshot Test for a UI Component

Prompt:
"Write a Jest snapshot test for a Card component that renders title, description, and image URL. Use React Testing Library."

Example:

// Card.jsx
import React from 'react';

const Card = ({ title, description, imageUrl }) => (
  <div className="card">
    <img src={imageUrl} alt={title} />
    <h2>{title}</h2>
    <p>{description}</p>
  </div>
);

export default Card;

// Card.test.jsx
import { render } from '@testing-library/react';
import Card from './Card';

test('matches snapshot', () => {
  const { asFragment } = render(
    <Card title="Test" description="A card" imageUrl="https://example.com/img.jpg" />
  );
  expect(asFragment()).toMatchSnapshot();
});

Why it works: Snapshot tests catch unintended UI changes quickly.

9. unittest Mock for External API Call

Prompt:
"Write a unittest test for a function that calls an external weather API. Use unittest.mock to patch requests.get and return a fake response."

Example:

# weather.py
import requests

def get_weather(city: str) -> dict:
    response = requests.get(f"https://api.weather.com/{city}")
    return response.json()

# test_weather.py
import unittest
from unittest.mock import patch
from weather import get_weather

class TestWeather(unittest.TestCase):
    @patch('weather.requests.get')
    def test_get_weather(self, mock_get):
        mock_get.return_value.json.return_value = {"temp": 20, "condition": "sunny"}
        result = get_weather("London")
        self.assertEqual(result, {"temp": 20, "condition": "sunny"})
        mock_get.assert_called_once_with("https://api.weather.com/London")

if __name__ == '__main__':
    unittest.main()

Why it works: Patching at module level avoids hitting real endpoints.

10. Integration Test with pytest and Docker Compose

Prompt:
"Write a pytest integration test that spins up a PostgreSQL container using Docker Compose, runs a migration, and inserts/retrieves data."

Example:

# test_integration.py
import pytest
import subprocess
import psycopg2
import time

@pytest.fixture(scope="module")
def docker_services():
    subprocess.run(["docker-compose", "up", "-d"])
    time.sleep(5)  # Wait for DB to be ready
    yield
    subprocess.run(["docker-compose", "down"])

def test_db_integration(docker_services):
    conn = psycopg2.connect("dbname=test user=test password=test host=localhost")
    cur = conn.cursor()
    cur.execute("CREATE TABLE IF NOT EXISTS items (id SERIAL, name TEXT)")
    cur.execute("INSERT INTO items (name) VALUES ('test_item')")
    conn.commit()
    cur.execute("SELECT * FROM items")
    assert cur.fetchone()[1] == 'test_item'
    conn.close()

Why it works: Real database integration catches issues that mocks miss.

11. Jest Test for Custom Hook

Prompt:
"Write a Jest test for a custom React hook called useCounter that returns count and increment/decrement functions."

Example:

// useCounter.js
import { useState } from 'react';

export function useCounter(initialValue = 0) {
  const [count, setCount] = useState(initialValue);
  const increment = () => setCount(c => c + 1);
  const decrement = () => setCount(c => c - 1);
  return { count, increment, decrement };
}

// useCounter.test.js
import { renderHook, act } from '@testing-library/react';
import { useCounter } from './useCounter';

test('should increment and decrement', () => {
  const { result } = renderHook(() => useCounter(0));

  act(() => result.current.increment());
  expect(result.current.count).toBe(1);

  act(() => result.current.decrement());
  expect(result.current.count).toBe(0);
});

Why it works: renderHook from testing-library simplifies hook testing.

12. pytest Test for Asynchronous Code

Prompt:
"Write a pytest test for an async function that fetches data from two APIs concurrently using asyncio.gather."

Example:

# async_fetcher.py
import asyncio
import aiohttp

async def fetch_url(session, url):
    async with session.get(url) as response:
        return await response.json()

async def fetch_all(urls):
    async with aiohttp.ClientSession() as session:
        tasks = [fetch_url(session, url) for url in urls]
        return await asyncio.gather(*tasks)

# test_async_fetcher.py
import pytest
from unittest.mock import AsyncMock, patch
from async_fetcher import fetch_all

@pytest.mark.asyncio
async def test_fetch_all():
    mock_session = AsyncMock()
    mock_response = AsyncMock()
    mock_response.json.return_value = {"key": "value"}
    mock_session.get.return_value.__aenter__.return_value = mock_response

    with patch('async_fetcher.aiohttp.ClientSession', return_value=mock_session):
        results = await fetch_all(["http://example.com/1", "http://example.com/2"])
        assert len(results) == 2
        assert results[0] == {"key": "value"}

Why it works: AsyncMock handles async context managers properly.

13. Jest Test for Redux Thunk

Prompt:
"Write a Jest test for a Redux thunk that dispatches multiple actions after an async API call."

Example:

// store/userSlice.js
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import axios from 'axios';

export const fetchUser = createAsyncThunk('user/fetchUser', async (userId) => {
  const response = await axios.get(`/api/users/${userId}`);
  return response.data;
});

const userSlice = createSlice({
  name: 'user',
  initialState: { data: null, loading: false },
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(fetchUser.pending, (state) => { state.loading = true; })
      .addCase(fetchUser.fulfilled, (state, action) => {
        state.loading = false;
        state.data = action.payload;
      });
  },
});

export default userSlice.reducer;

// userSlice.test.js
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import axios from 'axios';
import { fetchUser } from './userSlice';

const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);

jest.mock('axios');

test('dispatches pending and fulfilled actions', async () => {
  const mockUser = { id: 1, name: 'Alice' };
  axios.get.mockResolvedValue({ data: mockUser });

  const store = mockStore({ user: { data: null, loading: false } });
  await store.dispatch(fetchUser(1));

  const actions = store.getActions();
  expect(actions[0].type).toBe('user/fetchUser/pending');
  expect(actions[1].type).toBe('user/fetchUser/fulfilled');
  expect(actions[1].payload).toEqual(mockUser);
});

Why it works: Mock store captures dispatched actions for assertions.

14. pytest Test for File Upload Endpoint

Prompt:
"Write a pytest integration test for a Flask endpoint that accepts a file upload and saves it to disk."

Example:

# app.py
from flask import Flask, request
import os

app = Flask(__name__)
UPLOAD_FOLDER = '/tmp/uploads'

@app.route('/upload', methods=['POST'])
def upload_file():
    file = request.files['file']
    file.save(os.path.join(UPLOAD_FOLDER, file.filename))
    return 'OK', 200

# test_app.py
import pytest
import io
from app import app

@pytest.fixture
def client():
    app.config['TESTING'] = True
    with app.test_client() as client:
        yield client

def test_upload(client):
    data = {'file': (io.BytesIO(b"test content"), 'test.txt')}
    response = client.post('/upload', data=data, content_type='multipart/form-data')
    assert response.status_code == 200

Why it works: Uses Flask's test client to simulate real HTTP requests.

15. unittest Test for Date Utility with Edge Cases

Prompt:
"Write a unittest test for a function that calculates the number of days between two dates. Include edge cases: same day, leap year, and negative interval."

Example:

# date_utils.py
from datetime import date

def days_between(d1: date, d2: date) -> int:
    return abs((d2 - d1).days)

# test_date_utils.py
import unittest
from datetime import date
from date_utils import days_between

class TestDaysBetween(unittest.TestCase):
    def test_same_day(self):
        d = date(2024, 1, 1)
        self.assertEqual(days_between(d, d), 0)

    def test_normal(self):
        d1 = date(2024, 1, 1)
        d2 = date(2024, 1, 10)
        self.assertEqual(days_between(d1, d2), 9)

    def test_leap_year(self):
        d1 = date(2024, 2, 28)
        d2 = date(2024, 3, 1)
        self.assertEqual(days_between(d1, d2), 2)

    def test_negative_interval(self):
        d1 = date(2024, 1, 10)
        d2 = date(2024, 1, 1)
        self.assertEqual(days_between(d1, d2), 9)

if __name__ == '__main__':
    unittest.main()

Why it works: Covers logical edge cases like leap years and reversed order.

Conclusion

These 15 prompts are your starting kit for faster, more comprehensive test writing. Whether you're using pytest for Python, Jest for JavaScript, or unittest for legacy projects, adapting these patterns will save you time and catch bugs earlier.

Pro tip: Combine multiple prompts for complex scenarios. For example, use parameterization (prompt #5) with mocking (#6) to test an API client with various response codes.

Start with one prompt today. Your future self — and your CI pipeline — will thank you.

← All posts

Comments