Always freeze fun using AutoFixture, XUnit, and Moq

I use AutoFixture, Moq, and XUnit extensions ( [Theory] attribute) as described in this blog post at http://blog.ploeh.dk/2010/10/08/AutoDataTheorieswithAutoFixture .

I noticed that most unit tests look like this:

 [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); } 

Unlike always decorating bullying with [Frozen] , is there a way to tune the appliance to always freeze mocks?

Here's the AutoMoqData attribute:

 public class AutoMoqDataAttribute : AutoDataAttribute { public AutoMoqDataAttribute() : base(new Fixture().Customize(new AutoMoqCustomization())) { } } 
+7
c # unit-testing moq autofixture
source share
2 answers

Despite the fact that it is not currently built-in, it’s easy to write a general-purpose decorator that freezes objects when they leave the automatic adaptation tree:

 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)); } } 

Note that it decorates another ISpecimenBuilder , but remembers all the values ​​before returning them. If the same request arrives again, it will return a memoized value.

While you cannot extend AutoMoqCustomization , you can replicate what it does (these are just two lines of code) and use MemoizingBuilder around it:

 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()); } } 

Use AutoFreezeMoq instead of AutoMoqCustomization . It will freeze all mocks and all interfaces and abstract base classes created from these mocks.

 public class AutoMoqDataAttribute : AutoDataAttribute { public AutoMoqDataAttribute() : base(new Fixture().Customize(new AutoFreezeMoq())) { } } 
+7
source share

I finished copying the code from the AutoDataAttribute class and modified it to AutoDataAttribute FreezingCustomization .

This is the resulting attribute.

 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); } } 
+3
source share

All Articles