question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

AutoBogus taking too long to generate data

See original GitHub issue

I’ve come across a performance issue when using AutoFaker to generate test objects for use in unit tests.

I’ve been able to create a super simplified example of my domain model to demonstrate two things.

  1. AutoFaker generates way too many levels of data when it shouldn’t be generating data for levels beyond a reasonable level of nesting. Ideally the nesting level should be configurable…but at a max 2 levels would be more than enough for tests.
  2. AutoFaker becomes slower as a result and my real-world tests end up taking several minutes to complete rather than a few seconds.

Here is my unit test demonstrating the issue:

        [TestMethod]
        public void DemonstrateAutoFakerPerformanceIssue()
        {
            System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
            stopwatch.Start();

            var generator = new AutoBogus.AutoFaker<Document>();

            var document = generator.Generate();

            document.Indicator.ShouldNotBeNull();
            document.Indicator.Branch.ShouldNotBeNull();
            document.Indicator.Branch.Parent.ShouldBeNull();
            //document.Indicator.Branch.Documents.ShouldBeEmpty(); //Fails. Document should be populated. Indicator should be populated. Branch should have all its properties be default type. Or should be able to configure the generation depth.
            document.Indicator.Branch.Documents.First().Indicator.ShouldBeNull();
            document.Indicator.Branch.Documents.First().Branch.ShouldBeNull();


            document.Branch.ShouldNotBeNull();
            document.Branch.Documents.ShouldNotBeNull();
            document.Branch.Documents.ShouldNotBeEmpty();
            document.Branch.Documents.First().Branch.ShouldBeNull();
            //document.Branch.Documents.First().Indicator.ShouldBeNull(); //Fails.
            document.Branch.Documents.First().Indicator.Branch.ShouldBeNull();


            //Show that we are able to access populated properties that are much too deep. 
            var generator2 = new AutoBogus.AutoFaker<Sentence>();

            var sentence = generator2.Generate();
            sentence.Branch.ShouldNotBeNull();
            sentence.Paragraphs.ShouldNotBeNull();

            sentence.Branch.Documents.ShouldNotBeEmpty();
            sentence.Branch.Documents.First().Branch.ShouldBeNull();
            //sentence.Branch.Documents.First().Indicator.ShouldBeNull(); //Fails
            sentence.Branch.Documents.First().Indicator.Branch.ShouldBeNull();

            sentence.Branch.Paragraphs.ShouldNotBeEmpty();
            sentence.Branch.Paragraphs.First().Branch.ShouldBeNull();
            //sentence.Branch.Paragraphs.First().Sections.ShouldBeEmpty(); //Fails
            sentence.Branch.Paragraphs.First().Sections.First().Branch.ShouldBeNull();
            //sentence.Branch.Paragraphs.First().Sections.First().Pages.ShouldBeNull(); //Fails
            //sentence.Branch.Paragraphs.First().Sections.First().Pages.First().Documents.ShouldBeEmpty(); //Fails

            sentence.Branch.Paragraphs.First().Sections.First().Pages.First().Documents.First().Branch.ShouldBeNull();
            //sentence.Branch.Paragraphs.First().Sections.First().Pages.First().Documents.First().Indicator.ShouldBeNull(); //Fails

            sentence.Branch.Paragraphs.First().Sections.First().Pages.First().Documents.First().Indicator.Branch.ShouldBeNull();
            //sentence.Branch.Paragraphs.First().Sections.First().Pages.First().Documents.First().Indicator.Property.ShouldBeNullOrWhiteSpace(); //Fails

            stopwatch.Stop();

            stopwatch.ElapsedMilliseconds.ShouldBeLessThan(500);
        }

The following code represents a simplified version of my domain model. Please note that I’ve tried to make it make sense without giving away our exact domain model…modeling a document so that unique sentences can be applied to other paragraphs is not realistic…it was just the closest analogy that I could come up with. We basically have objects whose configuration needs to be tracked in branches (like version control). The links between objects are the foreign key relationships in the database and our entities are creating using Entity Framework.

The things that seem to contribute to the issue are:

  1. Having Branch reference all objects attached to that branch
  2. Having all entities have a base type that allows the branch to be specified seems to create
  3. Having entities be able to reference other types of entities
  4. Auto Faker seems to generate 3 children for every collection. Branch references all entities. Each entity also has a collection to track where else in the hierarchy they have been added. Each level in the hierarchy results in AutoFaker taking longer to generate.
        public class MyBranch
        {
            public string Property { get; set; }
            public MyBranch Parent { get; set; }

            public ICollection<MyBranch> Children { get; set; }

            public ICollection<Document> Documents { get; set; }
            public ICollection<Page> Pages { get; set; }
            public ICollection<PageSection> Sections { get; set; }

            public ICollection<Paragraph> Paragraphs { get; set; }

            public ICollection<Sentence> Sentences { get; set; }
        }

        public class EntityBase
        {
            public MyBranch Branch { get; set; }
        }

        public class Document : EntityBase
        {
            public string MyProperty { get; set; }
            public SpecialIndicator Indicator { get; set; }
            public OtherSpecialIndicator OtherIndicator { get; set; }
        }

        public class Page : EntityBase
        {
            public string MyProperty { get; set; }
            public OtherSpecialIndicator Indicator { get; set; }
            public ICollection<Document> Documents { get; set; } //documents where this page appears
        }

        public class PageSection : EntityBase
        {
            public string MyProperty { get; set; }
            public OtherSpecialIndicator Indicator { get; set; }
            public ICollection<Page> Pages { get; set; } //pages where this page section appears
        }

        public class Paragraph : EntityBase
        {
            public string MyProperty { get; set; }
            public OtherSpecialIndicator Indicator { get; set; }
            public ICollection<PageSection> Sections { get; set; } //sections where this paragraph has been used
        }

        public class Sentence : EntityBase
        {
            public string MyProperty { get; set; }
            public ICollection<Paragraph> Paragraphs { get; set; } //paragraphs where this sentance appears
        }

        public class SpecialIndicator : EntityBase
        {
            public string Property { get; set; }
        }

        //Adding this to other entities results in generation taking additional time
        public class OtherSpecialIndicator : EntityBase
        {
            public string Property { get; set; }
        }

Any thoughts on how this could be fixed? At the moment I am having to add rules so that for most objects Branch will be null or new Branch()…but it would be better if AutoBogus could stop itself from generating so many levels of data.

Issue Analytics

  • State:open
  • Created 5 years ago
  • Reactions:3
  • Comments:32 (13 by maintainers)

github_iconTop GitHub Comments

3reactions
nickdodd79commented, Mar 12, 2021

Hey All,

Thanks for effort of @Ian1971 I think we have a performance improvement in v2.13.0. It does involve using a WithTreeDepth() config handler.

I did some top level testing and a simple model that took 4s to generate now takes 18ms 👍

Nick.

1reaction
Ian1971commented, Feb 24, 2021

I’ve added a TreeDepth option in this PR. https://github.com/nickdodd79/AutoBogus/pull/64 This greatly helps improve performance for our use case (Xero api)

Read more comments on GitHub >

github_iconTop Results From Across the Web

AutoBogus
AutoBogus. A C# library complementing the Bogus generator by adding auto creation and population capabilities. The following packages are available for ...
Read more >
How to use AutoBogus/Bogus to generate a constant value ...
My objective is to configure every property type to a certain value and have AutoBogus auto-populate the objects based on my configuration. I ......
Read more >
Realistic Data Generation in .NET With Bogus
Learn how to generate realistic data with the Bogus .NET library and save your time when mocking data and seeding databases with EF...
Read more >
LPT: There is a library called Bogus, you should know it ...
Realize its magically generating fake data for a given object. ... in an integration test which takes significantly longer to track down.
Read more >
Mocking Data with Bogus
I've written previously on using Bogus to abstract away irrelevant values in unit testing, but I want to show you taking it one...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found