---
title: Specimen builders and specifications
description: How ISpecimenBuilder nodes and IRequestSpecification filters compose into AutoFixture's kernel graph.
---

AutoFixture resolves every `Create` call through a **graph of specimen builders**. Each node answers one question: *given this request, can I produce a specimen?*

This article is about that **kernel graph** — builders, specifications, and how they connect. It is not about nested object graphs produced by `Create<T>()`; see [Specimen graphs](/docs/fundamentals/specimen-graphs) for that.

## What is a specimen builder?

A **specimen builder** implements `ISpecimenBuilder`:

```csharp
public interface ISpecimenBuilder
{
    object Create(object request, ISpecimenContext context);
}
```

- **Request** — what AutoFixture is trying to create. Often a `Type` (`typeof(ClientDto)`), but also `ParameterInfo`, `PropertyInfo`, or custom objects.
- **Context** — `ISpecimenContext.Resolve` creates dependent specimens (constructor arguments, property values, nested types).
- **Result** — a specimen, or `NoSpecimen.Instance` to decline and let the next builder try.

Builders form a **chain of responsibility**. `CompositeSpecimenBuilder` runs children in order until one returns a specimen. See [Specimen pipeline](/docs/advanced/specimen-pipeline) for where customizations, the engine, and residue collectors sit in the full layout.

## The specification pattern

A **request specification** (`IRequestSpecification`) decides whether a request matches a rule:

```csharp
public interface IRequestSpecification
{
    bool IsSatisfiedBy(object request);
}
```

This is the [Specification pattern](https://en.wikipedia.org/wiki/Specification_pattern) applied to specimen **requests**, not to domain objects. Specifications answer: *should this builder handle this request?*

AutoFixture ships many built-in specifications, including:

| Specification | Matches |
| --- | --- |
| [`ExactTypeSpecification`](/api/autofixture/5-0-0-rc-1/autofixture.kernel.exacttypespecification) | A `Type` request equal to a target type |
| [`ParameterSpecification`](/api/autofixture/5-0-0-rc-1/autofixture.kernel.parameterspecification) | A constructor parameter by type and name |
| [`PropertySpecification`](/api/autofixture/5-0-0-rc-1/autofixture.kernel.propertyspecification) | A writable property by type and name |
| [`AbstractTypeSpecification`](/api/autofixture/5-0-0-rc-1/autofixture.kernel.abstracttypespecification) | Interface or abstract class `Type` requests |
| [`AndRequestSpecification`](/api/autofixture/5-0-0-rc-1/autofixture.kernel.andrequestspecification) | All of several specifications |

You can implement `IRequestSpecification` when built-in filters are not enough.

## Specifications plus builders as a graph

Most kernel nodes combine **filter + action**:

| Node | Role |
| --- | --- |
| [`FilteringSpecimenBuilder`](/api/autofixture/5-0-0-rc-1/autofixture.kernel.filteringspecimenbuilder) | Runs an inner builder only when a specification matches |
| [`CompositeSpecimenBuilder`](/api/autofixture/5-0-0-rc-1/autofixture.kernel.compositespecimenbuilder) | Tries child builders in order |
| [`TypeRelay`](/api/autofixture/5-0-0-rc-1/autofixture.kernel.typerelay) | Maps one `Type` request to another (uses `ExactTypeSpecification` internally) |
| [`FixedBuilder`](/api/autofixture/5-0-0-rc-1/autofixture.kernel.fixedbuilder) | Always returns the same specimen |

`Fixture` wires these into a deep graph at startup — `CompositeSpecimenBuilder` chains for dictionaries and lists, `TypeRelay` nodes in residue collectors for `IList<>`, `FilteringSpecimenBuilder` nodes for invariant culture, and more. Your `Customizations.Add` calls append nodes to the front of that graph.

Think of it as a **graph of specification-gated builders**: each edge is *if specification matches, run this builder (which may call `context.Resolve` and trigger more of the graph)*.

## Example scenario

You are testing `PricingService`, which depends on `IOrderRepository` and a `currency` string constructor parameter. You want a concrete in-memory repository and a fixed currency code without hand-writing the service in every test.

## Example

**Built-in relay** — map interface `Type` requests to a concrete class:

```csharp
var fixture = new Fixture();
fixture.Customizations.Add(
    new TypeRelay(typeof(IOrderRepository), typeof(InMemoryOrderRepository)));
```

**Built-in specification + builder** — pin the `currency` parameter:

```csharp
fixture.Customizations.Add(
    new FilteringSpecimenBuilder(
        new FixedBuilder("EUR"),
        new ParameterSpecification(typeof(string), "currency")));
```

**Custom specification** — only handle `decimal` property requests named `MinimumOrderAmount`:

```csharp
fixture.Customizations.Add(
    new FilteringSpecimenBuilder(
        new FixedBuilder(25m),
        new MinimumOrderAmountPropertySpecification()));

var service = fixture.Create<PricingService>();

Assert.IsType<InMemoryOrderRepository>(service.Repository);
Assert.Equal("EUR", service.Currency);
Assert.Equal(25m, service.MinimumOrderAmount);

public sealed class MinimumOrderAmountPropertySpecification : IRequestSpecification
{
    public bool IsSatisfiedBy(object request)
    {
        return request is PropertyInfo property
            && property.PropertyType == typeof(decimal)
            && property.Name == nameof(PricingService.MinimumOrderAmount);
    }
}
```

`TypeRelay` and `FilteringSpecimenBuilder` are composed with built-in specifications. `MinimumOrderAmountPropertySpecification` is custom, but plugs into the same graph shape.

## How it works

- Every `Create<T>()` enters the graph with a `Type` request; reflection triggers subsidiary requests for parameters and properties.
- `FilteringSpecimenBuilder` returns `NoSpecimen.Instance` when the specification fails — the composite moves to the next sibling.
- `TypeRelay` does not construct directly; it calls `context.Resolve` for the target type, re-entering the graph.
- Customizations prepend nodes; residue collectors append fallbacks after the engine. Same builder types, different positions.

Prefer [Register](/docs/fundamentals/customizations), [Customize](/docs/fundamentals/customizations), and [Build DSL](/docs/fundamentals/build-dsl) when they express your rule. Reach for specification-gated builders when you need precise control over **which requests** in the graph are affected.

## Next steps

- [Overview](/docs/advanced/overview)
- [Specimen pipeline](/docs/advanced/specimen-pipeline)
- [Customizations](/docs/fundamentals/customizations)

## API

- [`ISpecimenBuilder`](/api/autofixture/5-0-0-rc-1/autofixture.kernel.ispecimenbuilder)
- [`IRequestSpecification`](/api/autofixture/5-0-0-rc-1/autofixture.kernel.irequestspecification)
- [`FilteringSpecimenBuilder`](/api/autofixture/5-0-0-rc-1/autofixture.kernel.filteringspecimenbuilder)
- [`TypeRelay`](/api/autofixture/5-0-0-rc-1/autofixture.kernel.typerelay)
- [Kernel namespace](/api/autofixture/5-0-0-rc-1/autofixture.kernel)
