.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 ...
随机推荐
- 模态窗口原理及注意事项--http://www.alisdn.com/wordpress/?p=53
前言 在开发Windows引用程序的时候,在一些需要用户确认,或者提示用户注意的场合,经常使用模态对话框,或者叫模态窗口.在绝大多数情况下,模态窗口给开发人员带来了极大的便利,并且在某些应用上有不可替 ...
- pro_select_roleinfo_p3
DELIMITER | drop procedure if exists pro_select_roleinfo_p3; CREATE PROCEDURE pro_select_roleinfo_p3 ...
- 关于增强for循环和普通for循环是否需要判断为null的情况
1.增强for循环: public static void main(String[] args) { List<Object> list = null; for(Object s : l ...
- CMDB初步了解
本节内容 浅谈ITIL CMDB介绍 Django自定义用户认证 Restful 规范 资产管理功能开发 浅谈ITIL TIL即IT基础架构库(Information Technology Infra ...
- Pycharm选中代码无法Backspace直接删除
现象 如图,选中代码后,按习惯来说,直接Backspace就可以删除被选中代码. 但选中后再按“Backspace”,只会改变(扩选)选中范围. 解决 点击“工具栏”里的“Tool”,去掉勾选的Vim ...
- OVN实战---《An Introduction to OVN Routing》翻译
Overview 在前面一篇文章的基础上,现在我将通过OVN创建一个基础的三层网络.创建的最终结果将是一对logical switches通过一个logical router相连.另外,该路由器会通过 ...
- Linux网络调试工具资料链接
Dropbox: https://huoding.com/2016/12/15/574 Tcpdump: http://roclinux.cn/?p=2474
- 我的Android进阶之旅------>解决DownloadManager报错java.lang.SecurityException: Invalid value for visibility: 2
1.问题描述 今天使用Android系统的DownloadManager进行下载操作时,爆了如下所示的错误: java.lang.RuntimeException: Unable to start s ...
- 用仿ActionScript的语法来编写html5——第六篇,TextField与输入框
一,对比1,html5中首先看看在html5的canvas中的文字显示 var canvas = document.getElementById("myCanvas"); var ...
- win7开启特定端口
win7开启特定端口 在xp系统的时代,修改防火墙很方便,很简单.windows7或许是做得过于复杂了.当然所谓安全性也是相当于其他之前版本的系统更高了.为什么要打开端口,肯定是在win ...