nimbus fixture Account Contact reads the schema your Salesforce Apex tests already run against and writes a create<SObject>() method per object, with the required fields filled in. Not a template you adapt - output that matches this org. Free.
Every Salesforce project ends up with a test data factory, and every one of them is written the same way: insert a record, read the REQUIRED_FIELD_MISSING, add a field, run it again. The information was in the schema the whole time. This command reads it.
Nimbus executes your tests against an embedded PostgreSQL shaped by your org's real describes. The factory generator reads that schema - not a bundled approximation of it, and not the object definitions in your repo. It is the reason the generated class compiles and inserts on the first try instead of the fourth.
Standard objects work with no setup: Nimbus ships their describes. Custom objects need one nimbus sync first - after that they generate exactly like standard objects, including their required fields and their picklist value sets.
Nimbus already holds a describe for every object your tests run against. The generator reads that same schema - which fields are required, which are createable, what a picklist actually allows.
Required, createable fields get a literal of the right type. Picklists get a real value from the field's value set, because a restricted picklist rejects anything else. OwnerId is skipped - it populates itself on insert.
A required lookup pulls its parent object into the factory even if you never named it, and the methods come out parents-first so they can be inserted in that order.
A picklist with no value set in the local schema, a field type with no sensible default, a required parent with no schema at all - each becomes a named TODO plus a warning, never a fabricated value.
Three objects, one command. Account and Contact need one required field each. Contract needs a status - and an account to hang off.
Status is a restricted picklist, so the value comes from the field's own value set rather than a placeholder that would be rejected on insert.
The output is deterministic: the same project generates the same file every time, so regenerating after a schema change produces a diff you can actually review.
# Print a factory for three objects
nimbus fixture Account Contact Contract
# Save it into the default package
nimbus fixture Contract --write
# Name it something else
nimbus fixture Contract --class BillingFactory --write@IsTest
public class TestDataFactory {
static Account createAccount() {
return new Account(
Name = 'Test'
);
}
static Contact createContact() {
return new Contact(
LastName = 'Test'
);
}
static Contract createContract() {
// TODO: required lookup AccountId (lookup to Account) — set after inserting its parent
return new Contract(
Status = 'In Approval Process'
);
}
// Inserts the required parents, then returns an un-inserted Contract wired to them.
static Contract createContractWithParents() {
Account parent0 = createAccount();
insert parent0;
Contract record = createContract();
record.AccountId = parent0.Id;
return record;
}
}Note that Account appears in the output above even though Contract needs it - and it would appear even if you had never typed it. A required lookup pulls its parent in, and the methods are emitted parents-first so the chain can be inserted in order.
But createContract() still leaves AccountId unset, with a TODO naming the field and the object it points at. That is deliberate. Which account a contract belongs to is a decision your test is making; a generator that silently picks one has made it for you, invisibly, in every test that calls the method.
createContractWithParents() is the explicit opt-in: it inserts a fresh parent and wires the child to it. You choose which one you want at the call site, and the choice is visible in the test.
// I already have an account
Contract c = TestDataFactory.createContract();
c.AccountId = existingAccount.Id;
insert c;
// I just need a valid contract
Contract c = TestDataFactory
.createContractWithParents();
insert c;nimbus sync - never a call to a method that was never generated, which would produce a factory that does not compile.The command has a small surface on purpose. Everything else it needs it reads from the schema.
Writes the class and its -meta.xml into the project's default package and prints the path. Without it, the class goes to stdout - pipe it, diff it, or read it before you commit to anything.
Defaults to TestDataFactory. Set it when the name is taken, or when you want one factory per domain - nimbus fixture Contract --class BillingFactory.
Defaults to 62.0. Only used with --write, since stdout has no metadata file to stamp.
-o/--org and --profile flags, if the schema you want to generate from belongs to a different org or config profile than your default. Full reference at /docs/run-and-test#cmd-fixture.nimbus fixture generates a starting point, not a test data strategy. It gets you a class that compiles and inserts; what you build on top of it is the part that matters, and the tradeoffs there are real ones.
We wrote up those tradeoffs separately - static factory methods against the builder pattern, when Test.loadData and a static resource beat both, and why a @testSetup block that creates everything for everyone tends to age badly: Apex test data factories.
Generation is also a reasonable answer to a factory that has drifted. Regenerate against the current schema, diff it against what you have, and the required fields somebody added in the org three months ago show up as a line in the diff rather than as a failing insert.
@IsTest
private class ContractServiceTest {
@TestSetup
static void setup() {
insert TestDataFactory
.createContractWithParents();
}
@IsTest
static void activatesApprovedContracts() {
Contract c = [SELECT Id, Status FROM Contract LIMIT 1];
Test.startTest();
ContractService.activate(c.Id);
Test.stopTest();
// ...
}
}The required fields are already in the schema Nimbus runs your tests against. nimbus fixture reads them and hands you the class. Free, no org connection needed for standard objects.