代码之家  ›  专栏  ›  技术社区  ›  Pablo notPicasso

最小起订量设置方法

  •  1
  • Pablo notPicasso  · 技术社区  · 6 年前

    我需要测试许多类似的方法

    public interface ITest
    {
        void Method1(bool readMode, List<int> list);
        void Method2(bool readMode, List<int> list);
        void Method3(bool readMode, List<string> list);
    ...
    }
    

    测试所有方法非常相似:

    public void Method1Test()
    {
        Mock<ITest> test = new Mock<Itest>();
        test.Setup(x=>x.Method1(It.IsAny<bool>(), It.IsAny<List<int>>()).Verifable();
        // do stuff
        test.Verify(x=>x.Method1(true, It.IsAny<List<int>>()), Times.AtLeastOnce());
        test.Verify(x=>x.Method1(false, It.IsAny<List<int>>()), Times.Never());
        test.Verify(x=>x.Method1(It.IsAny<bool>(), It.Is<List<int>>(y=>y.Count == 0)), Times.Never());
        test.Verify(x=>x.Method1(It.IsAny<bool>(), It.Is<List<int>>(y=>y.Count == 2)), Times.Once());
    }
    


    我想这样写:

    public void Method1Test()
    {
        TestAnyMethod<int>(x=>x.Method1);
    }
    public void Method2Test()
    {
        TestAnyMethod<int>(x=>x.Method2);
    }
    public void Method3Test()
    {
        TestAnyMethod<string>(x=>x.Method3);
    }
    
    3 回复  |  直到 6 年前
        1
  •  2
  •   KozhevnikovDmitry    6 年前

    Moq使用表达式树进行配置,因此您可以通过构建各种 Expression<Action<ITest>> 实例。仅举一个例子,说明如何在您的特定情况下实现:

    public interface ITest
    {
        void Method1(bool readMode, List<int> list);
        void Method2(bool readMode, List<int> list);
        void Method3(bool readMode, List<string> list);
    }
    
    [Test]
    public void Method1Test()
    {
        Mock<ITest> test = new Mock<ITest>();
    
        TestAnyMethod<ITest, int>(test, "Method1");
        TestAnyMethod<ITest, int>(test, "Method2");
        TestAnyMethod<ITest, string>(test, "Method3");
    
        test.VerifyAll();
    }
    
    private void TestAnyMethod<T, TItem>(Mock<ITest> test, string methodName)
    {
        // Arrange
        var type = typeof(T);
        var methodInfo = type.GetMethod(methodName);
        test.Setup(Verifiable<TItem>(type, methodInfo)).Verifiable();
    
        // Act
        // make verifying call via reflection:
    
        // object.Method#(true, new List<TItem> { .. }))
        methodInfo.Invoke(test.Object, new object[] {true, new List<TItem>{ default(TItem) } });
    
        // object.Method#(true, new List<TItem> { .. , .. })
        methodInfo.Invoke(test.Object, new object[] {true, new List<TItem> { default(TItem), default(TItem) } });
    
        // Assert
        test.Verify(VerifyReadMode<TItem>(type, methodInfo, true), Times.AtLeastOnce());
        test.Verify(VerifyReadMode<TItem>(type, methodInfo, false), Times.Never());
        test.Verify(VerifyListCount<TItem>(type, methodInfo, 0), Times.Never());
        test.Verify(VerifyListCount<TItem>(type, methodInfo, 2), Times.Once());
    }
    
    /// <summary>
    /// Returns x=>x.Method#(It.IsAny`bool`(), It.IsAny`List`int``()
    /// </summary>
    /// <param name="mockingType">The type that we mock</param>
    /// <param name="method">Verifying method</param>
    private Expression<Action<ITest>> Verifiable<T>(Type mockingType, MethodInfo method)
    {
        var readModeArg = Expression.Call(typeof(It), "IsAny", new []{ typeof(bool) });
        var listArg = Expression.Call(typeof(It), "IsAny", new[] { typeof(List<T>) });
    
        return Verify(mockingType, method, readModeArg, listArg);
    }
    
    /// <summary>
    /// Returns x=>x.Method#(<paramref name="readMode"/>, It.IsAny`List`int``()
    /// </summary>
    /// <param name="mockingType">The type that we mock</param>
    /// <param name="method">Verifying method</param>
    /// <param name="readMode"></param>
    private Expression<Action<ITest>> VerifyReadMode<T>(Type mockingType, MethodInfo method, bool readMode)
    {
        var readModeArg = Expression.Constant(readMode);
        var listArg = Expression.Call(typeof(It), "IsAny", new[] { typeof(List<T>) });
    
        return Verify(mockingType, method, readModeArg, listArg);
    }
    
    /// <summary>
    /// Returns x=>x.Method#(It.IsAny`bool`(), It.Is`List`int``(y=>y.Count == <paramref name="count"/>)
    /// </summary>
    /// <param name="mockingType">The type that we mock</param>
    /// <param name="method">Verifying method</param>
    private Expression<Action<ITest>> VerifyListCount<T>(Type mockingType, MethodInfo method, int count)
    {
        var readModeArg = Expression.Call(typeof(It), "IsAny", new[] { typeof(bool) });
    
        var listPrm = Expression.Parameter(typeof(List<T>), "y");
        var prop = Expression.Property(listPrm, typeof(List<T>), "Count");
        var equal = Expression.Equal(prop, Expression.Constant(count));
        var lambda = Expression.Lambda<Func<List<T>, bool>>(equal, "y", new [] { listPrm });
        var listArg = Expression.Call(typeof(It), "Is", new[] { typeof(List<T>) }, lambda);
    
        return Verify(mockingType, method, readModeArg, listArg);
    }
    
    /// <summary>
    /// Returns lambda expression for verifying <paramref name="method"/> with arguments
    /// </summary>
    /// <param name="mockingType">The type that we mock</param>
    /// <param name="method">Verifying method</param>
    /// <param name="readModeArg">Expression for verify readMode argument</param>
    /// <param name="listArg">Expression for verify list argument</param>
    private Expression<Action<ITest>> Verify(Type mockingType, MethodInfo method, Expression readModeArg, Expression listArg)
    {
        var prm = Expression.Parameter(mockingType, "x");
        var methodCall = Expression.Call(prm, method, readModeArg, listArg);
        Expression<Action<ITest>> expr = Expression.Lambda<Action<ITest>>(methodCall, "x", new[] { prm });
        return expr;
    }
    

    希望有帮助。

        2
  •  0
  •   Pablo notPicasso    6 年前

    我可以通过基于传递的方法创建用于验证的表达式来实现这一点

    // Helper function to get It.IsAny<T>() Expression
    public static System.Linq.Expressions.MethodCallExpression IsAny<T>()
    {
        return System.Linq.Expressions.Expression.Call(typeof(It).GetMethod("IsAny").MakeGenericMethod(typeof(T)));
    }
    
    // Helper function to check conditions for list.Count
    public static bool CheckProperties(System.Collections.IList list, int expected)
    {
        return list.Count == expected;
    }
    
    public void TestMethod1()
    {
        var test = Mock.Of<ITest>();
        Mock.Get(test).Setup(x => x.Method1(It.IsAny<bool>(), It.IsAny<List<int>>())).Verifiable();
        //do stuff
        // Method1 passed as parameter
        TestAnyMethod<int>(test, x => x.Method1);
    }
    
    public void TestAnyMethod<T>(ITest test, Func<ITest, Action<bool, List<T>>> methodToTest)
    {
        var type = typeof(ITest);
        var param = Expression.Parameter(type);
        var method = type.GetMethod(methodToTest(Mock.Of<ITest>()).Method.Name); // Method that will be tested
    
        //test.Verify(x => x.METHOD(true, It.IsAny<List<T>>()), Times.AtLeastOnce());
        var call = Expression.Call(param, method, Expression.Constant(true), IsAny<List<T>>());
        Mock.Get(test).Verify(Expression.Lambda<Action<ITest>>(call, param),Times.AtLeastOnce());
    
        //test.Verify(x => x.METHOD(true, It.IsAny<List<T>>()), Times.AtLeastOnce());
        call = Expression.Call(param, method, Expression.Constant(true), IsAny<List<T>>());
        Mock.Get(test).Verify(Expression.Lambda<Action<ITest>>(call, param), Times.AtLeastOnce());
    
        var propertiesParam = Expression.Parameter(typeof(List<T>));
        var checkPropertiesMethod = GetType().GetMethod("CheckProperties", BindingFlags.Public | BindingFlags.Static);
    
        // test.Verify(x => x.METHOD(It.IsAny<bool>(), It.Is<List<T>>(y => y.Count == 0)), Times.Never());
        var checPropertiesCall = Expression.Call(Expression.Constant(this), checkPropertiesMethod, propertiesParam, Expression.Constant(0));
        call = Expression.Call(param, method, TestUtils.IsAny<bool>(), TestUtils.Is<EditFieldProperties<T>>(Expression.Lambda<bool>(checPropertiesCall, propertiesParam)));
        Mock.Get(test).Verify(Expression.Lambda<Action<ITest>>(call, param), Times.Never());
    
        // test.Verify(x => x.METHOD(It.IsAny<bool>(), It.Is<List<int>>(y => y.Count == 2)), Times.Once());
        checPropertiesCall = Expression.Call(Expression.Constant(this), checkPropertiesMethod, propertiesParam, Expression.Constant(2));
        call = Expression.Call(param, method, TestUtils.IsAny<bool>(), TestUtils.Is<EditFieldProperties<T>>(Expression.Lambda<bool>(checPropertiesCall, propertiesParam)));
        Mock.Get(test).Verify(Expression.Lambda<Action<ITest>>(call, param), Times.Once());
    
    }
    

    在我的项目中,我更进一步。我从“做事情”中提取了所有的东西,并将其传递给 VerifyAnyMethod Action 验证方法 .

        3
  •  -2
  •   schen993    6 年前

    我认为C有自动测试项目。。。您可以尝试一下,将公共代码放在[TestSetup]中,方法放在[TestMethod]中。从google上你可以查看以下链接 Automated Unit testing - why? what? which? ... 希望它能帮到你,如果它解决了你的问题,请标记为答案。