AutoFixture.AutoMoq supply a known value for one constructor parameter

后端 未结 6 1308
悲哀的现实
悲哀的现实 2020-12-13 14:52

I\'ve just started to use AutoFixture.AutoMoq in my unit tests and I\'m finding it very helpful for creating objects where I don\'t care about the specific

6条回答
  •  旧巷少年郎
    2020-12-13 15:09

    I fee like @Nick was almost there. When overriding the constructor argument, it needs to be for the given type and have it limited to that type only.

    First we create a new ISpecimenBuilder that looks at the "Member.DeclaringType" to keep the correct scope.

    public class ConstructorArgumentRelay : ISpecimenBuilder
    {
        private readonly string _paramName;
        private readonly TValueType _value;
    
        public ConstructorArgumentRelay(string ParamName, TValueType value)
        {
            _paramName = ParamName;
            _value = value;
        }
    
        public object Create(object request, ISpecimenContext context)
        {
            if (context == null)
                throw new ArgumentNullException("context");
            ParameterInfo parameter = request as ParameterInfo;
            if (parameter == null)
                return (object)new NoSpecimen(request);
            if (parameter.Member.DeclaringType != typeof(TTarget) ||
                parameter.Member.MemberType != MemberTypes.Constructor ||
                parameter.ParameterType != typeof(TValueType) ||
                parameter.Name != _paramName)
                return (object)new NoSpecimen(request);
            return _value;
        }
    }
    

    Next we create an extension method to allow us to easily wire it up with AutoFixture.

    public static class AutoFixtureExtensions
    {
        public static IFixture ConstructorArgumentFor(
            this IFixture fixture, 
            string paramName,
            TValueType value)
        {
            fixture.Customizations.Add(
               new ConstructorArgumentRelay(paramName, value)
            );
            return fixture;
        }
    }
    

    Now we create two similar classes to test with.

        public class TestClass
        {
            public TestClass(T value1, T value2)
            {
                Value1 = value1;
                Value2 = value2;
            }
    
            public T Value1 { get; private set; }
            public T Value2 { get; private set; }
        }
    
        public class SimilarClass
        {
            public SimilarClass(T value1, T value2)
            {
                Value1 = value1;
                Value2 = value2;
            }
    
            public T Value1 { get; private set; }
            public T Value2 { get; private set; }
        }
    

    Finally we test it with an extension of the original test to see that it will not override similarly named and typed constructor arguments.

    [TestFixture]
    public class AutoFixtureTests
    {
        [Test]
        public void Can_Create_Class_With_Specific_Parameter_Value()
        {
            string wanted = "This is the first string";
            string wanted2 = "This is the second string";
            Fixture fixture = new Fixture();
            fixture.ConstructorArgumentFor, string>("value1", wanted)
                   .ConstructorArgumentFor, string>("value2", wanted2);
    
            TestClass t = fixture.Create>();
            SimilarClass s = fixture.Create>();
    
            Assert.AreEqual(wanted,t.Value1);
            Assert.AreEqual(wanted2,t.Value2);
            Assert.AreNotEqual(wanted,s.Value1);
            Assert.AreNotEqual(wanted2,s.Value2);
        }        
    }
    

提交回复
热议问题