Agent Wranglers

Recommended

Test rules with several conditions as a table

When a result depends on two or more conditions, list every combination in a table with its expected result. Run each row as a test.

How to do it

Name the conditions, such as member or guest, a coupon or none, and an order above or below the free shipping limit. Write one row per combination, with the result the business expects. Ask the owner of the rule to read the table, because a missing row is where bugs hide. Merge rows only where a condition makes no difference, and name the ignored condition in the row. For conditions with a limit, also test the limit itself, as Test the edges and the errors says. Roles and actions follow the same idea in Test every role against every action.

Examples

Using these examples: they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

Python example

import pytest

# member, coupon, order total in cents, expected shipping fee in cents
SHIPPING = [
    (True,  None,       4999, 0),
    (True,  None,       5000, 0),
    (False, None,       4999, 495),
    (False, None,       5000, 0),
    (False, "FREESHIP", 4999, 0),
    (False, "FREESHIP", 5000, 0),
    (True,  "FREESHIP", 4999, 0),
    (True,  "FREESHIP", 5000, 0),
]

@pytest.mark.parametrize("member,coupon,total,fee", SHIPPING)
def test_shipping_fee(member, coupon, total, fee):
    assert shipping_fee(member=member, coupon=coupon, total=total) == fee

JavaScript example

import { expect, test } from 'vitest';

test.each([
  { member: true, coupon: null, total: 4999, fee: 0 },
  { member: true, coupon: null, total: 5000, fee: 0 },
  { member: false, coupon: null, total: 4999, fee: 495 },
  { member: false, coupon: null, total: 5000, fee: 0 },
  { member: false, coupon: 'FREESHIP', total: 4999, fee: 0 },
  { member: false, coupon: 'FREESHIP', total: 5000, fee: 0 },
  { member: true, coupon: 'FREESHIP', total: 4999, fee: 0 },
  { member: true, coupon: 'FREESHIP', total: 5000, fee: 0 },
])('member $member, coupon $coupon, total $total pays $fee', ({ member, coupon, total, fee }) => {
  expect(shippingFee({ member, coupon, total })).toBe(fee);
});

How to check

Multiply the number of values of each condition. The table has that many rows, or merged rows that name the conditions they ignore. Change the result for one combination in the code, and only that row's test fails.

For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/testing/unit-tests/decision-tables">Agent Wranglers testing playbook</a>. In code you write, add a comment next to it with the same link.