Private和Protected方法
.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
12:00:00 AM, 2.1"; ClassLibrary1.MyObject objInstance
= new MyObject("MyName"); object obj =
UnitTestUtilities.Helper.RunInstanceMethod(
typeof(ClassLibrary1.MyObject), "MyPrivateMethod",
objInstance, new object[3] {"Hello",
new DateTime(2004,05,24), 2.1}); string strActual = Convert.ToString(obj);
Assert.AreEqual(strExpected,strActual);18}

|
原则 |
实现 |
|
透明 |
我们仅创建的多余代码; |
|
范围 |
在本方法中没有任何东西依赖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类.这些技术都能帮助你改进测试覆盖面.
Private和Protected方法的更多相关文章
- .NET中如何测试Private和Protected方法
TDD是1)写测试2)写通过这些测试的代码,3)然后重构的实践.在,NET社区中, 这个概念逐渐变得非常流行,这归功于它所增加的质量保证.此时,它很容易测试public方法,但是一个普遍的问题出现了, ...
- 为什么类和接口不能使用private和protected?接口的方法不能使用private、protected、default
对于java程序员来说,java的访问权限修饰词public.protected.default.private的区别和使用肯定都不是问题,这里也不再啰嗦了,反正度娘一搜就一大把.最近在整理java ...
- java利用反射绕过私有检查机制实行对private、protected成员变量或方法的访问
在java中,如果类里面的变量是声明了private的,那么只能在被类中访问,外界不能调用,如果是protected类型的,只能在子类或本包中调用,俗话说没有不透风的墙.但是可以利用java中的反射从 ...
- Java 类、属性、方法修饰符 public、private、protected、default
Java 中修饰类修饰符:public .default (默认) Java 中修饰类中属性.方法修饰符:public.private.protected.default (默认) 通过 IDEA 创 ...
- 浅谈PHP的Public、Protected、Private三种方法的区别
public:权限是最大的,可以内部调用,实例调用等.protected: 受保护类型,用于本类和继承类调用.private: 私有类型,只有在本类中使用. <?php error_report ...
- JavaScript实现类的private、protected、public、static以及继承
JavaScript中的类 JavaScript实际上是一种弱类型语言,与C++和Java等语言不同.因此,在JavaScript中,没有强调类(class)这一概念,但实际运用中,类还是很重要的,比 ...
- C#中public、private、protected、internal、protected internal (转载)
在C#语言中,共有五种访问修饰符:public.private.protected.internal.protected internal.作用范围如下表:访问修饰符 说明public 公有访问.不受 ...
- Java关键字(一) 修饰符private、protected、public和default的作用域
我们经常用着四种修饰符去修饰变量.方法和类,但是这四种的作用域都一样吗? 其中private和public可能是最多人知道的,但是protected和default可能就不知道其具体的作用域是哪些范围 ...
- public,private,protected,以及不写时的差别
作用域public,private.protected.以及不写时的差别 这四个作用域的可见范围例如以下表所看到的. 说明:假设在修饰的元素上面没有写不论什么訪问修饰符,则表示friendly.不使用 ...
随机推荐
- JavaBean中DAO设计模式介绍
一.信息系统的开发架构 客户层-------显示层-------业务层---------数据层---------数据库 1.客户层:客户层就是client,简单的来说就是浏览器. 2.显示层:JSP/ ...
- Postman 是一个非常棒的Chrome扩展,提供功能强大的API & HTTP 请求调试
Postman 是一个非常棒的Chrome扩展,提供功能强大的API & HTTP 请求调试 需要FQ才能安装,使用时应该不用FQ了,除非使用postman的历史记录功能: 非常棒的C ...
- SharePoint 创建一个简单的Web Part 部分
SharePoint 创建一个简单的Web Part 部分 标准Web零件有时会很强大,运行多个功能的能力. 本文介绍了如何使用Visual Studio 创建一个简单的Web部分. 1. 打开VS, ...
- 编程算法 - 切割排序 代码(C)
切割排序 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 排序切割, 把一个数组分为, 大于k\小于k\等于k的三个部分. 能够使用高速排序的Parti ...
- BAT 特殊符号总结
原文:BAT 特殊符号总结 BAT特殊符号总结,用好特殊符号,利用提高开发效率.^ 转义符 用在特殊符号之前 比如: echo 非常^&批处理 如果不加^ 那么"批处理"将 ...
- hdu1047 Integer Inquiry 多次大数相加
转载请注明出处:http://blog.csdn.net/u012860063 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1047 Problem ...
- Cassandra C++/NodeJs开发环境
工作的需要,开始更多地倾向于去中心化的结构,目前看来Cassandra算是去中心化DB中性能/管理最热门的选择,崇尚其P2P的理念. 自身原因对JAVA不擅长(周围写C的好少),还是更热衷于C++/J ...
- MapGuide应用程序演示样例——你好,MapGuide!
图 3‑4显示了基于MapGuide的Web应用程序的开发流程,整个开发流程能够分为五个阶段.图中,矩形代表任务,椭圆形被任务使用的或被任务创建的实体,箭头代表数据流. 1) 载入文件类型的数据,配置 ...
- linux 多个源文件在编译时会产生一个目标文件
obj-m := target.o target-objs := src1.o src2.o src3.o 版权声明:本文博客原创文章.博客,未经同意,不得转载.
- 快速构建Windows 8风格应用3-打包发布应用
原文:快速构建Windows 8风格应用3-打包发布应用 本篇博文主要介绍如何打包应用程序,成功后如何部署应用程序,最后介绍如何发布应用程序到应用商店中. 如何打包Windows 8风格应用程序呢? ...