# How to Create Custom Test Fixtures in Catch2: A Complete Guide

> Master custom test fixtures in Catch2. Learn to use macros for per-section, direct member function, and persistent state fixtures for robust C++ testing.

- Repository: [Catch Org/Catch2](https://github.com/catchorg/Catch2)
- Tags: how-to-guide
- Published: 2026-07-30

---

**Catch2 implements custom test fixtures through a family of macros that generate unique derived classes from your fixture class, offering three distinct lifetime options: per-section isolation with `TEST_CASE_METHOD`, direct member function testing with `METHOD_AS_TEST_CASE`, and persistent state with `TEST_CASE_PERSISTENT_FIXTURE`.**

Creating custom test fixtures in Catch2 enables reusable setup logic and consistent test environments across multiple test cases. The catchorg/Catch2 framework achieves this through a sophisticated macro expansion system defined in the internal registry headers. By selecting the appropriate fixture pattern, you can control whether each test section receives fresh state or shares expensive resources.

## How Catch2 Implements Fixture Classes

The fixture mechanism relies on macro-generated inheritance rather than virtual functions or templates alone.

### The Internal Macro Expansion

In [`src/catch2/internal/catch_test_registry.hpp`](https://github.com/catchorg/Catch2/blob/main/src/catch2/internal/catch_test_registry.hpp), the `INTERNAL_CATCH_TEST_CASE_METHOD` macro defines the core machinery. The public interface in [`src/catch2/catch_test_macros.hpp`](https://github.com/catchorg/Catch2/blob/main/src/catch2/catch_test_macros.hpp) exposes `TEST_CASE_METHOD`, which expands approximately to:

```cpp
class CATCH2_INTERNAL_TEST_123 : public Fixture {
    void test() { /* test body */ }
};
static auto const& CATCH2_REG_123 = registerTest(/* ... */);

```

This generated class inherits from your fixture, allowing access to protected members and methods. The framework instantiates this derived class for every *partial run*—meaning each leaf `SECTION`—ensuring test isolation.

## Three Fixture Lifetime Patterns

Catch2 provides three distinct macros for custom test fixtures, each controlling how often the fixture class is instantiated.

### TEST_CASE_METHOD (Fresh Instance Per Section)

**`TEST_CASE_METHOD`** creates a new fixture instance for every leaf `SECTION`. This provides maximum isolation and is ideal for database connections or file handles that must start clean.

```cpp
class DbFixture {
    DBConnection conn;
public:
    DbFixture() : conn(DBConnection::create("test.db")) {}
    int nextId() { static int id = 0; return ++id; }
};

TEST_CASE_METHOD(DbFixture, "Insert without name", "[db]") {
    REQUIRE_THROWS(conn.execute("INSERT INTO users VALUES (?, '')", nextId()));
}

TEST_CASE_METHOD(DbFixture, "Insert normal", "[db]") {
    REQUIRE_NOTHROW(conn.execute("INSERT INTO users VALUES (?, 'John')", nextId()));
}

```

Each test case above receives its own `DbFixture` instance, preventing state leakage between assertions.

### METHOD_AS_TEST_CASE (Member Function as Test)

**`METHOD_AS_TEST_CASE`** registers an existing member function as a standalone test, creating a new fixture instance specifically for that member function. Use this when you have class methods that naturally represent test cases.

```cpp
class SimpleFixture {
    std::string s = "hello";
public:
    void checkString() { REQUIRE(s == "hello"); }
};

METHOD_AS_TEST_CASE(SimpleFixture::checkString,
                    "Check string via member function", "[simple]");

```

The framework instantiates `SimpleFixture`, calls `checkString()`, then destroys the instance.

### TEST_CASE_PERSISTENT_FIXTURE (Single Instance Per Test Case)

Added in **Catch2 3.7.0**, **`TEST_CASE_PERSISTENT_FIXTURE`** creates one fixture instance for the entire test case, reusing it across all leaf `SECTION`s. This avoids expensive setup costs when isolation is not required.

```cpp
struct ExpensiveSetup {
    ExpensiveSetup()  { std::this_thread::sleep_for(std::chrono::seconds(2)); }
    ~ExpensiveSetup() { std::this_thread::sleep_for(std::chrono::seconds(1)); }
    int value() const { return 42; }
};

struct MyFixture {
    mutable int counter = 0;
    ExpensiveSetup heavy;
};

TEST_CASE_PERSISTENT_FIXTURE(MyFixture, "Persistent fixture demo") {
    const int cur = counter++;   // mutable allows mutation
    SECTION("first") { REQUIRE(heavy.value() == 42); REQUIRE(cur == 0); }
    SECTION("second") { REQUIRE(cur == 1); }
}

```

The `heavy` member is constructed once, and `counter` persists across sections, allowing you to verify execution order.

## Templated Fixtures for Generic Testing

For type-parameterized tests, Catch2 provides template fixture macros defined in [`src/catch2/internal/catch_template_test_registry.hpp`](https://github.com/catchorg/Catch2/blob/main/src/catch2/internal/catch_template_test_registry.hpp) and exposed via [`src/catch2/catch_template_test_macros.hpp`](https://github.com/catchorg/Catch2/blob/main/src/catch2/catch_template_test_macros.hpp).

### TEMPLATE_TEST_CASE_METHOD and Variants

These macros accept a `TestType` template parameter that is substituted for each type in the provided list. The fixture logic remains identical while testing different concrete types.

```cpp
template <typename T>
struct VecFixture {
    std::vector<T> data{ T(1), T(2), T(3) };
};

TEMPLATE_TEST_CASE_METHOD(VecFixture, "Vector size test",
                          "[template][vector]", int, double) {
    REQUIRE(TestType::data.size() == 3);
}

```

The `TestType` alias refers to the specific instantiation of `VecFixture` for `int` or `double` during each partial run.

## Summary

- **Fixture Generation**: Catch2 creates unique derived classes via `INTERNAL_CATCH_TEST_CASE_METHOD` in [`src/catch2/internal/catch_test_registry.hpp`](https://github.com/catchorg/Catch2/blob/main/src/catch2/internal/catch_test_registry.hpp), inheriting from your custom fixture class.
- **Per-Section Isolation**: Use `TEST_CASE_METHOD` when you need fresh fixture state for every leaf `SECTION`.
- **Member Function Tests**: Use `METHOD_AS_TEST_CASE` to expose existing class methods as standalone test cases with automatic fixture instantiation.
- **Persistent State**: Use `TEST_CASE_PERSISTENT_FIXTURE` (available since Catch2 3.7.0) to share one fixture instance across all sections in a test case.
- **Generic Fixtures**: Use `TEMPLATE_TEST_CASE_METHOD` and related macros in [`src/catch2/catch_template_test_macros.hpp`](https://github.com/catchorg/Catch2/blob/main/src/catch2/catch_template_test_macros.hpp) to apply the same fixture logic across multiple types.

## Frequently Asked Questions

### How does Catch2 generate fixture classes internally?

Catch2 uses the `INTERNAL_CATCH_TEST_CASE_METHOD` macro in [`src/catch2/internal/catch_test_registry.hpp`](https://github.com/catchorg/Catch2/blob/main/src/catch2/internal/catch_test_registry.hpp) to generate a uniquely named class (e.g., `CATCH2_INTERNAL_TEST_<id>`) that publicly inherits from your fixture class. This derived class wraps your test body and is registered with the framework's test registry.

### What is the difference between TEST_CASE_METHOD and TEST_CASE_PERSISTENT_FIXTURE?

`TEST_CASE_METHOD` creates a fresh fixture instance for every leaf `SECTION`, ensuring complete test isolation. `TEST_CASE_PERSISTENT_FIXTURE`, introduced in Catch2 3.7.0, creates a single fixture instance when the test case begins and destroys it after the final section completes, allowing expensive setup to be amortized across multiple sections.

### Can I use custom test fixtures with multiple data types?

Yes. Use `TEMPLATE_TEST_CASE_METHOD`, `TEMPLATE_PRODUCT_TEST_CASE_METHOD`, or `TEMPLATE_LIST_TEST_CASE_METHOD` defined in [`src/catch2/catch_template_test_macros.hpp`](https://github.com/catchorg/Catch2/blob/main/src/catch2/catch_template_test_macros.hpp). These macros instantiate your fixture template with each specified type, accessible via the `TestType` alias inside the test body.

### Where are the public fixture macros defined?

The public-facing macros `TEST_CASE_METHOD`, `METHOD_AS_TEST_CASE`, and `TEST_CASE_PERSISTENT_FIXTURE` are defined in [`src/catch2/catch_test_macros.hpp`](https://github.com/catchorg/Catch2/blob/main/src/catch2/catch_test_macros.hpp). The template variants reside in [`src/catch2/catch_template_test_macros.hpp`](https://github.com/catchorg/Catch2/blob/main/src/catch2/catch_template_test_macros.hpp). Both delegate to internal implementations in the corresponding `internal/catch_*_registry.hpp` files.