I'm trying to add an ICustomization implementation to write generated fixture values to the console to aid in diagnosing intermittent test failures in our nightly build test runs.
The problem I'm having is that each value gets written to the console twice. Unfortunately all the examples and documentation I can find relate to custom processing for specific types - I'd like to write something that runs for all types, so that it logs the value for any fixture generated.
Below is a simplified version of what I've created so far (snippet from LINQPad).
void Main()
{
var fixture = new Fixture();
fixture.Customize(new CustomCustomisation());
fixture.Create<double>();
}
public class CustomCustomisation : ICustomization
{
public void Customize(IFixture fixture)
{
var engine = ((Fixture)fixture).Engine;
fixture.Customizations.Add(new Postprocessor(engine, new LogSpecimenCommand()));
}
}
public class LogSpecimenCommand : ISpecimenCommand
{
public void Execute(object specimen, ISpecimenContext context)
{
if (specimen == null || specimen is NoSpecimen) return;
Console.WriteLine($"SPECIMEN: {specimen}");
}
}
The output from the above is:
SPECIMEN: 213
SPECIMEN: 213
According to my investigations on AutoFixture, the way AutoFixture works when creating a new specimen is by using a chain of responsibility. This means that in general, it will take several requests and several creations to generate a specimen, and for each of these creations a LogSpecimenCommand is being issued, hence you get your trace twice.
Please read Extending AutoFixture to understand the context of my answer. There, I saw that AutoFixture provides a TracingBehaviour that seems to cover your case of use.
TracingBehaviourwill emit traces for both the requests and creations of specimens. If configure your fixture to use this behaviour:It will write this output to the console:
Note how it takes two different requests,
AutoFixture.Kernel.SeededRequestandSystem.Double(and their corresponding creations) to generate thedoublespecimen. Also worth noting is that the output indentation for each entry hints that there's a way to order the requests and creations according to their place in the chain of responsibility.After seeing the implementation of TracingBehaviour and the related types TracingBuilder and TraceWriter, I managed to generate a
CustomTracingBehaviourand aCustomTraceWriterthat also leverageTracingBuilderto write to the console with a custom trace format.TracingBuilderis a Specimen Builder that raises the event:so we can subscribe to this event to generate a trace whenever a specimen is created.
Create a transformation1 of
TracingBuilder. I've called itCustomTracingBehaviourand it's a simpler version of AutoFixture'sTracingBehaviour. Create also aCustomTraceWriter, which again is a simpler version of AutoFixture'sTraceWriter.CustomTraceWriterhas a reference to theTracingBuilderpassed from theCustomTracingBehaviour.Inside the event handler
OnSpecimenCreated, you can write your traces in your desired format.SpecimenCreatedEventArgscomes with both the created specimen and the depth of the creation event. After some quick tests, I figured that1is the lowest possible depth, so if you check for the depth before writing your traces, you can ensure that only one trace is created for the whole chain of requests and creations corresponding to a single specimen.Then, add the custom behaviour after instantiating your fixture:
This will produce the following output:
1 By using a custom
ISpecimenBuilderTransformation, we can transform anISpecimenBuilderinto anISpecimenBuilderNode. According to the remarks onISpecimenBuilderNode, this means that a transformed SpecimenBuilder will no longer be the one generating the specimen, but it will pass that responsibility along to a further SpecimenBuilder: