autofixture - How can I use custom ISpecimenBuilders with OmitOnRecursionBehavior? -


how can use custom ispecimenbuilder instances along omitonrecursionbehavior want applied globally fixture-created objects?

i'm working ef code first model foul-smelling circular reference that, purposes of question, cannot eliminated:

public class parent {     public string name { get; set; }     public int age { get; set; }     public virtual child child { get; set; } }  public class child {     public string name { get; set; }     public int age { get; set; }     public virtual parent parent { get; set; } } 

i'm familiar technique side-stepping circular references, in passing test:

[theory, autodata] public void cancreatepatientgraphwithautofixturemanually(fixture fixture) {     //fixture.customizations.add(new parentspecimenbuilder());     //fixture.customizations.add(new childspecimenbuilder());     fixture.behaviors.oftype<throwingrecursionbehavior>().tolist()                      .foreach(b => fixture.behaviors.remove(b));     fixture.behaviors.add(new omitonrecursionbehavior());     fixture.behaviors.add(new tracingbehavior());     var parent = fixture.create<parent>();     parent.should().notbenull();     parent.child.should().notbenull();     parent.child.parent.should().benull(); } 

but if either/both customizations uncommented, exception:

system.invalidcastexception: unable cast object of type 'ploeh.autofixture.kernel.omitspecimen' type 'circularreference.parent'. 

the failing cast occurring in ispecimenbuilder implementations (shown @ bottom of question) when call on ispecimencontext resolve parent , request coming child being resolved. guard against request coming child resolving operation this:

//... && propertyinfo.reflectedtype != typeof(child) //... 

but, seems pollute ispecimenbuilder implementation knowledge of 'who' might making request. also, seems duplicate work 'global' omitonrecursionbehavior meant do.

i want use ispecimenbuilder instances because have other things customize besides handling circular reference. i've spent lot of time looking examples of scenario here on , on ploeh haven't found yet discusses combination of behaviors , customizations. it's important solution 1 can encapsulate icustomization, rather lines , lines in test setup of

//... fixture.actlikethis(new specialbehavior())        .whengiven(typeof (parent))        .anddonoteventhinkaboutbuilding(typeof(child))        .unlessparentisnull() //... 

...because want extend [autodata] attribute tests.

what follows ispecimenbuilder implementations , output of tracingbehavior failing test:

public class childspecimenbuilder : ispecimenbuilder {     public object create(object request, ispecimencontext context)     {         var propertyinfo = request propertyinfo;         return propertyinfo != null                && propertyinfo.propertytype == typeof(child)                    ? resolve(context)                    : new nospecimen(request);     }      private static object resolve(ispecimencontext context)     {         var child = (child) context.resolve(typeof (child));         child.name = context.resolve(typeof (string)).tostring().tolowerinvariant();         child.age = math.min(17, (int) context.resolve(typeof (int)));         return child;     } }  public class parentspecimenbuilder : ispecimenbuilder {     public object create(object request, ispecimencontext context)     {         var propertyinfo = request propertyinfo;         return propertyinfo != null                && propertyinfo.propertytype == typeof (parent)                    ? resolve(context)                    : new nospecimen(request);     }      private static object resolve(ispecimencontext context)     {         var parent = (parent) context.resolve(typeof (parent));         parent.name = context.resolve(typeof (string)).tostring().toupperinvariant();         parent.age = math.max(18, (int) context.resolve(typeof (int)));         return parent;     } }  cancreatepatientgraphwithautofixturemanually(fixture: ploeh.autofixture.fixture) : failed  requested: ploeh.autofixture.kernel.seededrequest     requested: circularreference.parent       requested: system.string name         requested: ploeh.autofixture.kernel.seededrequest           requested: system.string           created: 38ab48f4-b071-40f0-b713-ef9d4c825a85         created: name38ab48f4-b071-40f0-b713-ef9d4c825a85       created: name38ab48f4-b071-40f0-b713-ef9d4c825a85       requested: int32 age         requested: ploeh.autofixture.kernel.seededrequest           requested: system.int32           created: 9         created: 9       created: 9       requested: circularreference.child child         requested: ploeh.autofixture.kernel.seededrequest           requested: circularreference.child             requested: system.string name               requested: ploeh.autofixture.kernel.seededrequest                 requested: system.string                 created: 1f5ca160-b211-4f82-871f-11882dbcf00d               created: name1f5ca160-b211-4f82-871f-11882dbcf00d             created: name1f5ca160-b211-4f82-871f-11882dbcf00d             requested: int32 age               requested: ploeh.autofixture.kernel.seededrequest                 requested: system.int32                 created: 120               created: 120             created: 120             requested: circularreference.parent parent               requested: circularreference.parent               created: ploeh.autofixture.kernel.omitspecimen  system.invalidcastexception: unable cast object of type 'ploeh.autofixture.kernel.omitspecimen' type 'circularreference.parent'. 

is option customize creation algorithm using customize method?

if yes, can create , use following [parentchildconventions] attribute:

internal class parentchildconventionsattribute : autodataattribute {     internal parentchildconventionsattribute()         : base(new fixture().customize(new parentchildcustomization()))     {     } }  internal class parentchildcustomization : icustomization {     public void customize(ifixture fixture)     {         fixture.customize<child>(c => c             .with(x => x.name,                 fixture.create<string>().tolowerinvariant())             .with(x => x.age,                 math.min(17, fixture.create<int>()))             .without(x => x.parent));          fixture.customize<parent>(c => c             .with(x => x.name,                 fixture.create<string>().toupperinvariant())             .with(x => x.age,                 math.min(18, fixture.create<int>())));     } } 

the original test, using [parentchildconventions] attribute, passes:

[theory, parentchildconventions] public void cancreatepatientgraphwithautofixturemanually(     parent parent) {     parent.should().notbenull();     parent.child.should().notbenull();     parent.child.parent.should().benull(); } 

Comments

Popular posts from this blog

html - How to style widget with post count different than without post count -

How to remove text and logo OR add Overflow on Android ActionBar using AppCompat on API 8? -

javascript - storing input from prompt in array and displaying the array -