Modern QA2026Writing CRUD Tests
Log inJoin
15 / 18 · Book 14 · Exercises← prev⊞ allnext →Get the book →

1.15Writing CRUD Tests

# test_users.py

def test_create_user(api, create_user):
    """Verify user creation returns correct data."""
    user = create_user(name="Alice", role="admin")
    assert user["name"] == "Alice"
    assert user["role"] == "admin"
    assert "id" in user


def test_get_user(api, create_user):
    """Verify fetching a user by ID returns correct data."""
    user = create_user(name="Bob")
    r = api.get(f"/users/{user['id']}")
    assert r.status_code == 200
    assert r.json()["name"] == "Bob"


def test_update_user(api, create_user):
    """Verify user update modifies the correct fields."""
    user = create_user(name="Original")
    r = api.put(f"/users/{user['id']}", json={
        "name": "Updated",
        "email": user["email"],
        "role": user["role"]
    })
    assert r.status_code == 200
    assert r.json()["name"] == "Updated"


def test_delete_user(api, create_user):
    """Verify user deletion and subsequent 404."""
    user = create_user()
    r = api.delete(f"/users/{user['id']}")
    assert r.status_code == 204
    # Verify deletion
    r = api.get(f"/users/{user['id']}")
    assert r.status_code == 404


@pytest.mark.parametrize("email,expected", [
    ("valid@test.com", 201),
    ("", 400),
    ("not-an-email", 422),
    ("a" * 300 + "@test.com", 422),
])
def test_create_user_email_validation(api, email, expected):
    """Verify email validation across various inputs."""
    r = api.post("/users", json={
        "name": "Test", "email": email, "role": "viewer"
    })
    assert r.status_code == expected

COMMON MISTAKE: Writing tests that depend on data created by other tests. Each test should create its own data and clean up after itself. Use factory fixtures to ensure test independence.

2.3 Newman vs pytest: When to Use Which

Aspect Newman pytest + requests
Learning curve Low (if already using Postman) Medium (requires Python)
Flexibility Limited to Postman scripting Full Python ecosystem
Data-driven testing CSV/JSON data files pytest parametrize, fixtures
Maintenance at scale Collections become unwieldy Standard code with modules and imports
Debugging Postman console Python debugger, logging
Reusable utilities Limited Full Python: custom assertions, helpers, libraries
Version control JSON exports (hard to diff) Python files (easy to diff and review)
Team collaboration Postman workspaces Git (standard code review workflow)