问题描述
我正在使用 Bogus 生成测试数据,但我有一些字段依赖于另一个对象的部分(我希望为每一代随机选择),但必须彼此一致。
这可能不是最好的解释,所以希望这个例子能更好地解释它。
我有一个 Order
,其中包含来自 Customer
的 ID 和货币。
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; }
}
var customerFaker =
new Faker<Customer>()
.StrictMode(true)
.RuleFor("Id",f => f.Random.Guid())
.RuleFor("Id",f => f.Finance.Currency());
var customers = customerFaker.Generate(10);
但是当涉及到“共享”在订单生成器中的规则之间选择的客户时,我陷入了困境:
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);
我想出了一些不太理想的方法(比如每次实例化一个新的 Faker 并随机传入一个客户),但我正在处理非常复杂的对象和依赖项,所以我会如果可能的话,希望避免这种情况。
我目前的想法是,最好的方法可能是扩展 Order
类以便能够存储 Customer
,然后稍后将其转换回订单。考虑到我需要执行此操作的模型数量,我希望尽可能避免这种情况。
public class OrderWithCustomer : Order
{
public Customer Customer { get; set; }
}
var orderWithCustomerFaker =
new Faker<OrderWithCustomer>()
.StrictMode(true)
.RuleFor("Id",f => f.Finance.Amount())
.RuleFor("Customer",f => f.PickRandom(customers))
.RuleFor("CustomerId",(f,o) => o.Customer.Id)
.RuleFor("Currency",o) => o.Customer.Currency);
var orders =
orderWithCustomerFaker
.Generate(10)
.Select(withCustomer => (Order)withCustomer);
解决方法
虽然 Bogus 提供了生成所有随机数据的好方法,但当您需要根据现有关系进行链接时,您不想再次获得随机数据。相反,在此后期步骤中,您希望根据之前的分配选择现有数据。
首先,您将所有 customers
生成为 List<Customer>
:
var customerFaker = new Faker<Customer>()
.StrictMode(true)
.RuleFor("Id",f => f.Random.Guid())
.RuleFor("Id",f => f.Finance.Currency());
var customers = customerFaker.Generate(10);
您可以直接访问该列表并在所需值中匹配/查找(通过自定义方法或使用 Linq):
using System.Linq; //for linq method,add at the top of file
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)
//Assuming that you implement your GetById() method or something similar
.RuleFor("Currency",(f,o) => customers.GetById(o.CustomerId).Currency);
//Or directly by using linq
.RuleFor("Currency",o) => customers.First(c => c.Id == o.CustomerId).Currency);
这一切都应该有效,因为 RuleFor()
中的第二个参数是一个 setter
,它将值分配给属性。你甚至可以这样做:
var orderFaker = new Faker<Order>()
.RuleFor("Currency",f => "EUR");