I'm writing some unit tests and have a class called Account
which has
public Guid AccountId {get;set;}
public IEnumerable<string> EmailAddresses {get;set;}
etc...
I want to use autofixture to create the account, but I'm having trouble getting the email format.
I have tried
fixture.Register<string>(() => string.Format("{0}@acme.com", fixture.Create<string>()));
but that that leads to circular problem.
I could do this
fixture.Register<string>(() => string.Format("{0}@acme.com", fixture.Create<int>()));
But I'd rather have a string at the start of the address.
EDIT Thanks to both answers I have a written up a summary and few other scenarios as a post here - http://nodogmablog.bryanhogan.net/2016/04/customizing-a-specific-string-inside-a-class-using-autofixture/
There are a couple of ways of doing that. Here's one of them:
Assuming that MyClass
is defined as
public class MyClass
{
public Guid AccountId { get; set; }
public IEnumerable<string> EmailAddresses { get; set; }
}
Then, a Fixture
object can be customized like so
var fixture = new Fixture();
fixture.Customize<MyClass>(c => c
.With(x =>
x.EmailAddresses,
fixture.CreateMany<MailAddress>().Select(x => x.Address)));
var result = fixture.Create<MyClass>();
And so the EmailAddresses
will be filled with email strings that look like:
"[email protected]"
"[email protected]"
"[email protected]"
This is one of those situations where AutoFixture is giving you feedback on the usability of your object model.
If the EmailAddresses
property is supposed to only contain valid email addresses, then you should ask yourself whether representing them as generic strings is the right choice. A more specific type like the MailAddress
class would restrict the set of valid values for that property.
It would also make it easier to generate test data for it, since AutoFixture knows how to create instances of MailAddress
.
Having said that, if it's not feasible for you to change the object model, you can still write a customization that tells AutoFixture to provide valid email addresses for any property or parameter of type IEnumerable<string>
with email
somewhere in their name:
public class EmailAddressStringsGenerator : ISpecimenBuilder
{
public object Create(object request, ISpecimenContext context)
{
if (IsEnumerableOfStringPropertyOrParameterNamedEmail(request))
{
return CreateManyEmailAddresses(context);
}
return new NoSpecimen();
}
static bool IsEnumerableOfStringPropertyOrParameterNamedEmail(object request)
{
return IsEnumerableOfStringPropertyNamedEmail(request) ||
IsEnumerableOfStringParameterNamedEmail(request);
}
static bool IsEnumerableOfStringPropertyNamedEmail(object request)
{
var property = request as PropertyInfo;
return property != null &&
property.Name.ContainsIgnoringCase("email") &&
typeof(IEnumerable<string>).IsAssignableFrom(property.PropertyType);
}
static bool IsEnumerableOfStringParameterNamedEmail(object request)
{
var parameter = request as ParameterInfo;
return parameter != null &&
parameter.Name.ContainsIgnoringCase("email") &&
typeof(IEnumerable<string>).IsAssignableFrom(parameter.ParameterType);
}
static IEnumerable<string> CreateManyEmailAddresses(ISpecimenContext context)
{
var addresses = (IEnumerable<MailAddress>)
context.Resolve(typeof(IEnumerable<MailAddress>));
return addresses.Select(a => a.Address);
}
}
You can then use that customization in a Fixture
by adding it to the Customizations
property:
fixture.Customizations.Insert(0, new EmailAddressStringsGenerator());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With