data_builder_test

A craft_runner builder that turns a plain schema class into an immutable fluent builder, for constructing test fixtures without a wall of map literals.

final body = const OrderBuilder()
    .withId('ord_1')
    .withTotal(4200)
    .build();          // => {'id': 'ord_1', 'total': 4200, 'status': 'pending'}

Every field you don't touch falls back to the default declared on the schema, so a test states only what it actually cares about.

Setup

dev_dependencies:
  data_builder_test: ^0.10.0

Declare the builder in craft_runner.yaml:

roots: [test]
exclude: ['.data_builder.dart']

builders:
  data_builder_test:DataBuilderCraftBuilder:

Then run craft_runner craft, or craft_runner watch to regenerate on save.

Writing a schema

Annotate a class with @dataBuilder, have it extend its own generated builder, and declare a part:

import 'package:data_builder_test/annotations.dart';

part 'order.data_builder.dart';

@dataBuilder
class Order extends OrderBuilder {
  String id = 'ord_1';
  int total = 0;
  String status = 'pending';

  @DataField(key: 'created_at')
  String? createdAt;
}

craft_runner writes order.data_builder.dart next to it containing OrderBuilder extends Buildable — a const default constructor, a withX(...) per field, and build(). All storage is private, and every withX returns a new instance.

@DataField

option effect
key map key to serialize under (defaults to the field name)
includeIfNull when false, the entry is dropped from build() if null
settable when false, no withX is generated and the field always serializes its default

Defaults

Defaults are not seeded through the constructor. Each field carries a private _<field>IsSet flag and build() emits isSet ? value : default, so an untouched field falls back to its declared initializer (or null). This keeps the const constructor trivial and avoids non-const collection literals in a const context.

Nested builders

A field whose type isn't a known scalar is treated as a nested builder: its storage type becomes <Type>Builder and build() serializes it recursively — value.build() for a single field, value.map((e) => e.build()).toList() for a List<...>.

@dataBuilder
class Cart extends CartBuilder {
  List<Order> orders = [];
}

const CartBuilder().withOrders([const OrderBuilder().withId('ord_2')]).build();

Notes

  • Parsing is syntactic only, inherited from craft_runner — the schema's fields must be declared on the class itself, not inherited from elsewhere.
  • Generated files end in .data_builder.dart; add that to exclude so the builder doesn't read its own output.

License

MIT

Libraries

annotations
data_builder_test
Barrel imported by craft_runner (data_builder_test:DataBuilderCraftBuilder). It exposes the build-time builder only — the annotations live in package:data_builder_test/annotations.dart so test sources can use them without pulling in the analyzer.