Unit testing 如何在AutoFixture中创建样本生成器以始终返回与正则表达式匹配的字符串?

Unit testing 如何在AutoFixture中创建样本生成器以始终返回与正则表达式匹配的字符串?,unit-testing,autofixture,Unit Testing,Autofixture,我试图在我的单元测试中使用约定,这些约定使用AutoFixture。我有一个Password value对象,如图所示: public class Password : SemanticType<string> { private int _daysPasswordValid; public Password(string password) : base(IsValid, password) { Guard.NotNullOrEmpty((

我试图在我的单元测试中使用约定,这些约定使用AutoFixture。我有一个Password value对象,如图所示:

public class Password : SemanticType<string>
{
    private int _daysPasswordValid;

    public Password(string password) : base(IsValid, password)
    {
        Guard.NotNullOrEmpty(() => password, password);
        Guard.IsValid(() => password, password, IsValid, "Invalid Password");

        DateCreated = DateTime.Now;
    }

    static bool IsValid(string candidate)
    {
        //password cannot contain be whitespace
        if (string.IsNullOrWhiteSpace(candidate))
            return false;

        const string passwordPattern = @"^(?=.*[A-Z].*[A-Z])(?=.*[!@#$&=()-*])(?=.*[0-9].*[0-9])(?=.*[a-z].*[a-z].*[a-z]).{20}$";

        var match = Regex.Match(candidate, passwordPattern);

        return match.Success;
    }

    public DateTime DateCreated { get; private set; }

    public int DaysPasswordValid
    {
        get { return _daysPasswordValid; }
        set
        {
            const int minimunDays = 0;
            const int maximumDays = 90;

            if (value <= maximumDays && value > minimunDays)
                _daysPasswordValid = value;
            else
                throw new ArgumentOutOfRangeException(
                    "Password must be valid more than {0} and no more than {1} days.".Fmt(minimunDays, maximumDays));
        }
    }

    public static implicit operator string(Password password)
    {
        return password.Value;
    }

    public static explicit operator Password(string value)
    {
        return new Password(value);
    }
}
以下是测试:

[Fact]
    public void ValidPasswordMatches()
    {
        var fixture = new Fixture();
        fixture.Customizations.Add(new ValidPasswordBuilder(PasswordPattern));
        Action a = () => fixture.Create<Password>();
        a.ShouldNotThrow<ArgumentException>();
    }
[事实]
public void ValidPasswordMatches()
{
var fixture=新fixture();
fixture.Customizations.Add(新的ValidPasswordBuilder(PasswordPattern));
动作a=()=>fixture.Create();
a、 不应该扔();
}
我可以按照上面的设置运行测试,测试通过了,但是如果我调试它,我会在Password类中的IsValid函数中得到一个错误(通过Guard子句),该错误表示从生成器返回的密码是:

Ploeh.AutoFixture.Kernel.NoSpecimen

我似乎从未得到与正则表达式模式匹配的结果。我觉得我很接近了,但需要一些人帮助我渡过难关


谢谢

看起来,您使用的模式不受支持:

^(?=.*[A-Z].*[A-Z])(?=.*[!@#$&=()-*])(?=.*[0-9].*[0-9])(?=.*[a-z].*[a-z].*[a-z]).{20}$

尝试使用不同的正则表达式

编辑:或尝试执行或,以便将AutoFixture配置为使用不同的正则表达式,而无需更改
密码


AutoFixture通过应用的算法将正则表达式转换为

您可以使用不同的模式或使用不同的引擎将正则表达式反转为自动机。例如,您可以使用引擎

但是,即使使用Rex,也不支持正则表达式,因为Rex当前不支持以下构造:

锚定\G、\b、\b、命名组、向前看、向后看、尽可能少的数量词、反向引用、条件替换、替换


如果要使用AutoFixture尝试Rex,可以使用以下生成器:

internal class RexRegularExpressionGenerator : ISpecimenBuilder
{
    public object Create(object request, ISpecimenContext context)
    {
        if (request == null)
            return new NoSpecimen();

        var regularExpressionRequest = request as RegularExpressionRequest;
        if (regularExpressionRequest == null)
            return new NoSpecimen();

        var pattern = regularExpressionRequest.Pattern;

        try
        {
            var regex = RexEngine
                .GenerateMembers(
                    new RexSettings(pattern) { k = 1 })
                .FirstOrDefault();

            if (Regex.IsMatch(regex, pattern))
                return regex;
        }
        catch (ArgumentException)
        {
            return new NoSpecimen(request);
        }

        return new NoSpecimen(request);
    }
}

据我所知,您只能将Rex作为.NET应用程序(.exe)文件下载,然后您可以像项目中的任何其他托管程序集一样引用该文件。

这对我来说很有用,因为我对OoTB RegularExpressionGenerator创建的字符串不满意(“\d”似乎总是创建一个“0”)。Rex.exe编译为x86,因此我使用dotpeek 10反编译并重建为DLL,并使用上述生成器,这是令人惊讶的:\d将生成的不仅仅是0-9,包括泰米尔语和各种时髦的unicode数字。(使我们将正则表达式从\d显式更改为[0-9]
internal class RexRegularExpressionGenerator : ISpecimenBuilder
{
    public object Create(object request, ISpecimenContext context)
    {
        if (request == null)
            return new NoSpecimen();

        var regularExpressionRequest = request as RegularExpressionRequest;
        if (regularExpressionRequest == null)
            return new NoSpecimen();

        var pattern = regularExpressionRequest.Pattern;

        try
        {
            var regex = RexEngine
                .GenerateMembers(
                    new RexSettings(pattern) { k = 1 })
                .FirstOrDefault();

            if (Regex.IsMatch(regex, pattern))
                return regex;
        }
        catch (ArgumentException)
        {
            return new NoSpecimen(request);
        }

        return new NoSpecimen(request);
    }
}