I am trying to create a class to generate data for unit testing using autofixture. But in some case i don't want to generate nested Icollection classes because of circular reference.
This is what i have so far but i keep getting the following error: The weird thing about the error message is, it say something about circular reference with a Request class but the TEntity (LookupOption) don't have any reference to Request class.
DataGenerator Class
public static class DataGenerator
{
public static IEnumerable<TEntity> GenerateManyData<TEntity>(bool createNestedEntities)
where TEntity : class
{
var fixture = new Fixture();
var dataBuilder = fixture.Build<TEntity>();
if (createNestedEntities)
{
fixture.Behaviors.Remove(new ThrowingRecursionBehavior());
fixture.Behaviors.Add(new OmitOnRecursionBehavior());
}
else
{
foreach (var property in typeof(TEntity).GetProperties())
{
if (string.Equals(property.PropertyType.Name,"ICollection`1"))
{
dataBuilder.Without(BuildLambda<TEntity, object>(property.Name));
}
}
}
var data = dataBuilder.CreateMany();
return data;
}
private static Expression<Func<TEntity, TValue>> BuildLambda<TEntity, TValue>(string property)
where TEntity : class
where TValue : class
{
var param = Expression.Parameter(typeof(TEntity), "e");
var prop = Expression.PropertyOrField(param, property);
return Expression.Lambda<Func<TEntity, TValue>>(prop, param);
}
}
Error Message:
AutoFixture was unable to create an instance of type Ploeh.AutoFixture.Kernel.SeededRequest because the traversed object graph contains a circular reference. Information about the circular path follows below. This is the correct behavior when a Fixture is equipped with a ThrowingRecursionBehavior, which is the default. This ensures that you are being made aware of circular references in your code. Your first reaction should be to redesign your API in order to get rid of all circular references. However, if this is not possible (most likely because parts or all of the API is delivered by a third party), you can replace this default behavior with a different behavior: on the Fixture instance, remove the ThrowingRecursionBehavior from Fixture.Behaviors, and instead add an instance of OmitOnRecursionBehavior.
Path:
App.Domain.Entities.Request Parent -->
App.Domain.Entities.Request -->
App.Domain.Entities.Request Request -->
App.Domain.Entities.RequestLookupOption -->
System.Collections.Generic.IEnumerable1[App.Domain.Entities.RequestLookupOption] --> System.Collections.Generic.IEnumerable1[App.Domain.Entities.RequestLookupOption] collection --> System.Collections.Generic.List1[App.Domain.Entities.RequestLookupOption] --> System.Collections.Generic.ICollection1[App.Domain.Entities.RequestLookupOption] --> System.Collections.Generic.ICollection`1[App.Domain.Entities.RequestLookupOption] RequestLookupOptions -->
App.Domain.Entities.LookupOption -->
App.Domain.Entities.Request
Entity
public class LookupOption
{
[Key]
public int OptionID { get; set; }
public string LookupID { get; set; }
[Required(ErrorMessage = "Label is required")]
public string Label { get; set; }
public string Description { get; set; }
[Required(ErrorMessage = "Sort Order is required")]
public int SortOrder { get; set; }
[Required(ErrorMessage = "Active is required")]
public bool Active { get; set; }
public string CssClasses { get; set; }
// Relational Data //
[JsonIgnore]
public virtual ICollection<RequestLookupOption> RequestLookupOptions { get; set; }
[JsonIgnore]
public virtual ICollection<AppMaster_Application> Applications { get; set; }
}
Basically what i am trying to do is this
private IEnumerable<LookupOption> LookupOptionsFakeData()
{
return _fixture.Build<LookupOption>()
.Without(m => m.RequestLookupOptions)
.Without(m => m.Applications)
.CreateMany();
}
but instead of create a function for each entity have the DataGenerator Class. Make sense or this is crazy talk?
Thanks.
Aucun commentaire:
Enregistrer un commentaire