Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Auto Populate by Convention? #8

Closed
bchavez opened this issue Nov 10, 2015 · 9 comments
Closed

Feature: Auto Populate by Convention? #8

bchavez opened this issue Nov 10, 2015 · 9 comments

Comments

@bchavez
Copy link
Owner

bchavez commented Nov 10, 2015

Just thought:

Possibly have a method that can auto-populate a domain/DTO object if certain property conventions are met.

IE: when auto populating an object, if properties such as SSN and Phone or Telephone are encountered, auto populate them without having to setup fluent rules for that property.

I think it would reduce the amount of setup required to get started.

@salixzs
Copy link
Contributor

salixzs commented Nov 12, 2015

I believe this is great idea. I would very much welcome it.
Also usual suspects, like "firstname", "lastname", "surname" :-)

@gdimauro
Copy link

gdimauro commented Oct 11, 2016

I've just implemented a helper class for using attributes for generating rules directly from entities. Just going to use this extensively in a very big app. Here an example:

[Fixtures(Locale = "it", Strict = true)]
public partial class Persona : TenantBaseEntity
{
public const string FixturesRuleSetPersonaGiuridica = "PersonaGiuridica";
public const string FixturesRuleSetPersonaFisica = "PersonaFisica";

[Fixture(null, RuleSets = FixturesRuleSetPersonaGiuridica)]
[Fixture("@=Name.FirstName()")]
public virtual string Nome { get; set; }

[Fixture(null, RuleSets = FixturesRuleSetPersonaGiuridica)]
[Fixture("@=Name.LastName(Bogus.DataSets.Name.Gender.Male)")]
public virtual string Cognome { get; set; }

...

@opoani
Copy link

opoani commented Oct 19, 2016

Hi. This sounds great are there any examples/documentations based on this helper ?

@oddbear
Copy link

oddbear commented Feb 21, 2017

As the Faker has virtual methods for generate/validate/etc., this might be best to implement as something like inheritance from Faker (ex. AutoFaker), with overrides of those methods?

Edit:
It's a easy hack. A example of the direction I would have liked here:

void Main()
{
   var clients = new AutoFaker<Test>()
      .RuleFor(u => u.Something, f => f.Finance.Account());
	
   clients.Generate().Dump();
}

public class AutoFaker<T> : Faker<T>
   where T : class
{
   private string _autofakerset;

   public AutoFaker()
   {
      _autofakerset = Guid.NewGuid().ToString();
      var properties = typeof(T).GetProperties();
      var firstname = properties.SingleOrDefault(p => "FirstName".Equals(p.Name, StringComparison.OrdinalIgnoreCase));
      if (firstname != null)
      {
         var propName = firstname.Name;

         base.Actions.Add(_autofakerset, propName, new PopulateAction<T>
         {
            Action = (a, b) => base.FakerHub.Person.FirstName,
            RuleSet = currentRuleSet,
            PropertyName = propName
         });
      }
   }
	
   public override T Generate(string ruleSets = null)
   {
      var instance = base.Generate(_autofakerset);
      base.Populate(instance, ruleSets);
      return instance;
   }
}

public class Test
{
   public string FirstName { get; set; }
   public string Something { get; set; }
}

@oddbear
Copy link

oddbear commented Feb 23, 2017

Actual I think a better approach would be to have another method on the Faker class, similar to RuleFor, where we can extend the Faker with a ruleset.

This will not break the "pipeline", and could therefore be better with other features.
I think some great rules to extend the Faker with could be:

  • Add common names, like 'firstname' (done before the RuleFor rules).
  • Add something to everything (ex. garbage like string GUIDs on properties without rules)
  • Enforce DataAnnotations, (ex. only pick (or get a substring) of names less than MaxLenght, StringLenght etc.)
    Other features that could be nice, would be to insert some statistics to create failures(like some would be null, instead for firstname). And something like AutoFixture.

I don't see that this would be "mixable" with inheritance. But if the Faker had another method, that could take a set with rules, including predefined. This might be feasible.

Ex. :

//Need better namings, cleanup, etc.
void Main()
{
   var common = new CommonNames();
   var clients = new Faker<Test>()
      .RuleForKnown(common) //Something like this.
      .RuleFor(u => u.Something, f => f.Finance.Account());
      //could add something like:
      //.RulesForKnown(new DummyValues())
      //.RulesForKnown(new DataAnotations())

   clients.Generate().Dump();
}

public class Faker<T> : Bogus.Faker<T> //Implement body directly in Bogus.Faker<T>
   where T : class
{
   public Faker<T> RuleForKnown(CommonNames ruleSet)
   {
      if (ruleSet == null)
         return this;

      var properties = typeof(T).GetProperties();

      foreach (var rule in ruleSet.GetRules())
         foreach (var property in rule.Key.Invoke(properties))
            base.Actions.Add(base.currentRuleSet, property.Name, new Bogus.PopulateAction<T>
            {
               Action = (a, b) => rule.Value(FakerHub),
               RuleSet = base.currentRuleSet,
               PropertyName = property.Name
            });
      
      return this;
   }
}

public class CommonNames
{
   private readonly Dictionary<Func<PropertyInfo[], PropertyInfo[]>, Func<Bogus.Faker, object>> _rules;
   
   public CommonNames()
   {
      _rules = new Dictionary<Func<PropertyInfo[], PropertyInfo[]>, Func<Bogus.Faker, object>>();
      
      _rules[Filter("FirstName")] = f => f.Person.FirstName;
      _rules[Filter("LastName")] = f => f.Person.LastName;
      _rules[Filter("SurName")] = f => f.Person.LastName;
   }

   public Func<PropertyInfo[], PropertyInfo[]> Filter(string name)
      => propertyInfo => FilterPropertyName(propertyInfo, name ?? string.Empty);

   private PropertyInfo[] FilterPropertyName(PropertyInfo[] properties, string name)
      => properties
         .Where(p => name.Equals(p.Name, StringComparison.OrdinalIgnoreCase))
         .ToArray();

   public IEnumerable<KeyValuePair<Func<PropertyInfo[], PropertyInfo[]>, Func<Bogus.Faker, object>>> GetRules()
      => _rules.AsEnumerable();
}

public class Test
{
   public string FirstName { get; set; }
   public string LASTNAME { get; set; }
   public string surname { get; set; }
   public string Something { get; set; }
}

@bchavez
Copy link
Owner Author

bchavez commented Feb 23, 2017

I like your ideas @oddbear the last example almost looks like a good starting point for a decent implementation.

Some other API names I like (in order):

Faker<T>
  .ApplyConvention(new AutoNameConvention())
  .UseConvention(new AutoNameConvention()) 
  .AddConvention(new AutoNameConvention())
  .Conventions(new AutoNameConvention())

  .RuleConvention(new AutoNameConvention())
  .UsingConvention(new AutoNameConvention()) 
  .ByConvention

Then maybe have AutoFaker<T> have all built-in conventions applied. People could then pick Faker<T> or AutoFaker<T>.

AutoFaker<T> would be the dual of Faker<T> where Faker<T> would be where users build-rules up from scratch. AutoFaker<T> would have conventions applied (and any missing properties rules after conventions could be filled in by default with randomness), and users would work from a full ruleset overriding only the ones they care about.

☁️ ☀️ Bassnectar - Chasing Heaven - Into the Sun

This was referenced May 20, 2017
@bchavez
Copy link
Owner Author

bchavez commented Jun 19, 2017

Hi Everyone,

A special member of our community, @nickdodd79, is working on the core implementation of Bogus' Auto Population feature. Soon you'll be able to create instances of interfaces and abstract classes where interface/abstract class fields/properties are populated with Bogus' data sets. Basically, you'll be able to create a whole reference graph of objects with Bogus.

If you'd like to comment on the public API that is currently being formulated for this feature, please let us know in #74. We'd like to hear from everyone so we can get an over-arching view of how you'd expect to use the auto-population features in your projects.

Many thanks,

💭 🔍 "I want to know... what you're thinking..."

@SimonCropp
Copy link
Contributor

@bchavez looks like this one should be closed?

@bchavez
Copy link
Owner Author

bchavez commented Jun 23, 2021

@SimonCropp sounds good to me.

For those looking for an automatic solution, please checkout AutoBogus:
https://github.com/nickdodd79/AutoBogus

@bchavez bchavez closed this as completed Jun 23, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants