AutoFixture, create a list of email addresses
Asked Answered
F

3

14

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/

Forland answered 1/4, 2016 at 20:17 Comment(0)
A
24

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]"
Antithesis answered 2/4, 2016 at 8:49 Comment(1)
Don't you want Select(x=> x.Address)? ToString on an a mail address results in "ecfd3086-48c7-4999-8b5e-c19f9d0875ff" <[email protected]>Bolingbroke
B
10

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());
Breannebrear answered 2/4, 2016 at 9:28 Comment(0)
N
0

From Autofixture

var localPart = fixture.Create<EmailAddressLocalPart>().LocalPart;
var domain = fixture.Create<DomainPart>().Domain;
var fullAddress = $"{localPart}@{domain}";
Nefen answered 16/11, 2021 at 10:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.