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.81k stars 500 forks source link

Generate same CPF in Brazil extensions #340

Closed tborgesa closed 3 years ago

tborgesa commented 3 years ago

Version Information

Software Version(s)
Bogus NuGet Package 32.0.1
.NET Core? 3.1
Windows OS? 10
Visual Studio? 2019 Enterprise

What locale are you using with Bogus?

pt_BR

What is the expected behavior?

That Each time i invoker Person.Cpf() for the same instance of Faker generate diferent result, like a Company.Cnpj()

What is the actual behavior?

Faker generate the same result fot diferent invoke.

How do you reproduce the issue?

static void Main(string[] args)
        {
            var faker = new Faker("pt_BR");
            for (int i = 0; i < 500; i++)
            {
                Console.WriteLine(faker.Person.Cpf());
            }
        }
bchavez commented 3 years ago

Hi @tborgesa,

I think the code you're looking for is:

static void Main(string[] args)
{
   for (int i = 0; i < 500; i++)
   {
      var p = new Person("pt_BR");
      Console.WriteLine(p.Cpf());
   }
}

image


If you'd like to know why your code doesn't work, consider the following:

void Main()
{
   var faker = new Faker("pt_BR");

   faker.Person.FullName.Dump();
   faker.Person.FullName.Dump();
}

image

The reason faker.Person is the same on every property access is that faker.Person is only supposed to be used in Faker<T>.RuleFor( f => f.Person ). The f in .RuleFor( f => ...) is faker except that Faker<T> is creating the new person on every Faker<T>.Generate() call. The .RuleFor( f => f.Person ) context property needs to be the same object across multiple calls of Faker<T>.RuleFor( f => f.Person.__ ).

If you call a Property, it should be the same object. If you all a Method(), it should be a different return value.

I hope that helps! Brian

tborgesa commented 3 years ago

Hi @bchavez ,

Thanks for support. I understand that Person is te same.

Another question. Why the same scenario in the Company for Cnpj() works fine, even though the same instance.

Consider the following:

          static void Main(string[] args)
          {
            var faker = new Faker("pt_BR");

            Console.WriteLine("CPF");
            Console.WriteLine(faker.Person.Cpf());
            Console.WriteLine(faker.Person.Cpf());

            Console.WriteLine("CNPJ");
            Console.WriteLine(faker.Company.Cnpj());
            Console.WriteLine(faker.Company.Cnpj());
        }

Look at the result:

image

Thanks. Thiago.

bchavez commented 3 years ago

Hi @tborgesa,

The reason is:

faker.Person is an object https://github.com/bchavez/Bogus/blob/5219e22de7767ceb6bb64e4cff379f39ef84cf18/Source/Bogus/Person.cs#L12

faker.Company is a DataSet https://github.com/bchavez/Bogus/blob/5219e22de7767ceb6bb64e4cff379f39ef84cf18/Source/Bogus/DataSets/Company.cs#L9

DataSets do not contain contextually relevant data for use across multiple calls of Faker<T>:

Faker<T>
   .RuleFor(f=> f.Company.CompanName()) // no context needed "Box and Paper Company"
   .RuleFor(f=> f.Person.FirstName ) // person context needed! - "Brian"
   .RuleFor(f=> f.Person.Email ) // person context needed for first name in fake email - "brian587@yahoo.com"

faker.Person is the only object on Faker that is used for this purpose. faker.Person is purely a convenience property to store contextual information about a Person because there is no "C# Extension Property" in the C# language yet.


It was mostly a design decision. One way to clean this up, of course, is to inherit from Faker:

public class FakerForFakerT : Faker{

    public Person Person {get;set;}
}
public class Faker<T>...
{
   public FakerForFakerT faker = new FakerForFakerT();
   RuleFor(Expression property, Func<FakerForFakerT> setterAction);
}

But eh, I didn't feel it was worth going through the whole ceremony of managing two separate classes Faker and FakerForFakerT when they're basically the same thing just one derived class has a contextual "Person". Also, it would have made extending Bogus' Faker<T> slightly more complex.

Eventually, hopefully, someday "C# Extension Properties" will clean this up in the future.