Giter Club home page Giter Club logo

soenneker.utils.autobogus's Introduction

Soenneker.Utils.AutoBogus

The .NET Autogenerator

This project is an automatic creator and populator for the fake data generator Bogus. It's a replacement for the abandoned AutoBogus library.

The goals:

  • Be fast
  • Support the latest types in .NET

It uses the fastest .NET Reflection cache: soenneker.reflection.cache. Bogus updates are automatically integrated.

.NET 6+ is supported.

Installation

dotnet add package Soenneker.Utils.AutoBogus

Usage

  • Create an AutoFaker instance:
var optionalConfig = new AutoFakerConfig();
var autoFaker = new AutoFaker(optionalConfig);
  • Call Generate<>() on any type you want:
var randomWord = autoFaker.Generate<string>();
var dictionary = autoFaker.Generate<Dictionary<int, string>>();
var order = autoFaker.Generate<Order>();
  • It's also possible to generate types via an argument:
var randomWord = autoFaker.Generate(typeof(string));
  • Set a faker, configuration, rules, etc:
autoFaker.Config.Faker = new Faker("de");
autoFaker.Config.RepeatCount = 3;
...

AutoFakerOverride

This is the recommended way for controlling type customization:

public class OrderOverride : AutoFakerOverride<Order>
{
    public override void Generate(AutoFakerOverrideContext context)
    {
        var target = (context.Instance as Order)!;
        target.Id = 123;
        
        // Faker is available
        target.Name = context.Faker.Random.Word();

        // AutoFaker is also available
        target.Customer = context.AutoFaker.Generate<Customer>();
     }
}

Then just add AutoFakerOverride to the AutoFaker.Config instance:

autoFaker.Config.Overrides = new List<AutoFakerGeneratorOverride>();
autoFaker.Config.Overrides.Add(new OrderOverride());

AutoFaker<T>

This inherits from Bogus.Faker, and can be used to designate rules specific to the AutoFaker instance.

var autoFaker = new AutoFaker<Order>();
autoFaker.RuleFor(x => x.Id, f => f.Random.Number());
var order = autoFaker.Generate();

Tips

  • โš ๏ธ Instantiating an AutoFaker takes a non-trivial amount of time because of Bogus Faker initialization (almost 1ms). It's recommended that a single instance be used if possible.
  • AutoFaker.GenerateStatic<T>() is also available, but should be avoided (as it creates a new AutoFaker/Faker on each call).

Notes

  • Some patterns that existed in AutoBogus have been removed due to the complexity and performance impact.
  • This is a work in progress. Contribution is welcomed.

Benchmarks

Soenneker.Utils.AutoBogus - AutoFaker

Method Mean Error StdDev
Generate_int 79.40 ns 0.635 ns 0.563 ns
Generate_string 241.35 ns 3.553 ns 3.324 ns
Generate_complex 6,782.34 ns 43.811 ns 38.837 ns

Soenneker.Utils.AutoBogus - AutoFaker<T>

Method Mean Error StdDev
Generate_string 283.6 ns 3.28 ns 3.07 ns
Generate_complex 8,504.0 ns 76.58 ns 67.89 ns

AutoBogus

Method Mean Error StdDev
Generate_int 1.17 ms 0.033 ms 0.026 ms
Generate_complex 10.91 ms 0.181 ms 0.236 ms

Bogus

Method Mean Error StdDev
Bogus_int 19.70 ns 0.176 ns 0.165 ns
Bogus_string 171.75 ns 2.763 ns 2.585 ns
Bogus_ctor 730,669.06 ns 8,246.622 ns 7,310.416 ns

soenneker.utils.autobogus's People

Contributors

pdevito3 avatar renovate[bot] avatar sergey-rybalkin avatar soenneker avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

soenneker.utils.autobogus's Issues

Generate fake from proto (gRPC) - class causes a fatal error / crashes the whole test runner process

When trying to create a fake from a generated class (gRPC object), the following error (crashes the whole test runner process) occurs:

Exit code is -1073741819 (Fatal error. Internal CLR error. (0x80131506)

Exit code is -1073741819 (Fatal error. Internal CLR error. (0x80131506)
   at System.Delegate.DelegateConstruct(System.Object, IntPtr)
   at System.RuntimeMethodHandle.InvokeMethod(System.Object, Void**, System.Signature, Boolean)
   at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(System.Object, System.Span`1<System.Object>, System.Reflection.BindingFlags)
   at System.Reflection.MethodBaseInvoker.InvokeWithFewArgs(System.Object, System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo)
   at System.Reflection.RuntimeConstructorInfo.Invoke(System.Reflection.BindingFlags, System.Reflection.Binder, System.Object[], System.Globalization.CultureInfo)
   at System.Reflection.ConstructorInfo.Invoke(System.Object[])
   at Soenneker.Reflection.Cache.Constructors.CachedConstructor.Invoke(System.Object[])
   at Soenneker.Utils.AutoBogus.AutoFakerBinder.CreateInstance[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]](Soenneker.Utils.AutoBogus.Context.AutoFakerContext, Soenneker.Reflection.Cache.Types.CachedType)
   at Soenneker.Utils.AutoBogus.Generators.Types.TypeGenerator`1[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].Soenneker.Utils.AutoBogus.Generators.Abstract.IAutoFakerGenerator.Generate(Soenneker.Utils.AutoBogus.Context.AutoFakerContext)
   at Soenneker.Utils.AutoBogus.AutoFakerBinder.CreateInstance[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]](Soenneker.Utils.AutoBogus.Context.AutoFakerContext, Soenneker.Reflection.Cache.Types.CachedType)
   at Soenneker.Utils.AutoBogus.Generators.Types.TypeGenerator`1[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].Soenneker.Utils.AutoBogus.Generators.Abstract.IAutoFakerGenerator.Generate(Soenneker.Utils.AutoBogus.Context.AutoFakerContext)
   at Soenneker.Utils.AutoBogus.AutoFakerBinder.PopulateMembers(System.Object, Soenneker.Utils.AutoBogus.Context.AutoFakerContext, Soenneker.Reflection.Cache.Types.CachedType, System.Collections.Generic.List`1<Soenneker.Utils.AutoBogus.AutoMember>)
   at Soenneker.Utils.AutoBogus.AutoFaker`1+<>c__DisplayClass19_0[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].<PrepareFinish>b__0(Bogus.Faker, System.__Canon)
   at Bogus.Faker`1[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].PopulateInternal(System.__Canon, System.String[])
   at Bogus.Faker`1[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].Generate(System.String)
   at Soenneker.Utils.AutoBogus.AutoFaker`1[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].Generate(System.String)
   at Bogus.Faker`1[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].op_Implicit(Bogus.Faker`1<System.__Canon>)

Here is the sample class which is generated by the C#-Protobuf compiler:

#nullable disable
namespace Google.Protobuf
{
  /// <summary>
  /// Generic interface for a Protocol Buffers message,
  /// where the type parameter is expected to be the same type as
  /// the implementation class.
  /// </summary>
  /// <typeparam name="T">The message type.</typeparam>
  public interface IMessage<T> : IMessage, IEquatable<T>, IDeepCloneable<T> where T : IMessage<T>
  {
    /// <summary>Merges the given message into this one.</summary>
    /// <remarks>See the user guide for precise merge semantics.</remarks>
    /// <param name="message">The message to merge with this one. Must not be null.</param>
    void MergeFrom(T message);
  }
}

 public sealed partial class ArticleCulture : pb::IMessage<ArticleCulture>
 #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
     , pb::IBufferMessage
 #endif
 {
   private static readonly pb::MessageParser<ArticleCulture> _parser = new pb::MessageParser<ArticleCulture>(() => new ArticleCulture());
   private pb::UnknownFieldSet _unknownFields;
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
   [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
   public static pb::MessageParser<ArticleCulture> Parser { get { return _parser; } }

   [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
   [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
   public static pbr::MessageDescriptor Descriptor {
     get { return global::Upper.ArticleConnector.Grpc.Contract.Lutz.ArticleCultureServiceReflection.Descriptor.MessageTypes[1]; }
   }

   [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
   [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
   pbr::MessageDescriptor pb::IMessage.Descriptor {
     get { return Descriptor; }
   }

   [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
   [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
   public ArticleCulture() {
     OnConstruction();
   }

   partial void OnConstruction();

   [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
   [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
   public ArticleCulture(ArticleCulture other) : this() {
     id_ = other.id_;
     name_ = other.name_;
     _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
   }

   [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
   [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
   public ArticleCulture Clone() {
     return new ArticleCulture(this);
   }

   /// <summary>Field number for the "id" field.</summary>
   public const int IdFieldNumber = 1;
   private string id_ = "";
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
   [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
   public string Id {
     get { return id_; }
     set {
       id_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
     }
   }

   /// <summary>Field number for the "name" field.</summary>
   public const int NameFieldNumber = 2;
   private string name_ = "";
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
   [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
   public string Name {
     get { return name_; }
     set {
       name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
     }
   }

   [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
   [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
   public override bool Equals(object other) {
     return Equals(other as ArticleCulture);
   }

   [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
   [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
   public bool Equals(ArticleCulture other) {
     if (ReferenceEquals(other, null)) {
       return false;
     }
     if (ReferenceEquals(other, this)) {
       return true;
     }
     if (Id != other.Id) return false;
     if (Name != other.Name) return false;
     return Equals(_unknownFields, other._unknownFields);
   }

   [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
   [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
   public override int GetHashCode() {
     int hash = 1;
     if (Id.Length != 0) hash ^= Id.GetHashCode();
     if (Name.Length != 0) hash ^= Name.GetHashCode();
     if (_unknownFields != null) {
       hash ^= _unknownFields.GetHashCode();
     }
     return hash;
   }

   [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
   [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
   public override string ToString() {
     return pb::JsonFormatter.ToDiagnosticString(this);
   }

   [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
   [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
   public void WriteTo(pb::CodedOutputStream output) {
   #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
     output.WriteRawMessage(this);
   #else
     if (Id.Length != 0) {
       output.WriteRawTag(10);
       output.WriteString(Id);
     }
     if (Name.Length != 0) {
       output.WriteRawTag(18);
       output.WriteString(Name);
     }
     if (_unknownFields != null) {
       _unknownFields.WriteTo(output);
     }
   #endif
   }

   #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
   [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
   void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
     if (Id.Length != 0) {
       output.WriteRawTag(10);
       output.WriteString(Id);
     }
     if (Name.Length != 0) {
       output.WriteRawTag(18);
       output.WriteString(Name);
     }
     if (_unknownFields != null) {
       _unknownFields.WriteTo(ref output);
     }
   }
   #endif

   [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
   [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
   public int CalculateSize() {
     int size = 0;
     if (Id.Length != 0) {
       size += 1 + pb::CodedOutputStream.ComputeStringSize(Id);
     }
     if (Name.Length != 0) {
       size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
     }
     if (_unknownFields != null) {
       size += _unknownFields.CalculateSize();
     }
     return size;
   }

   [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
   [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
   public void MergeFrom(ArticleCulture other) {
     if (other == null) {
       return;
     }
     if (other.Id.Length != 0) {
       Id = other.Id;
     }
     if (other.Name.Length != 0) {
       Name = other.Name;
     }
     _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
   }

   [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
   [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
   public void MergeFrom(pb::CodedInputStream input) {
   #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
     input.ReadRawMessage(this);
   #else
     uint tag;
     while ((tag = input.ReadTag()) != 0) {
       switch(tag) {
         default:
           _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
           break;
         case 10: {
           Id = input.ReadString();
           break;
         }
         case 18: {
           Name = input.ReadString();
           break;
         }
       }
     }
   #endif
   }

   #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
   [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
   [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
   void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
     uint tag;
     while ((tag = input.ReadTag()) != 0) {
       switch(tag) {
         default:
           _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
           break;
         case 10: {
           Id = input.ReadString();
           break;
         }
         case 18: {
           Name = input.ReadString();
           break;
         }
       }
     }
   }
   #endif
 }

Here is the code, that causes the error:

 ArticleCulture articleCulture = new AutoFaker<ArticleCulture>();

Please add a way to support internal properties/fields

At the moment internal fields/properties are "ignored", it would be great to give the user of your library the possibility to tell AutoBogus that internal properties/fields should be taken into account as well.

Maybe some kind of global switch (e.g BindingFlags) to enable it if needed.

Br

How do you customise the response for entities with properties that are set by the constructor?

If I have an object Person

public class Person
{
    public Person(string firstName, string lastName, int age)
    {
        FirstName = firstName;
        LastName = lastName;
        Age = age;
    }
    
    public string FirstName { get; }
    public string LastName { get; }
    public int Age { get; }
}

That I want to populate with AutoBogus. How can I customise the instantiation?

If I follow the documentation I believe I need the following:

public class PersonOverride : AutoFakerOverride<Person>
{
    public override void Generate(AutoFakerOverrideContext context)
    {
        var target = (context.Instance as Person)!;
        
        target.FirstName = context.Faker.Person.FirstName;
    }
}

However, that will not compile as the FirstName property does not have a public set accessor.

Drop in replacement?

Hi,

Thanks for creating this fork and awesome that soms issues has been solved.

From: nickdodd79/AutoBogus#108

Due to the performance issues and missing types etc I've decided to build an updated version of AutoBogus: soenneker.utils.autobogus

It aims to be a drop in replacement.

Is this really a drop in replacement?

  • I would expect that the version number would start with 2.14 (or 2.13.2), as the latest Bogus version is 2.13.1
  • There are many new dependencies in this package. Is that really needed? Sure we need the cache. But why the extensions, the smartenums etc. It would make it very hard to port the fixes to AutoBogus back when it's alive again
  • Why did we move from .NET Standard to .NET 6?
    • Also, why is the package multi-target package (compiled to .NET 6, 7 and 8)? Are there any code changes between .NET 6/7/8?
  • If we need breaking changes, is this possible? As it won't be a drop in replacement

Also, I'm not sure if the copyright is correct as most of the code is from AutoBogus
image
from: https://www.nuget.org/packages/Soenneker.Utils.AutoBogus

Last but not least, I'm not sure if the name of the forked package will help in making this package a succes. (it contains a username)

PS: there was already a fork (https://www.nuget.org/packages/AutoBogusLifesupport), but the repo's seems to be removed

Is there a way to always create an empty list instead of null

The current default behaviour is that lists within an object are always null if the property is e.g IReadonlyCollection, is there a way that AutoFaker always creates an empty list instead of null?

Is there a way to configure this, without creating a custom binder?

I would also like to create a FakeItEasy fake if the property of an object is an abstract or interface type?

Note:
With the original AutoFaker this was quite easy because the method of the class AutoFakerBinder: "CreateInstance(AutoFakerContext..)" was declared as virtual.

Br

(Performance idea) Code generation

Hello, Jake!

You've stated that one of this project goals is to Be fast.

I believe that using code generation is faster than using reflection, and (correct me if I'm wrong) current implementation of Binder is using the reflection. Are there any plans to use the code generation?

Extension methods configuration

I might be missing that this is already built-in, but it would be super awesome to be able to build configuration via With(e => e.Name), .Without, etc.. I understand it's slower, but subclassing overrides per-class kind of stinks - especially when I could have many different overrides for the same class, I feel like it's harder to grok. Thoughts?

Generate multiple creates nullable entries

When trying to generate multiple entities it's generating nullable entries. Seems it's not a drop-in replacement for AutoBogus. I am using NUnit as testing engine with parallel execution enabled.

Screenshot 2024-05-08 172610

Support abstract types

It should be possible to look up implementations of abstract classes in modules attached and generate that, rather than having to rely on other mocking libraries.

Private readonly fields - are overwritten/generated automatically

Hi,

With this fix: #143, private readonly fields are now also set automatically, is there a way to prevent/controll this with some kind of configuration (per type)?

This can cause issues when the field is initilized via constructor, because afterwards it's getting overwritten bei Autobogus.

Here is a very simple sample.

public class AnotherObjectToFake
{
    private readonly string _key;

    public AnotherObjectToFake(string key)
    {
        _key = key;
    }

    public string GetKey()
    {
        return _key;
    }
}

//test class
 [TestMethod]
 public void PrivateReadOnlyField_Should_Not_Be_Overwritten()
 {
     //arrange
     const string key = "someKey";

     //act
     AnotherObjectToFake objectToFake = new AutoFaker<AnotherObjectToFake>()
         .CustomInstantiator(_ => new AnotherObjectToFake(key));

     //assert
     objectToFake.GetKey().Should().Be(key);
 } 

image

Br

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.