nickdodd79 / AutoBogus

A C# library complementing the Bogus generator by adding auto creation and population capabilities.
MIT License
431 stars 50 forks source link

System.InvalidOperationException When Using Override #41

Closed tristangreeno closed 3 years ago

tristangreeno commented 4 years ago

I'm experiencing the following exception when using AutoFaker.Configure for global configuration (AutoFaker\<T> does not allow configurations for some reason). I am calling AutoFaker.Configure for each test because it's in the Setup method, and it seems that this will randomly cause issues. There doesn't seem to be a consistent way to reproduce this, but it happens every other run.


build   31-Jul-2020 14:48:05      X Tests.Generate_WithOkResponse_ReturnsTrueAndResults [1ms]
build   31-Jul-2020 14:48:05      Error Message:
build   31-Jul-2020 14:48:05       System.InvalidOperationException : Collection was modified; enumeration operation may not execute.
build   31-Jul-2020 14:48:05      Stack Trace:
build   31-Jul-2020 14:48:05         at System.Collections.Generic.List`1.Enumerator.MoveNextRare()
build   31-Jul-2020 14:48:05       at System.Linq.Enumerable.Any[TSource](IEnumerable`1 source, Func`2 predicate)
build   31-Jul-2020 14:48:05       at AutoBogus.AutoConfigBuilder.WithOverride[TBuilder](AutoGeneratorOverride generatorOverride, TBuilder builder)
build   31-Jul-2020 14:48:05       at AutoBogus.AutoConfigBuilder.AutoBogus.IAutoConfigBuilder<AutoBogus.IAutoFakerDefaultConfigBuilder>.WithOverride(AutoGeneratorOverride generatorOverride)
build   31-Jul-2020 14:48:05       at Tests.Utils.Generators.<>c.<.ctor>b__21_32(IAutoFakerDefaultConfigBuilder builder) in /buildeng/bamboo-agent-home/xml-data/build-dir/JOB1/Tests/Utils/Generators.cs:line 69
build   31-Jul-2020 14:48:05       at AutoBogus.AutoFaker.Configure(Action`1 configure)
nickdodd79 commented 4 years ago

Hi @tristangreeno

I suspect your issue is because your tests are being executed in parallel and so one test is overridding the config for another test whilst it is in flight. The static Configure method is aimed at setting the config once as opposed to for every test.

One approach to ensure your configuration is consistent for each test is to create an instance of the AutoFaker class, configure it in your setup and assign it to a variable accessible by your tests.

public void Setup()
{
    var faker = AutoFaker.Create(builder => ...);
}

public void Test1()
{
    faker.Generate<T>();
}

public void Test2()
{
    faker.Generate<T>();
}

Alternatively, you can configure at the Generate level and implement a static handler to provide any common config.

public void Test1()
{
    AutoFaker.Generate<T>(ConfigureFakes);
}

public void Test2()
{
    AutoFaker.Generate<T>(ConfigureFakes);
}

private static void ConfigureFakes(Action<IAutoGenerateConfigBuilder> builder)
{
    builder.abc(...);
}
tristangreeno commented 4 years ago

The issue I see with this is that the above approaches don't enable me to write Bogus .RuleFor configurations.

I need to use an override for AutoFaker<T>. AutoFaker.Create does not support generic types (like new AutoFaker<T>) for some reason. If it did, it would solve this issue.

The root of the problem I'm having is that AutoFaker<T> does not support setting overrides.

nickdodd79 commented 4 years ago

OK, I understand what you are trying to achieve and that AutoFaker<T>.Generate() doesn't support a configuration builder. I will look to get that added if I can. There may be a technical difficulty adding it, which is why it got excluded when the other config builders were added.

In the meantime, there is a work around using a sub class of AutoFaker<T> and the AutoFaker.Generate<TType, TFaker>() method.

public class PersonFaker: AutoFaker<Person>
{
    RuleFor(x => x.FirstName, f => "MyName");
}

public void Test()
{
    AutoFaker.Generate<Person, PersonFaker>(builder => ....);
}
nickdodd79 commented 4 years ago

Hey @tristangreeno

Just an update that I have been busy these last few weeks. Hoping to add the configuration builder to the Generate method this week.

Nick.

nickdodd79 commented 3 years ago

Hey @tristangreeno

I have released v2.11.0 which now provides a Configure() method on the AutoFaker<TType> class.

var fake = new AutoFaker<Person>()
    .Configure(builder => ...)
    .RuleFor(x => ...)
    .Generate();

Nick.

tristangreeno commented 3 years ago

Thanks Nick. I really appreciate the fast response.