简体   繁体   English

在.NET中对私有方法进行单元测试的最佳实践是什么?

[英]What is the best practice for unit testing private methods in .NET?

Recently in order to implement unit testing for a private method of a class, I used PrivateObject by creating a private accessors instead of using Reflection , to which I received the following code review comment: 最近为了实现类的私有方法的单元测试,我通过创建私有访问器而不是使用Reflection使用PrivateObject ,我收到了以下代码审查注释:

"My main concern with Private Object is the use of object[] in constructor. It replaces strong typing enforced by compiler with JavaScript-style run-time error detection.Consequently , personally, I would not recommend it." “我对私有对象的主要关注是在构造函数中使用object []。它取代了编译器强制执行的强类型操作和JavaScript式运行时错误检测。因此,个人而言,我不推荐它。”

This comment above confused me beacuse as per my understanding, Reflection also needs the object[] to invoke any method. 根据我的理解,上面的这条评论使我感到困惑,Reflection也需要object[]来调用任何方法。 Please help me to understand what the best approach is. 请帮助我了解最佳方法。

  • You can use special classes that inherit classes with private (now protected) methods and provide public methods that call invisible from outside protected methods. 您可以使用通过私有(现在受保护)方法继承类的特殊类,并提供从外部受保护方法调用不可见的公共方法。

This is called Test Specific Subclass or Test Specific Extension in great book Refactoring Test Code http://xunitpatterns.com/ 这在伟大的书重构测试代码http://xunitpatterns.com/中称为测试特定子类或测试特定扩展

You can read more details and ideas for testing private methods here : http://xunitpatterns.com/Test-Specific%20Subclass.html 您可以在此处阅读有关测试私有方法的更多详细信息和想法: http//xunitpatterns.com/Test-Specific%20Subclass.html

It works like 它很像

public TestClass : RealClass
{
    public int  CallHiddenCalculate()
    {
        return  Calculate(); // Calculate is now protected method that we expose for test purposes in this class
    }
}

You can place this class to test assembly so your real assembly doesnt contain test specific logic and classes because its bad design. 您可以将此类放置为测试程序集,以便您的实际程序集不包含特定于测试的逻辑和类,因为它的设计很糟糕。

  • You can also use conditional compilation for visibility attribute like the following 您还可以使用条件编译作为可见性属性,如下所示
#if DEBUG
        public
    #else
        private
    #endif

In this case in Debug you can call unit tests but in release those methods won't be visible. 在这种情况下,在Debug中,您可以调用单元测试,但在发布时,这些方法将不可见。 However this approach is much worse than the above and is more ugly too. 然而,这种方法比上述方法更糟糕,也更丑陋。

Testing just public interface can easily be not enough (and often is not) in order to say that you got good test coverage and your code is easy to maintain and refactor. 仅仅测试公共接口可能是不够的(通常不是),以便说您获得了良好的测试覆盖率,并且您的代码易于维护和重构。

As for marking private methods as internal and having test assembly see internal methods is bad for many reasons 至于将私有方法标记为内部并且具有测试程序集,请参阅内部方法由于许多原因而不好

  1. your ex private methods are visible from your assembly cause they are internal 您的前私人方法在您的装配中可见,因为它们是内部的
  2. you will have test specific logic (internal for those methods will only be for test purposes) in release version of your product, which is bad 您将在产品的发布版本中具有测试特定逻辑(这些方法的内部仅用于测试目的),这很糟糕

and I think there are more but those are most important 而且我认为还有更多,但这些是最重要的

Interesting question. 有趣的问题。 Generally, unit tests are meant to verify the public behavior of your classes, from the viewpoint of consumers of your classes. 通常,单元测试旨在从类的使用者的角度验证类的公共行为。 That is, the consumers don't care HOW you do it, so long as your class keeps the promises it makes. 也就是说,只要你的班级信守承诺,消费者就不会在意这么做。

If you REALLY need to expose 'private' members to unit test, mark them as internal and make them accessible via the InternalsVisibleTo attribute. 如果您真的需要将“私有”成员公开给单元测试,请将它们标记为内部并通过InternalsVisibleTo属性访问它们。 It's ugly, but it works, and you can later keep it out of your assembly with some conditional compilation. 这很丑陋,但它确实有效,你可以稍后通过一些条件编译将它从程序集中删除。

You are right that using reflection has much the same pitfalls as using the PrivateObject pattern. 你是对的,使用反射与使用PrivateObject模式有很多相同的陷阱。 A better solution is to avoid trying to specifically test private methods. 更好的解决方案是避免尝试专门测试私有方法。

In case you are using the Gallio/MbUnit testing framework, you might consider the built-in Mirror API. 如果您使用的是Gallio / MbUnit测试框架,则可以考虑使用内置的Mirror API。

Sometimes, the most obvious way to write a test is by accessing non-public state or behaviors. 有时,编写测试最明显的方法是访问非公共状态或行为。 It may not be the best way to write the test but it may seem like the simplest solution for the time being. 它可能不是编写测试的最佳方式,但它似乎是目前最简单的解决方案。 MbUnit provides a couple of classes to help access non-public members. MbUnit提供了几个类来帮助访问非公共成员。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM