Reputation: 3
I created following sample model:
internal sealed class Bike : IVehicle
{
public Bike(
Engine engineType,
WindowHue windowHue,
Vehicle transport,
ushort wheelsCount,
string name) =>
(EngineType, WindowHue, Transport, WheelsCount, Name) =
(engineType, windowHue, transport, wheelsCount, name);
public WindowHue WindowHue { get; }
public Engine EngineType { get; }
public Vehicle Transport { get; }
public ushort WheelsCount { get; }
public string Name { get; }
}
I'm currently writing unit tests for Bike validator and I would like to use AutoFixture to create instances of Bike class that have values that are considered valid and invalid. Is there a way to instruct AutoFixture how to create those types of instances and tell it to fetch valid or invalid one depending on unit test that is running? For example: in test case that checks whether valid instance of Bike class passes validation I would like AutoFixture to create a valid Bike instance. I attempted to achieve this behavior by creation of custom specimen builders but it seems that the last one that is registered is used to create an actual instance of requested type. Other idea was to create builder class that would use AutoFixture to create valid and invalid instances [via "Create" method] and use it in test cases, but I think that is not a good idea, since it leads to creation of redundant code [builder class per tested model]. If above behavior is possible, then is there a way to create such instances by using [AutoData] attribute, so that I don't have to call AutoFixture in test case body?
Upvotes: 0
Views: 3107
Reputation: 1284
Yes you can, however the complexity of your setup code will depend on the complexity of your domain.
You could declare a customization that would build your DTO models with valid data, then use it via a custom [AutoData]
attribute, and inside the test customize some of the DTOs with invalid data using .Customize<T>()
or .Build<T>()
.
Now if you want to provide your invalid DTOs from the test parameters you could try to implement a [Invalid]
attribute, that would customize individual test parameters, then use [Frozen]
to use the value in other generated models.
For the [Invalid]
attribute you can implement either the CustomizeAttribute
from the AutoFixture.NUnit3
package or the IParameterCustomizationSource
from AutoFixture
.
As you'll see the output of the customization attribute is an ICustomization
meaning inside the attribute you'll likely have a dictionary that outputs a customization for an invalid entity depending on the parameter type.
NB: I would really advise you use the first approach since it makes it obvious in what way the input data is invalid and makes asserting the results easier.
Upvotes: 1
Reputation: 1368
I would probably leave automapper out of this and create a class that takes care of creating the different types (invalid or valid) of objects that tests need:
Enums.cs
public enum BikeType
{
Valid,
Invalid
}
BikeCreator.cs
public static class BikeCreator
{
private Bike CreateValidBike()
{
return new Bike() //make this object "valid"
}
private Bike CreateInvalidBike()
{
return new Bike(); //make this object "invalid"
}
public Bike CreateInstance(BikeType bikeType)
{
Bike bike = null;
switch (bikeType)
{
case BikeType.Valid:
user = CreateValidBike();
break;
case BikeType.Invalid:
user = CreateInvalidBike();
break;
};
return bike;
}
}
That allows me to call that class in the following way:
//arrange
var invalidBike = BikeCreator.CreateInstance(BikeType.Invalid);
var validBike = BikeCreator.CreateInstance(BikeType.Valid);
This could be a good boilerplate to refactor into something more fancy with interfaces and generics. Sometimes "premature optimization is the root of all evil"
Upvotes: 0