PHPackages                             systopia/civicrm-test-fixtures - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Testing &amp; Quality](/categories/testing)
4. /
5. systopia/civicrm-test-fixtures

ActiveLibrary[Testing &amp; Quality](/categories/testing)

systopia/civicrm-test-fixtures
==============================

Reusable PHPUnit fixtures for CiviCRM extensions

15563PHP

Since Mar 26Pushed 3mo agoCompare

[ Source](https://github.com/systopia/civicrm-test-fixtures)[ Packagist](https://packagist.org/packages/systopia/civicrm-test-fixtures)[ RSS](/packages/systopia-civicrm-test-fixtures/feed)WikiDiscussions main Synced 3w ago

READMEChangelogDependenciesVersions (3)Used By (3)

Systopia Test Fixtures
======================

[](#systopia-test-fixtures)

A small PHP library to create **repeatable CiviCRM APIv4 test data** with minimal boilerplate.

It provides:

- **Builders** for single entities (returning numeric IDs)
- **Scenarios** that orchestrate multiple builders and return a **Fixture Bag**
- **Fixture Bags** as immutable return objects with schema validation
- A thin **APIv4 adapter/factory layer** so builders stay simple and can be tested with fakes

---

Non-Goals
---------

[](#non-goals)

This library is intentionally **not**:

- an ORM or persistence abstraction
- a general-purpose APIv4 wrapper
- a replacement for CiviCRM business logic

It exists solely to make **tests comfortable, readable, repeatable and intention-revealing**.

---

Installation
------------

[](#installation)

```
composer require --dev systopia/civicrm-test-fixtures
```

---

Design Philosophy
-----------------

[](#design-philosophy)

### Builders return IDs

[](#builders-return-ids)

Builders encapsulate default payloads + overrides and return the created entity ID.

### Scenarios return Bags

[](#scenarios-return-bags)

Scenarios orchestrate multiple builders (e.g. contact + membership + contribution) and return a bag containing the relevant IDs.

### Bags export a canonical array

[](#bags-export-a-canonical-array)

Bags are immutable objects. Consumers should read IDs via `toArray()`.

### IMPORTANT

[](#important)

Scenarios create real CiviCRM entities.

**Tests are expected to wrap execution in a database transaction and roll it back!** (See the example)

---

Quick Start
-----------

[](#quick-start)

### Create a scenario (Contact + Membership + pending Contribution)

[](#create-a-scenario-contact--membership--pending-contribution)

```
use Systopia\TestFixtures\Fixtures\Scenarios\ContributionScenario;

$bag = ContributionScenario::contactWithMembershipAndPendingContribution();

$data = $bag->toArray();

$contactId      = $data['contactId'];
$membershipId   = $data['membershipId'];
$contributionId = $data['contributionId'];
```

### Overrides

[](#overrides)

Most builders/scenarios accept override arrays `array` which are merged into defaults.

Override contact, membership and contribution fields:

```
use Systopia\TestFixtures\Fixtures\Scenarios\ContributionScenario;

$bag = ContributionScenario::contactWithMembershipAndPendingContribution(
  contactOverrides: [
    'first_name' => 'Ada',
    'last_name'  => 'Lovelace',
  ],
  membershipOverrides: [
    'join_date'  => '2022-01-01',
    'start_date' => '2022-01-02',
  ],
  contributionOverrides: [
    'total_amount' => 99.95,
    'currency'     => 'USD',
  ],
);
```

### Use Builders directly

[](#use-builders-directly)

If you only need a single entity ID, call a builder:

```
use Systopia\TestFixtures\Fixtures\Builders\ContactBuilder;

$contactId = ContactBuilder::createDefault();
// or assign default overrides:
$contactId = ContactBuilder::createDefault([
  'first_name' => 'Test',
  'last_name'  => 'User',
]);
```

Create a pending Contribution and an active membership for a contact:

```
use Systopia\TestFixtures\Fixtures\Builders\ContributionBuilder;
use Systopia\TestFixtures\Fixtures\Builders\MembershipBuilder;

$contributionId = ContributionBuilder::createPendingForContact($contactId);
$membershipId = MembershipBuilder::createActiveForContact($contactId);
```

### Fixture Bags

[](#fixture-bags)

Fixture bags validate that:

- the export contains all keys defined in the schema
- no extra keys are present

Consume IDs via `toArray()`:

```
use Systopia\TestFixtures\Fixtures\Scenarios\ContributionScenario;

$bag = ContributionScenario::contactWithMembershipAndPendingContribution();

$data = $bag->toArray();

// Canonical keys defined by the bag schema:
$contactId      = $data['contactId'];        // int
$membershipId   = $data['membershipId'];     // int|null
$contributionId = $data['contributionId'];   // int|null
```

Full Example
------------

[](#full-example)

```
