I'm using Bogus to generate test data but I have some fields that depend on parts of another object (that I want to be chosen randomly for each generation) but that have to be consistent with each other.
That's probably not the best explanation so hopefully this example explains it better.
I have an Order
which includes the ID and currency from a Customer
.
public class Customer
{
public Guid Id { get; set; }
public string Currency { get; set; }
}
public class Order
{
public Guid Id { get; set; }
public Guid CustomerId { get; set; } // The ID of a customer
public string Currency { get; set; } // The currency for the customer identified by CustomerId
public decimal Amount { get; set; }
}
I can generate some customers using:
var customerFaker =
new Faker<Customer>()
.StrictMode(true)
.RuleFor("Id", f => f.Random.Guid())
.RuleFor("Id", f => f.Finance.Currency());
var customers = customerFaker.Generate(10);
But I get stuck when it comes to "sharing" the customer that's been chosen between rules in the order generator:
var orderFaker =
new Faker<Order>()
.StrictMode(true)
.RuleFor("Id", f => f.Random.Guid())
.RuleFor("Amount", f => f.Finance.Amount())
.RuleFor("CustomerId", f => f.PickRandom(customers).Id)
//How do I share the Customer that's been chosen to use it in the rule below?
.RuleFor("Currency", f => f.PickRandom(customers).Currency);
I've come up with a few less-than-ideal ways of doing it (like instantiating a new Faker each time and passing in a random customer) but I'm working with quite complicated objects and dependencies so I'd like to avoid that if possible.
My current thinking is that the best way might be to extend the Order
class to be able to store the Customer
and then cast it back to being an order later. I'd like to avoid this if possible given the number of models I'll need to do this for.
public class OrderWithCustomer : Order
{
public Customer Customer { get; set; }
}
var orderWithCustomerFaker =
new Faker<OrderWithCustomer>()
.StrictMode(true)
.RuleFor("Id", f => f.Random.Guid())
.RuleFor("Amount", f => f.Finance.Amount())
.RuleFor("Customer", f => f.PickRandom(customers))
.RuleFor("CustomerId", (f, o) => o.Customer.Id)
.RuleFor("Currency", (f, o) => o.Customer.Currency);
var orders =
orderWithCustomerFaker
.Generate(10)
.Select(withCustomer => (Order)withCustomer);
While Bogus provide great sake of generating all the random data, when you need to link based on existing relation, you don't want to get random stuff again. Instead, in this late step you want to select existing data based on previous assignment.
At first you are generating all your
customers
asList<Customer>
:You can just access that list directly and match/find inside the required value (via custom method or with Linq):
This all should work, because 2nd argument in
RuleFor()
is asetter
which assigns the value to property. You could even do this: