首页 | 编程语言 | 网站建设 | 游戏天堂 | 冲浪宝典 | 网络安全 | 操作系统 | 软件时空 | 硬件指南 | 病毒相关 | IT 认证
软讯网络 > 网站建设 > ASP.NET > .NET环境下类测试工具的开发与实现
【标  题】:.NET环境下类测试工具的开发与实现
【关键字】:NET,NE,.NET,.NET,NET
【来  源】:网络

.NET环境下类测试工具的开发与实现

.NET环境下类测试工具的开发与实现
 
徐静

摘要:.NET平台为应用系统提供了良好的开发环境和技术支持,通过运用.Net框架提供的反射命名空间等技术,本文详细介绍了.NET环境下类测试工具的设计、开发全过程,该工具为测试人员提供了一个方便友好的测试环境,对于测试工作具有一定的参考价值。

引言

测试工具是软件测试中必不可少的辅助手段,在.Net环境下微软推出了适用于 .NET Framework 领域的类测试工具nUnit,利用nUnit可以创建和执行自动的单元测试,但是nUnit只是一个单元测试框架,它需要测试人员经过一个学习过程,然后根据nUnit规范编写测试用例代码,才能最终有效地使用它。虽然对于那些公共接口不经常更改的类,这种自动化测试是有效的,然而对于那些公共接口更改很多以及包含大多数用户接口代码的类来说,这种测试的效率就十分低下了。此外,测试人员从熟悉nUnit到对给定类编写测试案例代码的过程中所耗费的工作量远远超出其手工地对该类进行一次测试所耗费的工作量,给测试工作造成一定困难。针对这些问题,本文拟开发一个通用的类测试工具,它类似于被测模块的驱动模块,在单元测试中提供方便友好的方式接受测试数据,把相关的数据转换传送给被测模块,动态调用被测模块,并输出相应的结果。


一、需求与用户界面

.NET框架是微软推出的用于构建、配置、运行Web服务和应用程序的多语言环境,在典型的基于.Net平台的三层应用程序中,类作为业务层的实现主体,其测试工作是软件产品开发中很重要的一个环节,也是确保软件质量的基础和关键。针对类进行单元测试需要良好的测试平台,从功能上看,类测试平台需要能够从类创建对象,让对象接收消息,并能对所接收的消息进行显示、捕捉和分析。简言之,就是对类的每个 public 方法的输入输出进行测试,检验对于给定的输入,这个类的输出是否正确。基于以上考虑,类测试程序需要完成以下任务:

1、动态列出类所包含的 public方法,并根据用户的选择动态列出相应方法的参数及其参数类型。

2、提供友好的界面供用户输入参数值,并将参数值转换成对应的参数类型传入调用方法。

3、动态调用类方法,并输出方法返回值及相应的错误信息描述。

4、输出返回的参数值,供测试人员分析。

根据以上对类测试工具的需求分析,下面首先进行其界面设计。类测试主要是对类方法的测试,类方法涉及的参数类型复杂多样,包括数组型参数、结构型参数、嵌套结构参数及嵌套数组参数等多种复杂结构。为了清晰的描述各参数,同时也便于测试人员操作,本测试工具软件在界面部分采用树形结构动态显示类所包含的方法及参数,其界面设计如图1。


图1 测试工具界面

界面操作过程说明如下:

1、测试人员进入测试界面后,首先输入待测试的程序集名称,单击“加载”按钮,动态加载程序集包含的类,并将类名称添加到下拉列表中供测试人员选择。

2、测试人员作出选择后,方法列表将相应类所包含的Public方法罗列出来,一旦选定待测试的类方法,则参数列表以树形结构列出该方法的输入参数类型及参数名。其中,对于结构型参数,其各数据域分别对应到当前节点的子节点;对于数组型参数,则要求测试者输入数组长度,然后在当前节点下动态增加并展示对应于数组元素的子节点。

3、测试人员选择某一参数后,将在右边栏目中列出该参数的类型及详细信息,并提供文本框供测试者输入参数值,此时测试工具程序会对输入值进行类型检查并根据情况给予友好提示。

4、所有参数赋值完毕后,单击“调用”按钮,动态调用方法,并将返回结果,错误描述及输出参数显示输出。


二、问题的提出与实现

作为类测试工具软件,为了实现以上需求,该程序有三个难点:1.如何实现动态获取类信息及动态调用类方法;2.如何实现界面的动态展示;3.如何实现结构参数、数组参数及嵌套参数等复杂参数的赋值传入及输出。针对第1个问题,在程序开发过程中通过使用.Net框架的反射技术加以解决。反射提供了封装程序集、模块和类型的对象,使用反射可以动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性;第2个问题通过引入并灵活运用Treeview控件加以实现,由于本测试工具是具体针对一个分布式多层Web应用系统的类测试需求开发的,因此在界面部分采用Web Treeview控件,利用该控件可以方便地开发树形图,并按照树形结构组织数据;第3个问题则是在前两个问题的解决基础上通过采取递归调用的方法予以解决,下面具体阐述其实现原理及方法。


2.1 动态获取类信息及动态方法调用

利用.NET框架反射(System.Reflection)命名空间中的类以及System.Type类,可以加载程序集和获取在其中定义的类型信息,实现方法的动态调用。反射提供了由语言编译器(如Microsoft Visual Basic .NET)用来实现隐式晚期绑定的基础结构。System.Type类对于反射起着核心的作用,它是System.Reflection功能的根,也是访问元数据的主要方式。当反射请求加载的类型时,公共语言运行库将为它创建一个Type对象,使用Type对象的方法、字段、属性和嵌套类来查找有关该类型的所有信息。下面我们依据前面的需求分析说明代码的具体实现:代码段功能:动态加载并检测程序集,将其包含的类名称添加到列表中。

Dim ass As [Assembly] ‘定义程序集对象

ass = [Assembly].Load(Trim(assName.Text)) ‘动态加载用户指定的程序集

Dim ClassType As Type ‘定义Type对象

ClassList.Items.Add("所有待测试类")

For Each ClassType In ass.GetExportedTypes ‘逐一检测程序集中的Type对象

If ClassType.IsClass Then ‘判断是否是类对象

ClassList.Items.Add(ClassType.Name) ‘将类名称添加到列表中

End If

Next

……

说明:测试工具自动检测测试类包含的全部公共方法,获取方法的详细信息

ClassType = GetType(TypeName) ‘获取指定类的Type对象

Dim tArrayMethodInfo As MethodInfo() ‘定义MethodInfo数组以获取类方法的信息。

说明:MethodInfo类用以发现方法的特性并提供对方法元数据的访问。

tArrayMethodInfo = ClassType.GetMethods()‘从类的Type对象获取类所包含的所有方法

……

Dim myMethodInfo As MethodInfo

myMethodInfo = CType(tArrayMethodInfo(j), MethodInfo) ‘获取测试方法的MethodInfo对象

Dim MethodParam As ParameterInfo() ‘定义ParameterInfo数组以获取方法的参数信息

MethodParam = myMethodInfo.GetParameters ‘获取测试方法的所有参数

……

代码段功能:创建类实例,实现对测试方法的动态调用

Dim args() As Object ‘定义Object数组存储测试方法的参数值

Dim MethodObj As MethodInfo

Dim obj As Object

SetArgs(args, ClassType, MethodObj, MethodParam)‘设置参数值过程,参见2.3节

obj = Activator.CreateInstance(ClassType) ‘创建测试类的实例(说明:Activator类用以在本地创建对象类型,通过调用其CreateInstance方法创建类实例)。

retInt = MethodObj.Invoke(obj, args)‘通过Invoke方法调用由MethodInfo实例反射的方法。


2.2 Web界面的树形结构管理及实现

由于在测试过程中需要根据用户的选择动态展示类方法及其参数,对于数组,嵌套结构等复杂参数,还需要根据用户输入的长度实现数组的动态增减,因此在测试界面中主要采用树形结构管理并展示方法和参数。考虑到参数处理的复杂性及代表性,下面重点讨论“参数树”的设计实现。

顾名思义“参数树”是指用以展示方法参数的树结构,这里我们将参数统分为简单参数和复杂参数。简单参数是指诸如String、Int的基本类型参数,复杂参数是指数组、结构等复杂类型参数。简单参数对应于树结构的叶子节点,复杂参数对应于树结构的子节点,这些子节点下又嵌套包含子节点和叶子节点。为了便于处理,在具体实现中我们定义了"Normal"、"Enum"、"Struc"、"Arr"和"StrucArr"几种划分类型用以描述节点。当用户从方法列表中选取好方法后,即需要根据动态获取的参数信息建立相应的树结点。具体实现代码如下:

代码段功能:建立树结点

Private Function Node(ByVal sID As String, ByVal [text] As String, ByVal type As String) As TreeNode

Dim i As Integer

Dim sNodeType As String

Dim tNode As New TreeNode

Dim cssCol As New CssCollection

‘设置节点的属性值,包括节点ID、文本、节点的划分类型及节点样式等信息。

tNode.ID = sID

tNode.Text = [text]

tNode.Type = type

cssCol.CssText = "background:white;color:red;font-name:Arial;font-weight:bold-italic"

tNode.SelectedStyle = cssCol

‘对于结构型参数,动态获取结构成员信息并建立对应于结构成员的子节点。

If type = "Struc" Then

Dim f As FieldInfo() = tp.GetFields

For i = 0 To f.Length - 1

sNodeType = f(i).FieldType.Name

tNode.Nodes.Add(Node(I, f(i).Name, sNodeType))

Next

End If

tNode.Expanded = True

Return tNode

End Function


2.3 参数处理

参数处理比较复杂,从值的传递方式划分,参数可划分为值传递型及引用传递型;从参数类型划分,参数可划分为基本类型参数,枚举型参数、结构型参数及数组参数。其中,数组参数又分为基本类型数组参数和结构数组参数。结构型参数在其结构中又可包括基本类型数组和结构数组。为了实现复杂参数的传值,我们采用递归调用的方法分别处理数组及结构参数。具体代码及说明如下:

代码段功能:通过“参数树”的节点信息获取参数值字符串并将其转换为相应类型的参数值。

Private Sub SetArgs(ByRef args() As Object, ByRef ClassType As Type, ByRef MethodObj As MethodInfo, ByRef mPara() As ParameterInfo)

Dim i, j, k As Integer

Dim sNode, Str, tStr As String

Dim tp As Type


mPara = MethodObj.GetParameters ‘获取方法的参数信息

i = mPara.Length - 1

If i < 0 Then ‘如果选定的方法没有参数,则args置为nothing.

args = Nothing

Else

ReDim args(i)

For j = 0 To i

sNode = TreeParams.Nodes(0).Nodes(j).Type ‘获取参数树的节点

Select Case sNode

‘对于基本类型参数和枚举型参数直接将节点数据信息转换成对应的参数类型值并赋值给参数数组。

Case "Normal", "Enum"

args(j) = TypeConvert(TreeParams.Nodes(0).Nodes(j).NodeData, mPara(j).ParameterType.Name)

‘对于结构型参数调用SetStrucArgs方法获取其参数对象并赋值给参数数组。

Case "Struc"

Dim subArgs As Object

SetStrucArgs(subArgs, TreeParams.Nodes(0).Nodes(j))

args(j) = subArgs

‘对于数组型参数调用SetArrArgs方法获取其参数对象并赋值给参数数组。

Case "Arr","StrucArr"

Dim subArgs As Array

SetArrArgs(subArgs, TreeParams.Nodes(0).Nodes(j))

args(j) = subArgs

End Select

Next

End If

End Sub


代码段功能:通过“参数树”的节点信息获取参数值字符串并转换为相应类型的数组参数值。

Private Sub SetArrArgs(ByRef SubArgs As Array, ByRef tNode As TreeNode)

Dim Str, tStr As String

Dim tp As Type

Dim ArrLen, i As Integer


If IsNumeric(tNode.NodeData) Then

ArrLen = CInt(tNode.NodeData) ‘获取数组长度

Str = tNode.ID ‘获取表示参数类型的字符串

tStr = RecType(Str, tp) ‘根据字符串得到参数的划分类型及其对应的Type对象

SubArgs = Array.CreateInstance(tp, ArrLen) ‘根据获取的信息创建相应长度的数组实例


Select Case tStr ‘根据不同的划分类型进行不同的参数赋值处理

Case "Arr" ‘对于简单数组直接将界面获取的值信息转换成对应类型的值

For i = 0 To ArrLen - 1

SubArgs(i) = TypeConvert(tNode.Nodes(i).NodeData,Str)

Next

‘对于结构型数组依次调用SetStrucArgs方法为每一位数组成员的结构变量赋值。

Case "StrucArr"

For i = 0 To ArrLen - 1

Dim SubStrucArgs As Object

SetStrucArgs(SubStrucArgs, tNode.Nodes(i))

SubArgs.SetValue(SubStrucArgs, i)

Next

End Select

Else

SubArgs = Nothing ‘如果数组长度为0,则参数对象置为nothing。

End If

End Sub


代码段功能:通过“参数树”的节点信息获取参数值字符串并转换为相应类型的结构参数值。

Private Sub SetStrucArgs(ByRef StrucArgs As Object, ByRef tNode As TreeNode)

Dim k As Integer

Dim sNode As String

Dim Str, tStr As String

Dim tp As Type


Str = tNode.ID ‘获取表示参数类型的字符串

tStr = RecType(Str, tp) ‘根据字符串得到参数的划分类型及其对应的Type对象

StrucArgs = Activator.CreateInstance(tp) ‘创建类实例


Dim f As FieldInfo() = tp.GetFields ‘获取结构成员信息

For k = 0 To f.Length - 1

Select Case tStr ‘根据不同的划分类型进行不同的参数赋值处理

‘对于基本类型成员直接将界面获取的值信息转换成对应类型的值

Case "Normal","Enum"

StrucSetVal(StrucArgs, f(k).Name,tNode.Nodes(k).NodeData)

‘对于数组类型(包括结构数组)成员调用SetArrArgs方法完成结构成员的赋值。

Case "Arr","StrucArr"

Dim subArrArgs As Object

SetArrArgs(subArrArgs, tNode.Nodes(k))

StrucSetVal(StrucArgs, f(k).Name, subArrArgs)

‘对于结构型成员递归调用SetStrucArgs方法完成其赋值。

Case "Struc"

Dim subStrucArgs As Object

SetStrucArgs(subStrucArgs, tNode.Nodes(k))

StrucSetVal(StrucArgs, f(k).Name, subStrucArgs)

End Select

Next

End Sub

上述结构参数的赋值过程中运用了递归调用的处理方法,递归终止于基本类型成员的直接转换赋值。

至此,本文已详细阐述了测试工具开发中遇到的问题及解决方法,灵活运用这些方法及技术,对于.NET环境下的测试工作有一定的帮助及实际参考价值。

Micorsoft.Net中数字签名技术:【上一篇】
介绍.NET中的委派(Delegates)之一:【下一篇】
【相关文章】
没有相关文章
【随机文章】
  • suse10神速运行攻略(更新为六条)
  • 在ASP中使用均速分页法提高分页速度
  • sockd.conf - Dante server configuration zz
  • Emacs在Ubuntu的gnome环境无法使用fcitx的解决办法
  • Windows消息大全
  • EurekaLog 4.2.3 Enterprise (IDE辅助工具)
  • Oracle 9.2.0.1 升级至Oracle 9.2.0.6
  • LispBox 我的救星阿
  • 开机就睡眠,这是怎么回事?
  • Flash和Java结合开发的利器_《Java for Flash动态网站开发手札》_部分章节连载(6)
  • 【相关评论】
    没有相关评论
    【发表评论】
    姓名:
    邮件:
    随机码*
    评论*
          
    |  首 页  |  版权声明  |  联系我们   |  网站地图  |
    CopyRight © 2004-2007 软讯网络 All Rigths Reserved.