bchavez / Bogus

:card_index: A simple fake data generator for C#, F#, and VB.NET. Based on and ported from the famed faker.js.
Other
8.62k stars 491 forks source link

Generating dictionary values #469

Closed iveta-ivanova closed 1 year ago

iveta-ivanova commented 1 year ago

Version Information

Software Version(s)
Bogus NuGet Package 34.0.2
.NET Core? 7
.NET Full Framework?
Windows OS? 10
Linux OS? -
Visual Studio? 2022, 17.5.0

What locale are you using with Bogus?

en

What's the problem?

I have a Dto with a single field - a Dictionary<string,object>. I need to generate random values for each key in this dictionary. Doing this created a nested object and hence:

System.ArgumentException: 'Your expression 'row.Fields.get_Item("id")' cant be used. Nested accessors like 'o => o.NestedObject.Foo' at a parent level are not allowed. You should create a dedicated faker for NestedObject like new Faker().RuleFor(o => o.Foo, ...) with its own rules that define how 'Foo' is generated. See this GitHub issue for more info: https://github.com/bchavez/Bogus/issues/115'

What possible solutions have you considered?

Stackoverflow :)

Seriously, I can't think of a way I can fake any Dto with a dictionary field, without creating a nested object. Dto.Field.get_Item("id") - it appears unavoidable.

I haven't posted this as Issue or Feature request yet, in case I am missing something.

Do you have sample code to show what you're trying to do?

The Dto:

CustomerTableDto customerRow = new CustomerTableDto
            {
                Fields = new Dictionary<string, object>
                        {
                            { "id", 0 },
                            { "name",  "" },

                        }
            };

The erroneous Faker:

var CustomerTableDtoFaker = new Faker<CustomerTableDto>()
   .RuleFor(row => row.Fields["id"], f => f.PickRandom(idArray))
   .RuleFor(row => row.Fields["name"], f => f.PickRandom(namesArray))

(Please be complete. Provide all code necessary to run your example in LINQPad.) (The more complete code examples are, the more accurate answers will be.) (https://www.linqpad.net)

iveta-ivanova commented 1 year ago

I figured out the solution, just initializing the dictionary inline with the RuleFor statement and generating random dictionary values directly upon initialization (for anyone else's benefit :) )

bchavez commented 1 year ago

Thank you for posting the issue. Yep, in-lining the object creation in the .RuleFor is the correct way to handle the situation for now.

void Main()
{
   var faker = new Faker<CustomerTableDto>()
         .RuleFor( ctd => ctd.Fields, f =>
         {
            var fields = new Dictionary<string,object>();
            fields["id"] = f.Random.Number(1337);
            fields["name"] = f.Name.FirstName();
            return fields;
         });

   faker.Generate().Dump();
}

public class CustomerTableDto
{
   public Dictionary<string, object> Fields {get;set;}
}

image