我有一个如下所示的密码类:
public class Password : SemanticType<string>
{
public Password(string password, int daysValid) : base(IsValidPassword, password)
{
Guard.NotNullOrEmpty(() => password, password);
Guard.IsValid(() => password, password, IsValidPassword, "Invalid Password");
Guard.IsValid(() => daysValid, daysValid, IsValidDays, "Invalid number of days");
DaysPasswordValid = daysValid;
SetPasswordExpiration(daysValid);
}
private void SetPasswordExpiration(int daysValid)
{
var duration = Duration.FromStandardDays(daysValid);
ExpiryInstant = Clock.Now.Plus(duration);
}
public IClock Clock { get; set; }
private static bool IsValidPassword(string candidate)
{
//password cannot be whitespace
if (string.IsNullOrWhiteSpace(candidate))
return false;
return PasswordPolicy.IsValid(candidate);
}
private static bool IsValidDays(int days)
{
const int minimunDays = 1;
const int maximumDays = 90;
return days <= maximumDays && days >= minimunDays;
}
public Instant ExpiryInstant { get; private set; }
public bool HasExpired
{
get { return Clock.Now > ExpiryInstant; }
}
public int DaysPasswordValid { get; private set; }
}
我正在尝试创建测试并使用AutoFixture来帮助我。我正在使用NodaTime,这是IClock的来源(它被注入),NodaTime有一个很好的测试api,可以让我创建一个FakeClock,所以我设置我的夹具如图所示:
static readonly Instant TestInstant = Instant.FromUtc(2015, 01, 01, 01, 01, 01);
readonly FakeClock _stubClock = new FakeClock(TestInstant);
var fixture = new Fixture();
fixture.Build<Password>().With(p => p.Clock, _stubClock);
当我在仅具有IClock属性的测试类中测试此设置时,我的设置工作正常。但对于我真正的密码类,我还有两个自定义项,一个用于构建有效密码,另一个用于创建有效天数。这两个自定义关键在构造函数参数上,而不是属性。我的测试(到目前为止)如下:
[Fact]
public void TestBuilder()
{
var fixture = new Fixture();
fixture.Build<Password>().With(p => p.Clock, _stubClock);
fixture.Customizations.Add(new PasswordBuilder(_allValidRules, MinimumPasswordLength));
fixture.Customizations.Add(new ValidDaysParameterBuilder(MinimumDaysValid, MaximumDaysValid));
var pwd = fixture.Create<Password>();
}
我的两个自定义:
public class PasswordBuilder : ISpecimenBuilder
{
public IList<string> Rules { get; private set; }
public int ValidLength { get; private set; }
public PasswordBuilder(IList<string> rules, int validLength)
{
if (rules == null) throw new ArgumentNullException("rules");
Rules = rules;
ValidLength = validLength;
}
public object Create(object request, ISpecimenContext context)
{
var pi = request as ParameterInfo;
if (pi != null && pi.Name == "password" && pi.ParameterType == typeof(string))
{
var temp = string.Empty;
foreach (var rule in Rules)
{
var generator = new RegularExpressionGenerator();
var regExRequest = new RegularExpressionRequest(rule);
var result = generator.Create(regExRequest, new DelegatingSpecimenContext());
temp += result.ToString();
}
if (string.IsNullOrEmpty(temp))
return new NoSpecimen(request);
if (temp.Length < ValidLength)
temp = temp.PadRight(ValidLength, 'x');
return temp;
}
return new NoSpecimen(request);
}
private class DelegatingSpecimenContext : ISpecimenContext
{
public DelegatingSpecimenContext()
{
this.OnResolve = r => null;
}
public object Resolve(object request)
{
return this.OnResolve(request);
}
private Func<object, object> OnResolve { get; set; }
}
public class ValidDaysParameterBuilder : ISpecimenBuilder
{
private readonly int _minValue;
private readonly int _maxValue;
public ValidDaysParameterBuilder(int minValue, int maxValue)
{
_minValue = minValue;
_maxValue = maxValue;
}
public object Create(object request, ISpecimenContext context)
{
var pi = request as ParameterInfo;
if (pi != null && pi.Name == "daysValid" && pi.ParameterType == typeof (int))
{
return context.Resolve(new RangedNumberRequest(typeof(int), _minValue, _maxValue));
}
return new NoSpecimen(request);
}
}
问题是,在构建Password时,Clock属性始终为null,因此Build行不会填充Clock属性。正如我所说,如果我对一个只有基于IClock的属性的类使用相同的Build行,则会填充该属性。我试图&#34;听&#34;我的测试,但我不确定我的api是否有缺陷,或者我的测试设置是否错误。任何建议/帮助将不胜感激。
谢谢!