What testing the Luhn algorithm proves

The Luhn algorithm is a mod-10 checksum. Testing it confirms one narrow property: your code doubles the right digits, reduces each doubled value above nine, adds everything, and checks whether the total ends in zero. A pass proves nothing about whether an account exists, so every test case should use published sample values or numbers you construct yourself.

read more

A correct implementation walks the digit string from right to left, doubles every second digit starting with the second from the right, subtracts nine from any doubled value greater than nine, sums the results, and returns true when the sum modulo ten equals zero.

more on this topic

Prerequisites

  • A function under test that accepts a digit string and returns a boolean.
  • A test runner that reports each case separately, such as pytest, JUnit, Jest, or Go's testing package.
  • A fixed list of sample numbers with known outcomes, written into the test file.

How to test a Luhn implementation

  1. Assert true for the valid samples 79927398713, 4242424242424242, 4539148803436467, 5555555555554444, and 378282246310005.
  2. Assert false for the invalid samples 79927398710, 79927398711, 79927398712, 79927398714, and 4242424242424241.
  3. Loop over 79927398713 and replace one digit at a time with (digit + 1) mod 10, then assert every mutated string returns false.
  4. Run the suite against both an odd-length number such as 79927398713 and an even-length number such as 4242424242424242, because doubling from the wrong end passes one shape and fails the other.
  5. Feed formatted input such as "4242 4242 4242 4242" and "4242-4242-4242-4242" and assert the behavior your contract promises, either stripping separators or rejecting the string.
  6. Assert false or an argument error for "424242424242424A", "4242.4242.4242.4242", null, and the empty string.
  7. Check the boundary values "0" and "0000000000000000000", which sum to zero and therefore pass, then confirm your length cap rejects a 20-digit string.
  8. Add a property test that builds random digit strings, appends the computed check digit, and asserts the result is true.
  9. Include the failing input in every assertion message so a broken case is reproducible from the log alone.

Edge cases worth locking down

  • Leading zeros, which are valid digits and must not be trimmed before the sum.
  • Input that already contains the check digit versus input that contains the payload only.
  • Very long strings, where an unchecked loop can turn into a denial of service on a public endpoint.
  • Unicode digits, which many parsers accept and which will corrupt an ASCII-only sum.

Common failure modes

The most frequent bug is parity: doubling from the left instead of the right. It survives any test built only from even-length numbers, so keep at least one odd-length vector. The second is forgetting the nine subtraction, which inflates the sum and rejects valid values. The third is treating the check as authentication, which leads to code that skips real validation downstream.

test luhn algorithm

When a single test fails, print the running sum next to the digit string. The mismatch usually sits in the second-from-right position, and the printed sum shows in one line whether the doubling or the reduction is wrong.

more on this topic