我正在构建一个类库,它将有一些公共和私有方法。我希望能够对私有方法进行单元测试(主要是在开发过程中,但也可以用于将来的重构)。

正确的做法是什么?


当前回答

将它们声明为内部的,然后使用InternalsVisibleToAttribute允许单元测试程序集看到它们。

其他回答

有两种类型的私有方法。静态私有方法和非静态私有方法(实例方法)。下面两篇文章用示例解释了如何对私有方法进行单元测试。

单元测试静态私有方法 单元测试非静态私有方法

MS Test内置了一个很好的特性,通过创建一个名为VSCodeGenAccessors的文件,可以在项目中使用私有成员和方法

[System.Diagnostics.DebuggerStepThrough()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TestTools.UnitTestGeneration", "1.0.0.0")]
    internal class BaseAccessor
    {

        protected Microsoft.VisualStudio.TestTools.UnitTesting.PrivateObject m_privateObject;

        protected BaseAccessor(object target, Microsoft.VisualStudio.TestTools.UnitTesting.PrivateType type)
        {
            m_privateObject = new Microsoft.VisualStudio.TestTools.UnitTesting.PrivateObject(target, type);
        }

        protected BaseAccessor(Microsoft.VisualStudio.TestTools.UnitTesting.PrivateType type)
            :
                this(null, type)
        {
        }

        internal virtual object Target
        {
            get
            {
                return m_privateObject.Target;
            }
        }

        public override string ToString()
        {
            return this.Target.ToString();
        }

        public override bool Equals(object obj)
        {
            if (typeof(BaseAccessor).IsInstanceOfType(obj))
            {
                obj = ((BaseAccessor)(obj)).Target;
            }
            return this.Target.Equals(obj);
        }

        public override int GetHashCode()
        {
            return this.Target.GetHashCode();
        }
    }

使用派生自BaseAccessor的类

[System.Diagnostics.DebuggerStepThrough()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.TestTools.UnitTestGeneration", "1.0.0.0")]
internal class SomeClassAccessor : BaseAccessor
{

    protected static Microsoft.VisualStudio.TestTools.UnitTesting.PrivateType m_privateType = new Microsoft.VisualStudio.TestTools.UnitTesting.PrivateType(typeof(global::Namespace.SomeClass));

    internal SomeClassAccessor(global::Namespace.Someclass target)
        : base(target, m_privateType)
    {
    }

    internal static string STATIC_STRING
    {
        get
        {
            string ret = ((string)(m_privateType.GetStaticField("STATIC_STRING")));
            return ret;
        }
        set
        {
            m_privateType.SetStaticField("STATIC_STRING", value);
        }
    }

    internal int memberVar    {
        get
        {
            int ret = ((int)(m_privateObject.GetField("memberVar")));
            return ret;
        }
        set
        {
            m_privateObject.SetField("memberVar", value);
        }
    }

    internal int PrivateMethodName(int paramName)
    {
        object[] args = new object[] {
            paramName};
        int ret = (int)(m_privateObject.Invoke("PrivateMethodName", new System.Type[] {
                typeof(int)}, args)));
        return ret;
    }

这里有一篇关于私有方法单元测试的好文章。但是我不知道哪个更好,是让你的应用程序专门为测试而设计(就像只为测试而创建测试)还是使用反射来测试。 我敢肯定大多数人都会选择第二种方式。

你可以用两种方法对私有方法进行单元测试

you can create instance of PrivateObject class the syntax is as follows PrivateObject obj= new PrivateObject(PrivateClass); //now with this obj you can call the private method of PrivateCalss. obj.PrivateMethod("Parameters"); You can use reflection. PrivateClass obj = new PrivateClass(); // Class containing private obj Type t = typeof(PrivateClass); var x = t.InvokeMember("PrivateFunc", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, obj, new object[] { 5 });

在CodeProject上,有一篇文章简要讨论了测试私有方法的优缺点。然后它提供一些反射代码来访问私有方法(类似于Marcus上面提供的代码)。我在这个示例中发现的唯一问题是代码没有考虑重载方法。

你可以在这里找到文章:

http://www.codeproject.com/KB/cs/testnonpublicmembers.aspx