82

我来自 Java EE 世界,但现在我正在从事一个 .Net 项目。在 Java 中,当我想测试一个受保护的方法时,这很容易,只需要具有相同包名的测试类就足够了。

C#有类似的东西吗?对受保护的方法进行单元测试有什么好的做法吗?我只发现框架和人们说我应该只测试公共方法。

没有任何框架应该是可以做到的……</p>

4

8 回答 8

101

您可以继承您在测试类上测试的类。

[TestClass]
public class Test1 : SomeClass
{
    [TestMethod]
    public void MyTest
    {
        Assert.AreEqual(1, ProtectedMethod());
    }

}
于 2012-11-16T12:04:23.797 回答
39

另一种选择是internal用于这些方法,然后用于InternalsVisibleTo允许您的测试程序集访问这些方法。这不会阻止同一程序集中的其他类使用这些方法,但会阻止不是您的测试程序集的其他程序集访问它们。

这不会为您提供尽可能多的封装和保护,但它非常简单并且很有用。

添加到AssemblyInfo.cs包含内部方法的程序集中

[assembly: InternalsVisibleTo("TestsAssembly")]
于 2017-09-12T09:14:42.327 回答
35

您可以在继承您要测试的类的新类中公开受保护的方法。

public class ExposedClassToTest : ClassToTest
{
    public bool ExposedProtectedMethod(int parameter)
    {
        return base.ProtectedMethod(parameter);
    }
}
于 2017-07-16T08:19:39.817 回答
8

您可以使用 PrivateObject 类来访问所有私有/受保护的方法/字段。

PrivateObject 是 Microsoft 单元测试框架中的一个类,它是一个包装器,可以调用通常无法访问的成员进行单元测试。

于 2017-03-06T06:54:14.053 回答
6

您可以使用反射来调用私有和受保护的方法。

请参阅此处了解更多信息:

http://msdn.microsoft.com/en-us/library/66btctbe.aspx

于 2012-11-16T12:10:15.970 回答
6

尽管公认的答案是最好的答案,但它并没有解决我的问题。从受保护的类派生出来的许多其他东西污染了我的测试类。最后,我选择将待测试逻辑提取到公共类中并对其进行测试。当然,这并不适合所有人,并且可能需要进行相当多的重构,但是如果您一直滚动到此答案,它可能会对您有所帮助。:) 这是一个例子

老情况:

protected class ProtectedClass{
   protected void ProtectedMethod(){
      //logic you wanted to test but can't :(
   }
}

新情况:

protected class ProtectedClass{
   private INewPublicClass _newPublicClass;

   public ProtectedClass(INewPublicClass newPublicClass) {
      _newPublicClass = newPublicClass;
   }

   protected void ProtectedMethod(){
      //the logic you wanted to test has been moved to another class
      _newPublicClass.DoStuff();
   }
}

public class NewPublicClass : INewPublicClass
{
   public void DoStuff() {
      //this logic can be tested!
   }
}

public class NewPublicClassTest
{
    NewPublicClass _target;
    public void DoStuff_WithoutInput_ShouldSucceed() {
        //Arrange test and call the method with the logic you want to test
        _target.DoStuff();
    }
}
于 2018-09-17T12:48:31.653 回答
0

您可以使用从基类调用受保护方法的公共方法创建存根。这也是您在生产中使用这种受保护方法的方式。

public class FooStub : Bar 
{
    public string MyMethodFoo()
    {
        return MyMethodBar();
    }
}

public abstract class Bar 
{
    protected string MyMethodBar()
    {
        return "Hello World!"
    }
}
于 2021-01-18T12:06:12.673 回答
0

这是我在测试项目中使用的扩展方法(扩展方法是什么?) 。唯一的缺点是您必须将名称写成 a string,因为nameof()它遵循保护规则,并且不允许您引用受保护或私有成员。

        public static MethodInfo GetNonPublicMethod(this Type type, string method)
        {
            MemberInfo[] temp = type.GetMember(method, MemberTypes.Method, BindingFlags.NonPublic | BindingFlags.Instance);
            if (temp.Length == 1)
            {
                if (temp[0] is MethodInfo ret)
                {
                    return ret;
                }
                else
                {
                    throw new ArgumentException("Not a method.");
                }
            }
            else
            {
                if (temp.Length == 0)
                {
                    throw new ArgumentException("Method was not found.");
                }
                else
                {
                    throw new ArgumentException("Multiple methods found.");
                }
            }
        }

有关此方法的更多信息:https ://docs.microsoft.com/en-us/dotnet/api/system.type.getmember?view=net-5.0

PS:methodInfo.Invoke(instance, params)用来调用它。

于 2021-09-15T11:34:09.897 回答