我正在使用AutoFixture,Moq和XUnit扩展程序([Theory]
属性),如本博文http://blog.ploeh.dk/2010/10/08/AutoDataTheorieswithAutoFixture中所述。
我注意到大多数单元测试都是这样的:
[Theory, AutoMoqData]
public void Test(
[Frozen] Mock<IServiceOne> serviceOne,
[Frozen] Mock<IServiceTwo> serviceTwo,
MyClass classUnderTest)
{
// Arrange
serviceOne
.Setup(m => m.Get(It.IsAny<int>()));
serviceTwo
.Setup(m => m.Delete(It.IsAny<int>()));
// MyClass has a constructor with arguments for IServiceOne, and IServiceTwo
// classUnderTest will use the two mocks specified above
// Act
var result = classUnderTest.Foo();
// Assert
Assert.True(result);
}
与总是使用[Frozen]
装饰模具相反,是否有办法设置夹具以始终冻结模具?
以下是AutoMoqData
属性:
public class AutoMoqDataAttribute : AutoDataAttribute
{
public AutoMoqDataAttribute()
: base(new Fixture().Customize(new AutoMoqCustomization()))
{
}
}
答案 0 :(得分:8)
虽然它目前不是内置的,但是编写一个通用的装饰器很容易,当它们离开AutoFixture责任树时冻结对象:
public class MemoizingBuilder : ISpecimenBuilder
{
private readonly ISpecimenBuilder builder;
private readonly ConcurrentDictionary<object, object> instances;
public MemoizingBuilder(ISpecimenBuilder builder)
{
this.builder = builder;
this.instances = new ConcurrentDictionary<object, object>();
}
public object Create(object request, ISpecimenContext context)
{
return this.instances.GetOrAdd(
request,
r => this.builder.Create(r, context));
}
}
请注意,它会装饰另一个ISpecimenBuilder
,但会在返回之前记住所有值。如果同一请求再次到达,它将返回记忆值。
虽然你不能扩展 AutoMoqCustomization
,但你可以复制它的作用(它只有两行代码),并使用它周围的MemoizingBuilder
:
public class AutoFreezeMoq : ICustomization
{
public void Customize(IFixture fixture)
{
if (fixture == null)
throw new ArgumentNullException("fixture");
fixture.Customizations.Add(
new MemoizingBuilder(
new MockPostprocessor(
new MethodInvoker(
new MockConstructorQuery()))));
fixture.ResidueCollectors.Add(new MockRelay());
}
}
使用此AutoFreezeMoq
代替AutoMoqCustomization
。它将冻结所有模拟,以及从这些模拟创建的所有接口和抽象基类。
public class AutoMoqDataAttribute : AutoDataAttribute
{
public AutoMoqDataAttribute()
: base(new Fixture().Customize(new AutoFreezeMoq()))
{
}
}
答案 1 :(得分:3)
我最终copying code from the AutoDataAttribute
class并修改它以包含FreezingCustomization
。
这是结果属性。
public class AutoMoqDataAttribute : AutoDataAttribute
{
public AutoMoqDataAttribute()
: base(new Fixture().Customize(new AutoMoqCustomization()))
{
}
public override IEnumerable<object[]> GetData(System.Reflection.MethodInfo methodUnderTest, Type[] parameterTypes)
{
var specimens = new List<object>();
foreach (var p in methodUnderTest.GetParameters())
{
CustomizeFixture(p);
if (p.ParameterType.GetInterfaces().Any(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IMock<>)))
{
var freeze = new FreezingCustomization(p.ParameterType, p.ParameterType);
this.Fixture.Customize(freeze);
}
var specimen = Resolve(p);
specimens.Add(specimen);
}
return new[] { specimens.ToArray() };
}
private void CustomizeFixture(ParameterInfo p)
{
var dummy = false;
var customizeAttributes = p.GetCustomAttributes(typeof(CustomizeAttribute), dummy).OfType<CustomizeAttribute>();
foreach (var ca in customizeAttributes)
{
var c = ca.GetCustomization(p);
this.Fixture.Customize(c);
}
}
private object Resolve(ParameterInfo p)
{
var context = new SpecimenContext(this.Fixture);
return context.Resolve(p);
}
}