Reputation: 2043
My problem is a bit of an odd one and I don't think it's really something Autofixture can solve but here goes;
We have a test that loops through every ICloneable
in our assembly and attempts to clone it. Currently there is a horrific Populate
method I want to get rid of and replace. It checks the type of each property and assigns a default value based on that (a nice, big, long if else statement).
The problem I have here is that I don't want to have to maintain a specific list of Autofixture.Register
methods, as that is more maintenance than the method itself.
Any ideas?
Thanks.
private void CheckAssemblyClones(Assembly entitiesAssembly)
{
foreach (Type entityType in entitiesAssembly.GetTypes()
.Where(t => t.GetInterfaces().Contains(typeof(ICloneable))
&& !t.IsAbstract
&& t.GetConstructor(Type.EmptyTypes) != null))
{
ICloneable original = Activator.CreateInstance(entityType) as ICloneable;
//Horrible method is used here to populate the object
//This is where I tried to add fixture.Create(original) but it
//doesn't like this original is an interface. If I use entityType
//directly it complains as there are interfaces within the class
//implementations that are later fulfilled using an IoC
PopulateProperties(original, true);
//Tried this, which fails because it is an ICloneable
//var fixture = new Fixture();
//original = fixture.Create(original);
MethodInfo cloneMethod = entityType.GetMethod("Clone", new Type[]
{
typeof(Boolean)
});
object clone = cloneMethod.Invoke(original, new object[]
{
true
});
}
}
private static PropertyInfo[] PopulateProperties(object obj, bool nest)
{
//var fixture = new Fixture();
var properties = obj.GetType().GetProperties();
foreach (PropertyInfo property in properties)
{
//Tried this but it failed due to PropertyInfo being an abstract class.
//var autoProp = fixture.Create(property);
//For every type set a default value for the property
}
return properties;
}
Upvotes: 2
Views: 207
Reputation: 233367
It sounds like you're trying to write a convention-based test that covers the behaviour of multiple types. That's what the AutoFixture.Idioms is for.
Sketching out a possible implementation, you should look into defining a class that derives from IdiomaticAssertion
:
public class CloneableAssertion : IdiomaticAssertion
{
private readonly ISpecimenBuilder builder;
public CloneableAssertion(ISpecimenBuilder builder)
{
if (builder == null)
throw new ArgumentNullException("builder");
this.builder = builder;
}
public override void Verify(Type type)
{
// Check if type is ICloneable before trying to create it.
// Return if it's not ICloneable.
// If this.builder is a standard Fixture object, the returned
// object will be populated with data, if possible.
var sut = (ICloneable)Create(type);
// Insert test against sut here...
}
private object Create(Type type)
{
return new SpecimenContext(this.builder).Resolve(type);
}
}
For more comprehensive examples, see the source code of AutoFixture.Idioms. The best place to start is probably WritablePropertyAssertion, which is fairly small and simple.
Perhaps you're implementing ICloneable
for internal use only, in which case it's fine, but you should, however, be aware that use of it is discouraged in public APIs:
we recommend that ICloneable not be implemented in public APIs
Upvotes: 1