我正在构建一个类库,其中包含一些公共和私有方法。我希望能够单元测试私有方法(主要是在开发过程中,但也可能对未来的重构有用)。
正确的操作方式是什么?
我正在构建一个类库,其中包含一些公共和私有方法。我希望能够单元测试私有方法(主要是在开发过程中,但也可能对未来的重构有用)。
正确的操作方式是什么?
如果你想对一个私有方法进行单元测试,那么可能存在问题。通常情况下,单元测试是用来测试类的接口,也就是它的公共(和受保护的)方法。当然,你可以通过“黑科技”来解决这个问题(即使只是将方法设置为公共方法),但是你也可以考虑以下几点:
如果您正在使用.NET,应该使用InternalsVisibleToAttribute。
测试私有方法可能并不常用。然而,我有时会从测试方法中调用私有方法,这样可以避免为测试数据生成编写重复代码...
Microsoft 提供了两种机制:
访问器(Accessors)
但是,当原始类的接口发生更改时,该机制有时会变得有些棘手。因此,大多数情况下我避免使用它。
PrivateObject 类 另一种方式是使用 Microsoft.VisualStudio.TestTools.UnitTesting.PrivateObject。
// Wrap an already existing instance
PrivateObject accessor = new PrivateObject( objectInstanceToBeWrapped );
// Retrieve a private field
MyReturnType accessiblePrivateField = (MyReturnType) accessor.GetField( "privateFieldName" );
// Call a private method
accessor.Invoke( "PrivateMethodName", new Object[] {/* ... */} );
X
的FooService
,那么你关心的只是请求时它确实执行X
。它如何执行并不重要。如果类中存在接口无法检测到的问题(不太可能),它仍然是一个有效的FooService
。如果这是一个可通过接口看到的问题,公共成员的测试应该能够检测到它。整个重点应该是只要轮子正常运转,它就可以用作轮子。 - BasicPrivMethod
存在问题,那么调用PrivMethod
的PubMethod
的测试应该能够暴露出来。当你将SimpleSmtpService
更改为GmailService
时会发生什么?突然间,你的私有测试指向的代码不再存在,或者可能工作方式不同并且会失败,尽管应用程序可能按设计完美运行。如果有适用于两个电子邮件发送器的复杂处理过程,也许应该放在一个名为EmailProcessor
的地方,可以由两个服务共享,并进行单独测试。 - Basic在我很少需要测试私有函数的情况下,我通常会将它们改为受保护状态,然后编写一个带有公共封装函数的子类。
该类:
...
protected void APrivateFunction()
{
...
}
...
测试用的子类:
...
[Test]
public void TestAPrivateFunction()
{
APrivateFunction();
//or whatever testing code you want here
}
...
私有类型、内部类型和私有成员之所以如此,是因为它们有一些原因,通常您不希望直接干预它们。如果您这样做,很可能会在以后出现问题,因为创建这些程序集的人不能保证私有/内部实现仍然保持不变。
但是,有时在对已编译或第三方程序集进行某些黑客/探索时,我发现自己想要初始化一个私有类或具有私有或内部构造函数的类。或者,有时处理无法更改的预编译遗留库时,我会编写一些针对私有方法的测试。
因此,AccessPrivateWrapper应运而生 - http://amazedsaint.blogspot.com/2010/05/accessprivatewrapper-c-40-dynamic.html - 它是一个快速包装器类,使用C# 4.0动态特性和反射使工作变得容易。
您可以创建内部/私有类型,例如:
//Note that the wrapper is dynamic
dynamic wrapper = AccessPrivateWrapper.FromType
(typeof(SomeKnownClass).Assembly,"ClassWithPrivateConstructor");
//Access the private members
wrapper.PrivateMethodInPrivateClass();
你可以通过两种方式对私有方法进行单元测试。
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 });
PrivateClass
实例并使用它。https://dev59.com/wGox5IYBdhLWcg3wklCE - SharpC我也使用了InternalsVisibleToAttribute方法。值得一提的是,如果您感到不舒服将以前的私有方法更改为内部方法以实现这一点,那么也许它们根本不应成为直接单元测试的对象。
毕竟,您正在测试类的行为,而不是其具体实现——您可以更改后者而不更改前者,您的测试仍应该通过。
存在两种类型的私有方法:静态私有方法和非静态私有方法(实例方法)。以下两篇文章将通过示例解释如何对私有方法进行单元测试。