.NET中如何测试Private和Protected方法
TDD是1)写测试2)写通过这些测试的代码,3)然后重构的实践.在,NET社区中, 这个概念逐渐变得非常流行,这归功于它所增加的质量保证.此时,它很容易测试public方法,但是一个普遍的问题出现了,”我如何测试Protected和private方法呢?”
本文将:
- 总结”你是否应该测试private方法的争论?”的一些关键点.
- 创建一些案例,这些案例仍旧是有用的,至少知道怎样测试private和protected方法—不考虑你站在争论的哪一边.
- 提供方法和可下载的代码示例来展现这些测试技术.
背后的方法
你是否应该测试private方法?
一个Google查询 向你展示了有很多关于使用private方法的争议,更不用说测试他们了.下面这个表概括了一些关于这个话题的正方和反方的普遍意见.
正方 |
反方 |
|
使用private方法 |
|
|
测试Private方法 |
|
|
在这些主题的两方,都有明了并且具有经验的人.因此我不打算,也不期望终结”我是否应该测试private方法”的争论.但是对于双方来说,这里仍有价值来知道如何测试他们,即使你认为private不应该被测试.
- 如果你至少能表现出你可以测试他们,但是你没有这样做(例如,你没有简单的说”不要测试private方法”,因为你不知道如何去测试),你的观点将更加具有说服力.
- 测试非public方法的选择让你明白在你的小组中,什么真正做的最好.
- 只要仍有有效的条件,是值得拥有一种方便的方法来测试他们.
好的原则以及不适当的技术
Andrew Hunt a和 David Thomas在他们的书中Pragmatic Unit Testing in C# with NUnit, 解释到,好的单元测试是ATRIP:
- 自动化(Automatic)
- 彻底(Thorough )
- 可重复(Repeatable)
- 独立(Independent )
- 专业(Professional)
对于测试private/protected方法来说,有另外三个附加原则:
- 透明(Transparency) - 不要改变测试下的系统(System Under Test ,SUT),例如,在产品代码中增加包装的方法.
- 范围(Scope) - 可以在Debug和Release下运行
- 简单(Simplicity) -最小的开销,因此容易修改,并且非常简单引入最小的风险.
记住这些原则,下面是一些不足的策略.
策略 |
问题 |
不要使用任何private方法. |
|
使用指示符#if DEBUG ... #endif来包装一个public方法,这个方法然后包装private方法.单元测试现在可以间接访问那些public方法包装的private方法.(这是一种我使用许多次的方法,并且发现它是单调的,不是面向对象的) |
|
Public方法使用[ |
|
创建内部方法来访问private方法.然后在public方法包装那些private方法的程序集的其他地方,创建一个公共的测试类. |
|
测试Protected方法
Protected方法仅仅对于它得继承类可见,因此,对于测试套件来说并不是立即可见的.例如,激射我们想测试来自from ClassLibrary1.MyObject
的方法.
protected string MyProtectedMethod(string strInput, int i32Value)
{
return this.Name + ": " + strInput + ", " +
i32Value.ToString();
}
Pragmatic Unit Testing in C# with NUnit一书解释了一个解决方案:创建一个继承自MyObject类的类MyObjectTester,然后创建一个public方法TestMyProtectedMethod
,
这个方法包装了那个
protected
方法
.
例如
,
public new string TestMyProtectedMethod(string strInput, int i32Value)
{
return base.MyProtectedMethod(strInput, i32Value);
}
方法很简单,也遵循所有原则:
原则 |
实现 |
透明 |
通过使用继承,并把 |
范围 |
在本方法中没有任何东西依赖Debug-only技术. |
简单 |
尽管这个方法需要一新的类,以及每个protected 方法的额外public包装方法,但是它是面向对象的,并且使类型安全的. |
测试Private方法
测试private方法需要多做有些工作,但是我们仍可以使用System.Reflection来实现.你可以使用反射来动态访问一种类型的方法, 包括实例和静态private方法的方法.注意访问private方法需要ReflectionPermission,但是对于运行在开发机器或者构建服务器上的单元测试来说,这不是问题.
假设我们想测试来自ClassLibrary1.MyObject
的private方法MyPrivateMethod
:
private string MyPrivateMethod(string strInput, DateTime dt, double dbl)
{
return this.Name + ": " + strInput + ", " +
dt.ToString() + ", " + dbl.ToString();
}
一个解决方法是创建一个UnitTestUtilities工程,这个工程有一个helper类通过反射来调用测试方法.例如,供下载的解决方案在UnitTestUtilities.Helper
中有如下方法:
public static object RunStaticMethod(System.Type t, string strMethod,
object [] aobjParams)
{
BindingFlags eFlags =
BindingFlags.Static | BindingFlags.Public |
BindingFlags.NonPublic;
return RunMethod(t, strMethod,
null, aobjParams, eFlags);
} //end of method
public static object RunInstanceMethod(System.Type t, string strMethod,
object objInstance, object [] aobjParams)
{
BindingFlags eFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
return RunMethod(t, strMethod,
objInstance, aobjParams, eFlags);
} //end of method18private static object RunMethod(System.Type t, string
strMethod, object objInstance, object [] aobjParams, BindingFlags eFlags)
{
MethodInfo m;
try
{
m = t.GetMethod(strMethod, eFlags);
if (m == null)
{
throw new ArgumentException("There is no method '" + strMethod + "' for type '" + t.ToString() + "'.");
} object objRet = m.Invoke(objInstance, aobjParams);
return objRet;
}
catch
{
throw;
}
} //end of method
Private方法RunMethod
带有一些必要的参数,这些参数是反射需要用来调用一个方法,然后返回值的.它有两个public方法RunStaticMethod
和RunInstanceMethod
来为静态和实例方法分别包装这.
看看RunMethod
,它首先得到类型的MethodInfo.
因为我们期望它仅为已经存在的方法调用
.
一个空的方法触发一个
Exception
.
一旦我们有
MethodInfo
,我们就可以调用实例化对象提供的方法(static 方法为null)以及参数数组.
我们可以在一个NUnit测试中像下面使用这个Utility:
[Test]
public void TestPrivateInstanceMethod()
{
string strExpected = "MyName: Hello, 5/24/2004
:: AM, 2.1"; ClassLibrary1.MyObject objInstance
= new MyObject("MyName"); object obj =
UnitTestUtilities.Helper.RunInstanceMethod(
typeof(ClassLibrary1.MyObject), "MyPrivateMethod",
objInstance, new object[] {"Hello",
new DateTime(,,), 2.1}); string strActual = Convert.ToString(obj);
Assert.AreEqual(strExpected,strActual);}
原则 |
实现 |
透明 |
我们仅创建的多余代码; |
范围 |
在本方法中没有任何东西依赖Debug-only技术. |
简单 |
Because the method is being dynamically called, the parameters aren't checked at compile time.本方法可以通过一个简单的调用来调用任何方法.一旦你有 |
总结
关于是否应该测试private方法仍有争论,但是我们有能力去测试他们.我们可以使用继承创 建一个继承类TesterClass
来测试protected方法.这个继承类包装了其基类的 protected方法为public.我们可以是哦女冠反射来测试private方法,它能够抽象 到一个UnitTestUtility
helper类.这些技术都能帮助你改进测试覆盖面.
.NET中如何测试Private和Protected方法的更多相关文章
- Private和Protected方法
.NET中如何测试Private和Protected方法 TDD是1)写测试2)写通过这些测试的代码,3)然后重构的实践.在,NET社区中, 这个概念逐渐变得非常流行,这归功于它所增加的质量保证. ...
- 在MS Test中如何测试private方法
前言: 在博客开始之前,我们先讨论一下是否应该对private方法做测试,通常有两种观点: private方法应该被测试: private方法不应该被测试: 我们以下面的代码为例子来进行说明: pub ...
- C#中public、private、protected、internal、protected internal (转载)
在C#语言中,共有五种访问修饰符:public.private.protected.internal.protected internal.作用范围如下表:访问修饰符 说明public 公有访问.不受 ...
- java中public、private、protected区别
类中的数据成员和成员函数据具有的访问权限包括:public.private.protect.friendly(包访问权限) 1.public:public表明该数据成员.成员函数是对所有用户开放的,所 ...
- java中public,private,protected和default的区别
类中的数据成员和成员函数据具有的访问权限包括:public.private.protect.default(包访问权限) 作用域 当前类 同一package 子孙类 其他pac ...
- C#中public、private、protected等关键字说明
public 公有访问.不受任何限制.private 私有访问.只限于本类成员访问,子类,实例都不能访问.protected 保护访问.只限于本类和子类访问,实例不能访问.internal 内部访问. ...
- java面向对象中四种权限(private,protected,public,友好型)详解
转自http://blog.csdn.net/a1237871112/article/details/50926975 及http://blog.csdn.net/blackmanren/articl ...
- C#中五种访问修饰符作用范围 public、private、protected、internal、protected internal
1.五种访问修饰符包括哪些? public.private.protected.internal.protected internal 2.五种访问修饰符的作用范围? public :公有访问.不受 ...
- Ruby中访问控制符public,private,protected区别总结
重点关注private与protected public 默认即为public,全局都可以访问,这个不解释 private C++, “private” 意为 “private to this cla ...
随机推荐
- 穿透Session 0 隔离(二)
上一篇我们已经对Session 0 隔离有了进一步认识,如果在开发过程中确实需要服务与桌面用户进行交互,可以通过远程桌面服务的API 绕过Session 0 的隔离完成交互操作. 对于简单的交互,服务 ...
- 基于kubernetes集群的Vitess最佳实践
概要 本文主要说明基于kubernetes集群部署并使用Vitess; 本文假定用户已经具备了kubernetes集群使用环境,如果不具备请先参阅基于minikube的kubernetes集群搭建, ...
- Share and NTFS Permission
NTFS Permissions Share Permissions Share and NTFS Permission Similarities 共享权限和NTFS权限的相似性 Modifying ...
- Java 语言基础之函数
函数的定义: 函数就是定义在类中的具有特定功能的一段独立小程序 函数也称为方法 函数定义格式: 修饰符 返回值类型 函数名(参数类型 形式参数1, 参数类型 形式参数2,...) { 执行语句; re ...
- jQuery实现图片预览
摘自:http://www.cnblogs.com/leejersey/p/3660202.html JS代码: /* *名称:图片上传本地预览插件 v1.1 *作者:周祥 *时间:2013年11月2 ...
- hadoop开发MapReduce程序
准备工作: 1.设置HADOOP_HOME,指向hadoop安装目录 2.在window下,需要把hadoop/bin那个目录替换下,在网上搜一个对应版本的 3.如果还报org.apache.hado ...
- Linux运维工程师:30道面试题整理
1.linux 如何挂在 windows 下的共享目录 mount.cifs //192.168.1.3/server /mnt/server -o user=administrator,pass=1 ...
- Android Studio java和XML快速切换技巧
今天又发现了一个Android Studio强大的功能,非常惊叹! 我们开发Android应用程序时,Activity或者Fragment会有一个相对应的布局.在Eclipse中或者一般的做法,我们会 ...
- vue生命周期以及vue的计算属性
一.Vue生命周期(vue实例从创建到销毁的过程,称为生命周期,共有八个阶段) 1.beforeCreate :在实例初始化之后,数据观测 (data observer) 和 event/watche ...
- 吴超老师课程---Hadoop的伪分布安装
1.1 设置ip地址 执行命令 service network restart 验证: ifconfig1.2 关闭防火墙 执行命令 service ip ...