2

我正在使用Bogus生成测试数据,但我有一些字段依赖于另一个对象的部分(我希望为每一代随机选择)但必须彼此一致。

这可能不是最好的解释,所以希望这个例子能更好地解释它。

我有一个Order包含来自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; }
}

我可以使用以下方法生成一些客户:

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.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);
4

2 回答 2

2

虽然 Bogus 可以很好地生成所有随机数据,但当您需要基于现有关系进行链接时,您不想再次获得随机数据。相反,在此后期步骤中,您希望根据先前的分配选择现有数据。

起初,您正在生成所有customersas 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", (f,o) => customers.First(c => c.Id == o.CustomerId).Currency);

这一切都应该起作用,因为第二个参数 inRuleFor()setter将值分配给属性。你甚至可以这样做:

var orderFaker = new Faker<Order>()
    .RuleFor("Currency", f => "EUR");
于 2021-01-25T20:16:52.943 回答
0

您可以从 Faker 扩展类并为该类添加一个字段,女巫可以容纳客户。像这样:

public class Customer
{
    public Guid Id { get; set; }
    public string Currency { get; set; }
    public List<Order> Orders { 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; }
}



public sealed class OrderFaker : Faker<Order>
{
    private Customer? _customer;
    public OrderFaker()
    {
        _customer = null;
            
        StrictMode(true)
            .RuleFor(o => o.Id, f => f.Random.Guid())
            .RuleFor(o => o.CustomerId, _ => _customer!.Id)
            .RuleFor(o => o.Amount, f => f.Finance.Amount())
            .RuleFor(o => o.Currency, f =>  _customer!.Currency);
    }
    
    public OrderFaker With(Customer customer)
    {
        _customer = customer;
        return this;
    }
}

public sealed class CustomerFaker : Faker<Customer>
{
    private readonly OrderFaker _orderFaker = new();
    public CustomerFaker()
    {

        StrictMode(true)
            .RuleFor(c => c.Id, f => f.Random.Guid())
            .RuleFor(c => c.Currency, f => f.Finance.Currency().Code)
            .RuleFor(c => c.Orders, (f, c) => _orderFaker.With(c).Generate(f.Random.Int(3, 5)).ToList());
    }
}

之后,您可以调用new CustomerFaker().Generate(150)以生成 150 个客户,其中包含 3 到 5 个相互关联的订单。

编辑:固定货币。

于 2022-02-23T18:18:51.963 回答