> For the complete documentation index, see [llms.txt](https://practical-testing.gitbook.io/home/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://practical-testing.gitbook.io/home/test-automation/test-with-zombies.md).

# Test With ZOMBIES

ZOMBIES<sup>1</sup> is an acronym and a useful test heuristic, **especially for developers.**

Testing is a complex activity, but using ZOMBIES helps catch easy-to-prevent bugs. Pick the low-hanging fruit, so to speak.

### ZOM - Zero, One, Many

**Zero** and **One** are edge cases, and **Many** is the first generalization - if the function or module works correctly with 2 "things", it is likely to work with 3, 4, and more (though far from always).

#### Zero

For convenience and structure, "Zero" cases are grouped into in-memory and out-of-memory.

#### In-Memory "Zero" Cases<sup>\*</sup>

* **Null / None** references (standalone variables, inside `List`, `Set`, or `Map/dict values`)
* **Numeric zero values**: `0`, `0.0`
* **NaN** (Not a Number)
* **Empty or blank string** (`""`, `" "`)
* **Empty collections**: `[]`, `{}`, empty `Set` or `Map`, empty Map values, empty JSON array/object
* **Default-constructed / uninitialized objects** (all fields at defaults)
* **Boolean false** (logical zero in some contexts)

*\*Although these originate in memory, zero values can propagate into or come back from external systems, and can occur in an out-of-memory context (see below).*

***

#### Out-of-Memory (External) "Zero" Cases

* **Database query results**:
  * No rows returned (`SELECT ...` yields an empty result set)
  * Aggregations yielding `0` (e.g., `COUNT(*)=0`)
* **File system / I/O**:
  * Zero-length file
  * Empty stream or socket response
* **API / Service responses**:
  * Empty JSON/XML response body
  * Valid response with an empty list or object
  * `null` or missing fields in the payload
* **Message queues / event buses**:
  * No messages available (empty poll)

#### One

Exactly "one of the thing" is a frequent edge case too. Exactly one item in a shopping cart, one money transfer, one item in a List of Set.

Consider the loop below. It takes two values at a time and sums them up.

For example, given the input `[1,2,3,4]`, it will compute `1+2`, `3+4`, and output `[3, 7]`.

But it will fail with input containing just one element.

{% tabs %}
{% tab title="Python" %}

```python
def sum_pairs(numbers):
    pair_list = []
    for i in range(0, len(numbers), 2):
        # assumes 2+ elements, exactly even count
        pair_sum = numbers[i] + numbers[i + 1]
        pair_list.append(pair_sum)
    return pair_list


print(sum_pairs([10, 20, 30, 40]))  # [30, 70]  
print(sum_pairs([10]))   # IndexError: list index out of range
```

{% endtab %}

{% tab title="Java" %}

```java
public List<Integer> sumPairs(int[] nums) {
    List<Integer> list = new ArrayList<>();

    for (int i = 0; i < nums.length; i += 2) {
        // assumes 2+ elements, exactly even count
        int pairSum = nums[i] + nums[i + 1];
        list.add(pairSum);
    }
    return list;
}
```

{% endtab %}
{% endtabs %}

#### Many

*"If it works with 2 things, it will work with more"* is a good starting point as a generalization, but sometimes insufficient. Special, context-dependent values are important.

Even the trivial `sum_pairs` example above will fail given a collection with an `odd` number of elements.

"Odd" or "even" count is one example of how a special number may reveal a bug.&#x20;

See [EP\&BVA](/home/techniques/ep-and-bva.md) for more special business, numerical, and non-numerical values.

***

### B - Boundary Values

See [EP\&BVA](/home/techniques/ep-and-bva.md).

***

### I - Interfaces

Sometimes, programmers get so tangled up in the implementation details that they let implementation dictate or influence the interface (method/function signature, API endpoints, JSON contracts, etc.)

Interfaces exist to benefit the "client" (a human user, another program, a calling function).

This point suggests **focusing on the interface first - its usability and clarity**.&#x20;

* **Working solo**: practice TDD to produce cleaner interfaces. With tests, one sees how the function, class, or another smaller piece of code looks and feels when being used by the caller.
* **Working together**: code/design reviews, providing an unimplemented interface to future users to provide feedback on

***

### E - Exercise Exceptional Behavior

Sometimes known as "negative testing" - trigger failures, crashes, timeouts, and write code that is prepared to handle such events gracefully.

* **Files:** absent, locked for reading/writing, interruption during read/write, corrupted content
* **Network:** disconnected, timeout, slow response, invalid data received
* **User input:** unexpected or invalid formats, empty input, extremely large input
* **System resources:** low memory, disk full, CPU spikes
* **APIs / external services:** unavailable, error responses, rate-limited, malformed responses

See [Advanced State Testing](https://practical-testing.gitbook.io/home/techniques/state-based-testing#advanced-state-testing) and [Testing Failures and Errors](https://practical-testing.gitbook.io/home/testing-practices/testing-failures-and-errors) for more ideas.

***

### S - Simple Scenarios, Simple Solutions

A guiding tip that reflects the general TDD approach: when implementing something, imagine simple scenarios first (happy path), and write the simplest possible implementation for that first.&#x20;

Iterate and handle harder scenarios with more complex code gradually.

### References

1. ZOMBIES was likely originally coined by James Grenning [in his blog post](https://blog.wingman-sw.com/tdd-guided-by-zombies). See also "TDD Guided by ZOMBIES" [YouTube video](https://www.youtube.com/watch?v=dYM8HEacJgs).
