共享自己的一个单元测试帮助类-UnitTestHelper

    单元测试在开发过程中的重要性不言而喻,很多时候仅使用Assert.*来进行断言检查仍然是不够的,Assert只知道对与错,适合于自动化测试,对程序的调试却帮助有限。试着想像这么一种情形:我们写了一个数据库访问类MyInfoDA,针对数据库进行CURD操作,其中有一个方法GetInfoById返回一个实体MyInfo的实例,我们可以用Assert.IsNotNull简单的检查是否有实例返回,却无法了解MyInfo的内部结构是怎样的。最简单的办法或许就是Console.WriteLine挨个将MyInfo的内容Print出来,或者就是直接在IDE调试器里面查看对象内容。而我很厌烦这么做,于是就写了这么一个帮助类,感觉还是蛮有用途的,因此公布出来,供大家参考。

  1 None.gif using  System.Diagnostics;
  2 None.gif using  System.Reflection;
  3 None.gif using  System.Text;
  4 None.gif
  5 None.gif namespace  NHTSS.UnitTest
  6 ExpandedBlockStart.gifContractedBlock.gif dot.gif {
  7ExpandedSubBlockStart.gifContractedSubBlock.gif    /**//// <summary>
  8InBlock.gif    /// 单元测试的帮助类。
  9ExpandedSubBlockEnd.gif    /// </summary>

 10InBlock.gif    public sealed class UnitTestHelper
 11ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
 12InBlock.gif        private UnitTestHelper()
 13ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
 14ExpandedSubBlockEnd.gif        }

 15InBlock.gif
 16ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
 17InBlock.gif        /// 格式化输出一个对象的所有属性值。
 18InBlock.gif        /// </summary>
 19InBlock.gif        /// <param name="obj">格式化输出一个对象的所有属性值。</param>
 20ExpandedSubBlockEnd.gif        /// <returns>对象名属性值。</returns>

 21InBlock.gif        public static string ObjectProperty2String(object obj)
 22ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
 23ExpandedSubBlockStart.gifContractedSubBlock.gif            return ObjectProperty2String(obj, new Type[] dot.gif{});
 24ExpandedSubBlockEnd.gif        }

 25InBlock.gif
 26ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
 27InBlock.gif        /// 格式化输出一个对象的所有属性值。
 28InBlock.gif        /// </summary>
 29InBlock.gif        /// <param name="obj">格式化输出一个对象的所有属性值。</param>
 30InBlock.gif        /// <param name="exposeItems">特别需要暴露的类型。</param>
 31InBlock.gif        /// <returns>对象名属性值。</returns>
 32ExpandedSubBlockEnd.gif        /// <remarks>没有跨层次概念,如果需要,应将链结构的类型都放置在exposeItems中。</remarks>

 33InBlock.gif        public static string ObjectProperty2String(object obj, Type[] exposeItems)
 34ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
 35InBlock.gif            int tmp = 0;
 36InBlock.gif            return ObjectProperty2String(obj, exposeItems, ref tmp);
 37ExpandedSubBlockEnd.gif        }

 38InBlock.gif
 39InBlock.gif        private static string ObjectProperty2String(object obj, Type[] exposeItems, ref int layer)
 40ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
 41InBlock.gif            layer++;
 42InBlock.gif
 43InBlock.gif            StringBuilder sb = new StringBuilder();
 44InBlock.gif            if (obj != null)
 45ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
 46InBlock.gif                Type objType = obj.GetType();
 47InBlock.gif                sb.Append(objType.Name).Append(" ->");
 48InBlock.gif                MemberInfo[] members = objType.GetMembers();
 49InBlock.gif                if ((objType.IsValueType) && (!objType.IsPrimitive))
 50ExpandedSubBlockStart.gifContractedSubBlock.gif                dot.gif{
 51InBlock.gif                    // value type use Field.
 52InBlock.gif                    foreach (MemberInfo m in members)
 53ExpandedSubBlockStart.gifContractedSubBlock.gif                    dot.gif{
 54InBlock.gif                        if (m.MemberType == MemberTypes.Field)
 55ExpandedSubBlockStart.gifContractedSubBlock.gif                        dot.gif{
 56InBlock.gif                            InvokePropertyOrField(sb, obj, objType, exposeItems, ref layer, m, BindingFlags.Default | BindingFlags.GetField);
 57ExpandedSubBlockEnd.gif                        }

 58ExpandedSubBlockEnd.gif                    }

 59ExpandedSubBlockEnd.gif                }

 60InBlock.gif                else
 61ExpandedSubBlockStart.gifContractedSubBlock.gif                dot.gif{
 62InBlock.gif                    // reference type use Property.
 63InBlock.gif                    foreach (MemberInfo m in members)
 64ExpandedSubBlockStart.gifContractedSubBlock.gif                    dot.gif{
 65InBlock.gif                        if (m.MemberType == MemberTypes.Property)
 66ExpandedSubBlockStart.gifContractedSubBlock.gif                        dot.gif{
 67InBlock.gif                            InvokePropertyOrField(sb, obj, objType, exposeItems, ref layer, m, BindingFlags.Default | BindingFlags.GetProperty);
 68ExpandedSubBlockEnd.gif                        }

 69ExpandedSubBlockEnd.gif                    }

 70ExpandedSubBlockEnd.gif                }

 71ExpandedSubBlockEnd.gif            }

 72InBlock.gif
 73InBlock.gif            layer--;
 74InBlock.gif
 75InBlock.gif            return sb.ToString();
 76ExpandedSubBlockEnd.gif        }

 77InBlock.gif
 78InBlock.gif        private static void InvokePropertyOrField(StringBuilder sb, object obj, Type objType, Type[] exposeItems, ref int layer, MemberInfo m, BindingFlags flags)
 79ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
 80InBlock.gif            object val = null;
 81InBlock.gif            if (m.Name == "Item")
 82ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
 83InBlock.gif                try
 84ExpandedSubBlockStart.gifContractedSubBlock.gif                dot.gif{
 85InBlock.gif                    if (m.DeclaringType.Equals(m.ReflectedType))
 86ExpandedSubBlockStart.gifContractedSubBlock.gif                    dot.gif{
 87InBlock.gif                        // assume it is a index indicator [Array].
 88ExpandedSubBlockStart.gifContractedSubBlock.gif                        int count = (int) objType.InvokeMember("Count", BindingFlags.Default | BindingFlags.GetProperty, null, obj, new object[] dot.gif{});
 89InBlock.gif                        for (int k = 0; k < count; k++)
 90ExpandedSubBlockStart.gifContractedSubBlock.gif                        dot.gif{
 91ExpandedSubBlockStart.gifContractedSubBlock.gif                            val = objType.InvokeMember("get_Item", BindingFlags.Default | BindingFlags.InvokeMethod, null, obj, new object[] dot.gif{k});
 92InBlock.gif                            sb.Append("\n").Append("\t".PadRight(layer, '\t')).Append(m.Name).Append("[").Append(k).Append("]=<").Append(val).Append(">; ");
 93InBlock.gif                            ExposeDetail(sb, val, exposeItems, ref layer);
 94ExpandedSubBlockEnd.gif                        }

 95ExpandedSubBlockEnd.gif                    }

 96ExpandedSubBlockEnd.gif                }

 97InBlock.gif                catch (Exception ex)
 98ExpandedSubBlockStart.gifContractedSubBlock.gif                dot.gif{
 99InBlock.gif                    // use compiler swtich /d:TRACE
100InBlock.gif                    //Trace.WriteLine(ex.Message);
101InBlock.gif                    Console.WriteLine("<<ERROR>> " + ex.Message);
102ExpandedSubBlockEnd.gif                }

103ExpandedSubBlockEnd.gif            }

104InBlock.gif            else
105ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
106ExpandedSubBlockStart.gifContractedSubBlock.gif                val = objType.InvokeMember(m.Name, flags, null, obj, new object[] dot.gif{});
107InBlock.gif                sb.Append("\n").Append("\t".PadRight(layer, '\t')).Append(m.Name).Append("=<").Append(val).Append(">; ");
108InBlock.gif                ExposeDetail(sb, val, exposeItems, ref layer);
109ExpandedSubBlockEnd.gif            }

110ExpandedSubBlockEnd.gif        }

111InBlock.gif
112InBlock.gif        // recursion function.
113InBlock.gif        private static void ExposeDetail(StringBuilder sb, object val, Type[] exposeItems, ref int layer)
114ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
115InBlock.gif            if (sb == null || val == null || exposeItems == null)
116ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
117InBlock.gif                return;
118ExpandedSubBlockEnd.gif            }

119InBlock.gif            if (!ContainType(val.GetType(), exposeItems))
120ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
121InBlock.gif                return;
122ExpandedSubBlockEnd.gif            }

123InBlock.gif            string str = ObjectProperty2String(val, exposeItems, ref layer);
124InBlock.gif            sb.Append("\r\n").Append("\t".PadRight(layer, '\t')).Append(str);
125ExpandedSubBlockEnd.gif        }

126InBlock.gif
127InBlock.gif        // estimate Type.
128InBlock.gif        private static bool ContainType(Type valType, Type[] exposeItems)
129ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
130InBlock.gif            if (exposeItems == null)
131ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
132InBlock.gif                return false;
133ExpandedSubBlockEnd.gif            }

134InBlock.gif            int count = exposeItems.Length;
135InBlock.gif            for (int k = 0; k < count; k++)
136ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
137InBlock.gif                if (valType == exposeItems[k])
138ExpandedSubBlockStart.gifContractedSubBlock.gif                dot.gif{
139InBlock.gif                    return true;
140ExpandedSubBlockEnd.gif                }

141ExpandedSubBlockEnd.gif            }

142InBlock.gif            return false;
143ExpandedSubBlockEnd.gif        }

144ExpandedSubBlockEnd.gif    }

145ExpandedBlockEnd.gif}

146 None.gif

    说明一下,其实思路很简单的,就是通过GetType()获得该对象的元数据,然后通过反射输出该对象的值域(Field和Property)。对集合对象,或者特别想要了解的属性或字段通过递归方式处理。
   UnitTestHelper 提供了两个静态重载方法ObjectProperty2String,也比较好理解。下面给出两个简单的例子:

 1 ExpandedBlockStart.gif ContractedBlock.gif /**/ /// <summary>
 2InBlock.gif/// 测试简单的数据实体。
 3ExpandedBlockEnd.gif/// </summary>

 4 None.gif [TestFixture]
 5 None.gif public   class  TestBaseInfo
 6 ExpandedBlockStart.gifContractedBlock.gif dot.gif {
 7InBlock.gif  [Test]
 8InBlock.gif  public void TestBuildInfoMock()
 9ExpandedSubBlockStart.gifContractedSubBlock.gif  dot.gif{
10InBlock.gif    //InfoMock 是个简单的测试实体对象。
11InBlock.gif    InfoMock mock = new InfoMock();
12InBlock.gif    mock.Name = "Mock";
13InBlock.gif    mock.Address = "Paradise";
14InBlock.gif    mock.Age = "No.1";
15InBlock.gif    mock.Company = "Chiron";
16InBlock.gif    mock.Credit = "IBM + Google + Microsoft";
17InBlock.gif    mock.InfoId = 0;
18InBlock.gif    Console.Out.WriteLine(UnitTestHelper.ObjectProperty2String(mock));
19ExpandedSubBlockEnd.gif  }

20ExpandedBlockEnd.gif}

21 None.gif
22 ExpandedBlockStart.gifContractedBlock.gif /**/ /// <summary>
23InBlock.gif/// 测试ParametersDA。
24ExpandedBlockEnd.gif/// </summary>

25 None.gif [TestFixture]
26 None.gif public   class  TestParametersDA
27 ExpandedBlockStart.gifContractedBlock.gif dot.gif {
28InBlock.gif  [Test]
29InBlock.gif  public void TestGetAllParameters()
30ExpandedSubBlockStart.gifContractedSubBlock.gif  dot.gif{
31InBlock.gif    // ParameterCollection是一个数据实体集合。
32InBlock.gif    ParameterCollection coll = ParametersDA.Instance.GetAllParams();
33ExpandedSubBlockStart.gifContractedSubBlock.gif    Console.Out.WriteLine(UnitTestHelper.ObjectProperty2String(coll, new Type[]dot.giftypeof(ParameterInfo) }));
34ExpandedSubBlockEnd.gif  }

35ExpandedBlockEnd.gif}

P.S. 这是本人在博客园的第一篇正式技术文章,严格说来也没啥技术,只是一点实用技巧,以前很少动手写东西,肤浅不足之处,欢迎拍砖。

转载于:https://www.cnblogs.com/bengxia/archive/2006/03/20/354455.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值