【问题标题】:Testing private static generic methods in C#在 C# 中测试私有静态泛型方法
【发布时间】:2017-06-19 18:53:04
【问题描述】:

如何测试私有静态泛型方法?我的测试项目可以看到内部结构。如何测试这些方法?

internal class Foo {

    // Non-static.  This works!
    private T TestThisMethod1<T>(T value) {
        Console.WriteLine("Called TestThisMethod1");
        return value;
    }

    // Static.  Can't get this to work!
    private static T TestThisMethod2<T>(T value) {
        Console.WriteLine("Called TestThisMethod2");
        return value;
    }

    // Static.  Can't get this to work!
    private static void TestThisMethod3<T>(T value) {
        Console.WriteLine("Called TestThisMethod3");
    }

    // Static.  Can't get this to work!
    private static void TestThisMethod4<T, T2>(T value, T2 value2) {
        Console.WriteLine("Called TestThisMethod4");
    }
}

第一个例子有效。它不是静态的。这是https://msdn.microsoft.com/en-us/library/bb546207.aspx的例子。

[TestMethod]
public void PrivateStaticGenericMethodTest() {

    int value = 40;
    var foo = new Foo();

    // This works.  It's not static though.
    PrivateObject privateObject = new PrivateObject(foo);
    int result1 = (int)privateObject.Invoke("TestThisMethod1", new Type[] { typeof(int) }, new Object[] { value }, new Type[] { typeof(int) });

    // Fails
    int result2 = (int)privateObject.Invoke("TestThisMethod2",  BindingFlags.Static | BindingFlags.NonPublic, new Type[] { typeof(int) }, new Object[] { value }, new Type[] { typeof(int) });

    // Fails
    PrivateType privateType = new PrivateType(typeof(Foo));
    int result2_1 = (int)privateType.InvokeStatic("TestThisMethod2", new Type[] { typeof(int) }, new Object[] { value }, new Type[] { typeof(int) });

    // Fails
    int result2_2 = (int)privateType.InvokeStatic("TestThisMethod2", BindingFlags.Static | BindingFlags.NonPublic, new Type[] { typeof(int) }, new Object[] { value }, new Type[] { typeof(int) });

    // Stopping here.  I can't even get TestThisMethod2 to work...
}

我写这篇文章的目的并不是要质疑或争论测试私有方法的优点:这个主题已经被反复争论了。更重要的是,我写这个问题的目的是说“应该可以使用 PrivateObject 或 PrivateType 来做到这一点。那么,怎么做呢?”

【问题讨论】:

  • 你的私有静态方法有消费者吗?如果不是,那为什么要测试它的行为?
  • 一般私有方法通过调用它们的公共方法进行测试
  • 没错,我通常遵循“仅测试公共方法”的规范。这些天来,如果可以避免的话,我讨厌公开任何东西。这种方法在代码中埋得很深。我应该能够使用 PrivateObject 或 PrivateType 单独测试此方法。
  • 通用 T 项目是问题所在。对于那些它由于某种原因找不到方法。

标签: c# generics testing methods static


【解决方案1】:

终于找到了一种方法,用谷歌搜索泛型类型的测试。使用对象自身请求该方法,然后运行 ​​make generic 方法调用并最后调用它。

[TestMethod]
public void TestMethod2()
{
    int value = 40;
    var foo = new Foo();

    MethodInfo fooMethod = foo.GetType().GetMethod("TestThisMethod2", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Instance);
    if (fooMethod == null)
    {
        Assert.Fail("Could not find method");
    }
    MethodInfo genericFooMethod = fooMethod.MakeGenericMethod(typeof(int));
    int result1 = (int)genericFooMethod.Invoke(typeof(int), new object[] { value });

    Assert.AreEqual(result1, value);
}

【讨论】:

  • 这是一个解决方案,它确实回答了这个问题。我期待 PrivateObject 或 PrivateType 可以在幕后执行此操作而无需自己进行反射。不幸的是,在这种特殊情况下,两者似乎都不起作用。
【解决方案2】:

您不应该测试私有方法。因为它们是一个可以改变的实现细节。你应该测试你的公共接口。

如果您在覆盖公共接口后有未覆盖的私有方法,请删除它们。

【讨论】:

  • 我不会总是遵守严格的规则“你不应该测试私有方法”。假设您有一个只有公共入口点的复杂控制台应用程序,您不会测试任何东西吗?我不想仅仅因为我想测试一个方法而改变它的可访问性。
  • 如果您的控制台应用程序不够模块化,并且只有 main 作为公共入口点,那么它要么是快速破解不值得为其编写单元测试的东西......要么是不合标准的软件设计.控制台应用程序是 UI...您的业务和数据层不应该是私有方法。
  • 控制台应用程序只是一个例子......我的意图不是讨论测试私有方法的价值与否。 Microsoft 看到了创建 PrivateObject 和 PrivateType 类来测试私有方法的价值。我正在寻求了解如何正确使用它们..
【解决方案3】:

通过我的测试,PrivateObject 似乎存在静态和泛型方法的问题。支持 Brian 的回答,这是一种您可以使用(和修改)的方法。

public static class PrivateMethodTester
{
    public static object InvokePrivateMethodWithReturnType<T>(T testObject, string methodName, BindingFlags flags, Type[] genericTypes, object[] parameters) {
        MethodInfo methodInfo = testObject.GetType().GetMethod(methodName, flags);
        if (methodInfo == null) {
            throw new Exception("Unable to find method.");
        }
        MethodInfo method = methodInfo.MakeGenericMethod(genericTypes);
        return method.Invoke(genericTypes, parameters);
    } 
}

这样称呼它:

            Type[] types = new Type[] { typeof(MyGenericType1) };
            var parameters = new object[] { new MyClassParam(), "stringParam" };
            var returnObj = PrivateMethod.InvokePrivateMethodWithReturnType(new TestObjectClass("fake", null), "MyPrivateMethodName", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Instance, types, parameters);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-28
    • 2015-04-17
    • 1970-01-01
    • 2015-06-05
    • 2023-04-01
    • 2023-03-20
    • 2010-11-24
    相关资源
    最近更新 更多