https://github.com/cesarparra/test-data-framework
The Salesforce Test Data Builder framework allows you to intuitively create Salesforce SObject data for your unit tests using a fluent language. It provides base support for any SObject, standard or custom, out of the box, but allows you to adapt it to your custom needs.
https://github.com/cesarparra/test-data-framework
apex framework salesforce salesforce-developers salesforcedx sfdx testing unit-testing
Last synced: about 1 month ago
JSON representation
The Salesforce Test Data Builder framework allows you to intuitively create Salesforce SObject data for your unit tests using a fluent language. It provides base support for any SObject, standard or custom, out of the box, but allows you to adapt it to your custom needs.
- Host: GitHub
- URL: https://github.com/cesarparra/test-data-framework
- Owner: cesarParra
- License: mit
- Created: 2022-03-16T20:43:18.000Z (about 3 years ago)
- Default Branch: main
- Last Pushed: 2022-04-15T12:55:45.000Z (about 3 years ago)
- Last Synced: 2025-03-14T17:03:37.808Z (about 2 months ago)
- Topics: apex, framework, salesforce, salesforce-developers, salesforcedx, sfdx, testing, unit-testing
- Language: Apex
- Homepage: https://github.com/cesarParra/test-data-framework
- Size: 7.73 MB
- Stars: 6
- Watchers: 1
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
Salesforce Test Data Builder
Easy and intuitive way to create Salesforce unit test data.
Documentation
·
Report Bug
·
Request Feature
## 💡 About
The Salesforce Test Data Builder framework allows you to intuitively create Salesforce SObject data for your
unit tests using a fluent language.It provides base support for any SObject, standard or custom, out of the box, but allows you
to adapt it to your custom needs.## 🏁 Getting Started
### 🏃 Deploying
To deploy clone or download this repo and push the contents of `force-app/main/default/classes` to your org.
### Usage
#### Quick Start
Tip: See the `IntegrationTests` class for more in depth example usages of the framework.
A record can be created through the following syntax
```apex
Contact anyContact = (Contact)SObjectTestDataBuilder.of(Contact.SObjectType).registerNewForInsert();
SObjectTestDataBuilder.commitRecords();
````SObjectTestDataBuilder.of` receives an `SObjectType` for the type of record that you want to create. Calling
`registerNewForInsert` on the returned object will queue up the record for bulk insertion once
`SObjectTestDataBuilder.commitRecords()` gets called.You can also create multiple records by using the `registerNewForInsert` overload that takes the number
of records to create```apex
List multipleContacts = (List)SObjectTestDataBuilder.of(Contact.SObjectType).registerNewForInsert(5);
SObjectTestDataBuilder.commitRecords();
```By default, the framework will try to resolve for any required fields on the SObject. In the `Contact` example,
the `LastName` field is a required text field, so the framework will use a `String` from the `DefaultTestData`
class to fill up that field.Feel free to modify that class to change the defaults for any of the different field types.
During record creation you can also explicitly specify any field data you want to create by chaining `with` calls
and passing an SObjectField and a value:```apex
Contact anyContact = (Contact)SObjectTestDataBuilder.of(Contact.SObjectType)
.with(Contact.FirstName, 'John')
.with(Contact.LastName, 'Smith')
.registerNewForInsert();
SObjectTestDataBuilder.commitRecords();
```#### Relationships
When creating test data you might want to also create relationship records, either parent-to-child
or child-to-parent, which are both supported by the framework.To create a **parent-to-child** relationship you can use the `withChild` method:
```apex
Account accountWithChild = (Account)SObjectTestDataBuilder.of(Account.SObjectType)
.withChild(
SObjectTestDataBuilder.of(Contact.SObjectType),
Contact.AccountId
)
.registerNewForInsert();
SObjectTestDataBuilder.commitRecords();
```The `withChild` method takes 2 arguments: a builder for the child (which can be obtained by calling `SObjectTestDataBuilder.of`)
and the relationship field between the 2 objects.**Retrieving child records**
Once the records have been inserted to the database (after the call to `SObjectTestDataBuilder.commitRecords()`) you do not
need to query the database to get the reference to the children. Instead, the framework keeps a reference of all inserted records
so you can retrieve the children by using the `SObjectTestDataBuilder.getChildrenOfTypeById` method:```apex
List accountChildren = SObjectTestDataBuilder.getChildrenOfTypeById(accountWithChild.Id, Contact.SObjectType);
```To create **child-to-parent** relationships the framework has the concept of "late binding", which is a way to specify
a relationship between objects without calling the database until necessary for bulkification purposes.The late binding is used with the regular `with` method that is used to specify any field value. But instead
of passing a record ID value (which *is* valid as well, but will not take advantage of bulkification) you pass
in a `SObjectTestDataBuilder.LateBinding` object, which can be obtained by calling the `SObjectTestDataBuilder.lateBinding`
method:```apex
SObjectTestDataBuilder.of(OrderItem__c.SObjectType)
.with(OrderItem__c.Order__c, SObjectTestDataBuilder.lateBinding(Order__c.SObjectType))
.registerNewForInsert();
SObjectTestDataBuilder.commitRecords();
```This will create both the `OrderItem__c` and the parent `Order__c`.
#### Custom Builders
When creating SObjects you will probably want more control over the data than what the default builder gives you. The framework
also allows you to create custom builders for different SObjectTypes.To create a custom builder you will need to **both** extend `SObjectTestDataBuilder` and implement `ITestDataBuilder`.
For the framework to automatically detect your custom builder it also **needs* to have a name that ends in `TestDataBuilder`
(though there is a way to explicitly specify the builder to the framework, explained below).Any custom builder should start with some boilerplate code that looks as follows:
```apex
@IsTest
public with sharing class OrderTestDataBuilder extends SObjectTestDataBuilder implements ITestDataBuilder {
public override SObjectType getSObjectType() {
return Order__c.SObjectType;
}public OrderTestDataBuilder with(SObjectField field, Object value) {
return (OrderTestDataBuilder) withData(field, value);
}public Order__c registerNewForInsert() {
return (Order__c) this.registerSObjectForInsert();
}public List registerNewForInsert(Integer numberOfRecords) {
return this.registerSObjectsForInsert(numberOfRecords);
}public OrderTestDataBuilder withChild(ITestDataBuilder childBuilder, SObjectField relationshipField) {
return (OrderTestDataBuilder)this.withChildData(childBuilder, relationshipField);
}protected override Map getDefaultValueMap() {
return new Map {
Order__c.Customer__c => bindTo(SObjectTestDataBuilder.of(Account.SObjectType))
};
}
}
```Creating a custom builder gives you the following functionality:
* Allows you to create additional `withSomeField` method, which will make your code more fluent
* You can optionally override the `getDefaultValueMap` method, which will allow you to create default data tailored to the SObject.
* Note by the example that you can use late binding by calling the `bindTo` method automatically provided to you when extending `SObjectTestDataBuilder`.
* You can optionally override the `beforeInsert` and `afterInsert` methods, which will allow you to execute code before and after hitting the database for the insertion of your records.#### Default resolution vs. Explicitly specifying
By default, the framework will look for any class that ends with `TestDataBuilder` to try and automatically resolve with test data builder to use.
When one is not found then the `DefaultTestDataBuilder` will be used, which will attempt to resolve required fields with default data. But you can also
explicitly specify which builder to use to the framework in the unit test itself, in case you want to either override the automatic resolution and use a different builder,
or if you simply don't want to follow the naming convention.You can do that by using the `SObjectTestDataBuilder.registerBuilder` method:
```apex
SObjectTestDataBuilder.registerBuilder(Order.SObjectType, CustomOrderBuilder.class);
```### 🧪 Tests
This repo provides the `IntegrationTests` class with examples of all functionality provided by the framework. The
`kitchenSinkExample` provides an example of a complex hierarchy of objects.## 🚧 Roadmap
* [ ] Release as unmanaged package
* [ ] In-memory support## 🤝Contributing
Contributions are always welcome!
## ⚖️License
Distributed under the MIT License. See LICENSE file for more information.