Test Data Design and Requirements Traceability Matrix (RTM)

๐Ÿ“‹ Table of Contents โ–พ
  1. Designing Test Data and Building an RTM
  2. Common Mistakes

Even the best-written test case is useless without the right test data to drive it, and meaningless if nobody can tell which requirement it verifies. Test data design ensures your inputs are realistic, comprehensive and cover the scenarios that matter. The Requirements Traceability Matrix (RTM) ensures every requirement has at least one test case covering it โ€” and every test case is justified by a requirement. Together, they transform your test suite from a collection of scripts into a structured quality assurance system.

Designing Test Data and Building an RTM

Test data is not an afterthought โ€” it is a first-class deliverable of the test design phase. Poor test data leads to false passes (the test “passed” because it used a trivially easy input) and missed defects (the edge case was never tested because no one created data for it).

# Test data design for a user registration feature
# Requirements:
#   REQ-001: Username must be 3โ€“20 alphanumeric characters
#   REQ-002: Email must be valid format (RFC 5322)
#   REQ-003: Password must be 8โ€“64 chars with complexity rules
#   REQ-004: Duplicate email must show error message

# โ”€โ”€ Test data table โ”€โ”€
test_data_table = [
    # (data_id, username, email, password, scenario, expected_req)
    ("TD-001", "alice",      "alice@test.com",    "Secure@1",    "All valid โ€” happy path",       "REQ-001,002,003"),
    ("TD-002", "ab",         "ab@test.com",       "Secure@1",    "Username too short (2 chars)",  "REQ-001"),
    ("TD-003", "a" * 21,     "long@test.com",     "Secure@1",    "Username too long (21 chars)",  "REQ-001"),
    ("TD-004", "alice",      "not-an-email",      "Secure@1",    "Invalid email format",          "REQ-002"),
    ("TD-005", "alice",      "alice@test.com",     "short",       "Password below minimum",        "REQ-003"),
    ("TD-006", "bob",        "alice@test.com",     "Secure@1",    "Duplicate email",               "REQ-004"),
    ("TD-007", "user_123",   "user@test.com",      "Secure@1",    "Username with underscore",      "REQ-001"),
    ("TD-008", "",           "empty@test.com",     "Secure@1",    "Empty username",                "REQ-001"),
]

# โ”€โ”€ Requirements Traceability Matrix (RTM) โ”€โ”€
rtm = {
    "REQ-001": {
        "description": "Username must be 3-20 alphanumeric characters",
        "test_cases": ["TC-REG-001", "TC-REG-002", "TC-REG-003", "TC-REG-007", "TC-REG-008"],
        "status": "Covered",
    },
    "REQ-002": {
        "description": "Email must be valid RFC 5322 format",
        "test_cases": ["TC-REG-001", "TC-REG-004"],
        "status": "Covered",
    },
    "REQ-003": {
        "description": "Password must be 8-64 chars with complexity rules",
        "test_cases": ["TC-REG-001", "TC-REG-005"],
        "status": "Covered",
    },
    "REQ-004": {
        "description": "Duplicate email must show error message",
        "test_cases": ["TC-REG-006"],
        "status": "Covered",
    },
}

print("Requirements Traceability Matrix (RTM)")
print("=" * 70)
for req_id, info in rtm.items():
    cases = ", ".join(info["test_cases"])
    print(f"  {req_id}: {info['description']}")
    print(f"           Tests: {cases}  [{info['status']}]")
    print()

# Check for uncovered requirements
uncovered = [r for r, info in rtm.items() if not info["test_cases"]]
if uncovered:
    print(f"WARNING: Uncovered requirements: {uncovered}")
else:
    print("All requirements have at least one test case โœ“")
Note: The RTM is a living document that must be updated every time requirements change, test cases are added, or test cases are retired. Its primary value is answering two questions: “Is every requirement tested?” (forward traceability) and “Does every test case trace back to a requirement?” (backward traceability). Orphan test cases โ€” those that do not trace to any requirement โ€” should be reviewed. They may be testing outdated functionality, or they may reveal a requirement that was never formally documented.
Tip: Store test data separately from test cases in a dedicated data sheet or database table. This separation lets you reuse the same test case logic with different data sets โ€” for example, running the same registration test case with data for ten different countries, each with different address formats. It also makes it easy to refresh test data without editing test case steps.
Warning: Never use real production data in your test environment without proper anonymisation. Real email addresses, phone numbers, credit card numbers and personal information create privacy violations and legal liability. Use generated or anonymised data โ€” tools like Faker (Python) or Chance.js (JavaScript) can create realistic test data that is entirely synthetic.

Common Mistakes

Mistake 1 โ€” Using the same test data for every test case

โŒ Wrong: Every test case uses “john@test.com” and “Password123” regardless of what scenario it is testing.

โœ… Correct: Each test case uses data specifically designed for its scenario โ€” valid data for positive tests, boundary data for boundary tests, and deliberately malformed data for negative tests.

Mistake 2 โ€” Building the RTM after testing is complete

โŒ Wrong: Creating the traceability matrix retroactively as a documentation exercise after all tests have been executed.

โœ… Correct: Building the RTM during the test design phase so gaps in coverage are visible before execution begins. If a requirement has zero test cases mapped to it, you know immediately that additional test cases are needed.

🧠 Test Yourself

What is the primary purpose of a Requirements Traceability Matrix (RTM)?