NUnit详细使用用法(补充)--在.NET中如何利用NUnit测试Private和Protected方法
(上一篇:http://arlen.cnblogs.com/archive/2006/03/21/354747.html)
在.NET中如何测试Private和Protected方法?
                     How to Test Private and Protected methods in .NET, TimStall,
介绍
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)
protected string MyProtectedMethod(string strInput, int i32Value) 2
 {
{3
 return this.Name + ": " + strInput + ", " +
    return this.Name + ": " + strInput + ", " + 4
 i32Value.ToString();
     i32Value.ToString();5
 }
}6

Pragmatic Unit Testing in C# with NUnit一书解释了一个解决方案:创建一个继承自MyObject类的类MyObjectTester,然后创建一个public方法TestMyProtectedMethod,这个方法包装了那个protected方法.例如,
1 public new string TestMyProtectedMethod(string strInput, int i32Value)
public new string TestMyProtectedMethod(string strInput, int i32Value) 
2 {
{
3 return base.MyProtectedMethod(strInput,
    return base.MyProtectedMethod(strInput, 
4 i32Value);
     i32Value);
5 }
}
6 
方法很简单,也遵循所有原则:
| 原则 | 实现 | 
| 透明 | 通过使用继承,并把 | 
| 范围 | 在本方法中没有任何东西依赖Debug-only技术. | 
| 简单 | 尽管这个方法需要一新的类,以及每个protected 方法的额外public包装方法,但是它是面向对象的,并且使类型安全的. | 
测试Private方法
测试private方法需要多做有些工作,但是我们仍可以使用System.Reflection来实现.你可以使用反射来动态访问一种类型的方法, 包括实例和静态private方法的方法.注意访问private方法需要ReflectionPermission,但是对于运行在开发机器或者构建服务器上的单元测试来说,这不是问题.
  假设我们想测试来自ClassLibrary1.MyObject的private方法MyPrivateMethod:
1 private string MyPrivateMethod(string strInput, DateTime dt, double
private string MyPrivateMethod(string strInput, DateTime dt, double 
2 dbl)
 dbl) 
3 {
{
4 return this.Name + ": " + strInput + ", " +
    return this.Name + ": " + strInput + ", " + 
5 dt.ToString() + ", " + dbl.ToString();
     dt.ToString() + ", " + dbl.ToString();
6 }
}
7 
  一个解决方法是创建一个UnitTestUtilities工程,这个工程有一个helper类通过反射来调用测试方法.例如,供下载的解决方案在UnitTestUtilities.Helper中有如下方法:
 public static object RunStaticMethod(System.Type t, string strMethod,
public static object RunStaticMethod(System.Type t, string strMethod, 
 2 object [] aobjParams)
 object [] aobjParams) 
 3 {
{
 4 BindingFlags eFlags =
    BindingFlags eFlags = 
 5 BindingFlags.Static | BindingFlags.Public |
     BindingFlags.Static | BindingFlags.Public | 
 6 BindingFlags.NonPublic;
     BindingFlags.NonPublic;
 7 return RunMethod(t, strMethod,
    return RunMethod(t, strMethod, 
 8 null, aobjParams, eFlags);
     null, aobjParams, eFlags);
 9 } //end of method
} //end of method
10 public static object RunInstanceMethod(System.Type t, string strMethod,
public static object RunInstanceMethod(System.Type t, string strMethod, 
11 object objInstance, object [] aobjParams)
 object objInstance, object [] aobjParams) 
12 {
{
13 BindingFlags eFlags = BindingFlags.Instance | BindingFlags.Public |
    BindingFlags eFlags = BindingFlags.Instance | BindingFlags.Public | 
14 BindingFlags.NonPublic;
     BindingFlags.NonPublic;
15 return RunMethod(t, strMethod,
    return RunMethod(t, strMethod, 
16 objInstance, aobjParams, eFlags);
     objInstance, aobjParams, eFlags);
17 } //end of method
} //end of method
18 private static object RunMethod(System.Type t, string
private static object RunMethod(System.Type t, string 
19 strMethod, object objInstance, object [] aobjParams, BindingFlags eFlags)
 strMethod, object objInstance, object [] aobjParams, BindingFlags eFlags) 
20 {
{
21 MethodInfo m;
    MethodInfo m;
22 try
    try 
23 {
    {
24 m = t.GetMethod(strMethod, eFlags);
        m = t.GetMethod(strMethod, eFlags);
25 if (m == null)
        if (m == null)
26 {
        {
27 throw new ArgumentException("There is no method '" +
             throw new ArgumentException("There is no method '" + 
28 strMethod + "' for type '" + t.ToString() + "'.");
              strMethod + "' for type '" + t.ToString() + "'.");
29 }
        }
30 
                                
31 object objRet = m.Invoke(objInstance, aobjParams);
        object objRet = m.Invoke(objInstance, aobjParams);
32 return objRet;
        return objRet;
33 }
    }
34 catch
    catch
35 {
    {
36 throw;
        throw;
37 }
    }
38 } //end of method
} //end of method
39 
Private方法RunMethod 带有一些必要的参数,这些参数是反射需要用来调用一个方法,然后返回值的.它有两个public方法RunStaticMethod 和 RunInstanceMethod来为静态和实例方法分别包装这.
     看看RunMethod,它首先得到类型的MethodInfo.因为我们期望它仅为已经存在的方法调用.一个空的方法触发一个Exception. 一旦我们有MethodInfo,我们就可以调用实例化对象提供的方法(static 方法为null)以及参数数组.
我们可以在一个NUnit测试中像下面使用这个Utility:
 1 [Test] public void TestPrivateInstanceMethod()
[Test] public void TestPrivateInstanceMethod()
 2 {
{
 3 string strExpected = "MyName: Hello, 5/24/2004
    string strExpected = "MyName: Hello, 5/24/2004 
 4 12:00:00 AM, 2.1";
     12:00:00 AM, 2.1";
 5 
     
 6 ClassLibrary1.MyObject objInstance
    ClassLibrary1.MyObject objInstance 
 7 = new MyObject("MyName");
     = new MyObject("MyName");
 8 
    
 9 object obj =
    object obj = 
10 UnitTestUtilities.Helper.RunInstanceMethod(
     UnitTestUtilities.Helper.RunInstanceMethod(
11 typeof(ClassLibrary1.MyObject), "MyPrivateMethod",
     typeof(ClassLibrary1.MyObject), "MyPrivateMethod",
12 objInstance, new object[3] {"Hello",
     objInstance, new object[3] {"Hello", 
13 new DateTime(2004,05,24), 2.1});
     new DateTime(2004,05,24), 2.1});
14 
    
15 string strActual = Convert.ToString(obj);
    string strActual = Convert.ToString(obj);
16 
    
17 Assert.AreEqual(strExpected,strActual);
    Assert.AreEqual(strExpected,strActual);
18 }
}
19 
| 原则 | 实现 | 
| 透明 | 我们仅创建的多余代码; | 
| 范围 | 在本方法中没有任何东西依赖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类.这些技术都能帮助你改进测试覆盖面. 原文:How to Test Private and Protected methods in .NET, TimStall,
本文引自:
http://confach.cnblogs.com/articles/225502.html
 
                    
                

 
     
                
            
         
 浙公网安备 33010602011771号
浙公网安备 33010602011771号