MATLAB xUnit测试框架:架构注释
本文总结了MATLAB xUnit的关键类和设计选择,这是一个基于xUnit模式的MATLAB单元测试框架。
注:本文档中的测试图案和气味术语均取自xUnit测试模式:重构测试代码, Gerard Meszaros, Addison-Wesley, 2007年。
内容
TestComponent、TestCase和TestSuite
抽象的TestComponent类定义了一个具有描述(名称和位置)并且可以运行的对象。
一个TestCase对象是一个测试组件,它定义了一个单独的测试用例,该用例可以以通过或失败的结果运行。
一个TestSuite对象是一个测试组件,它包含其他测试组件的集合。注意测试套件的层次特性;它们既可以包含单独的测试用例对象,也可以包含其他测试套件。运行测试套件意味着调用运行方法在其集合中的每个测试组件上执行。
测试案例:四阶段测试
TestCase类提供了标准xUnit四阶段测试,使用新夹具,隐式安装,隐式拆卸.这些元素都可以在运行TestCase方法:
执行测试用例% test_case.run(monitor)调用TestCase对象的setUp() %方法,然后是test方法,然后是tearDown()方法。观察者是一个TestRunObserver对象。%观察者的testStarted()、% testFailure()、testError()和testFinished()方法在适当的时间被调用。monitor是一个% TestRunMonitor对象。通常它是一个TestRunLogger %的子类或者是一个CommandWindowTestRunDisplay的子类。% % test_case.run()自动使用% CommandWindowTestRunDisplay对象,以便将测试% suite执行信息打印到命令窗口。
如果nargin < 2 monitor = CommandWindowTestRunDisplay();结束
Did_pass = true;monitor.testComponentStarted(自我);
尝试self.setUp ();f = str2func(self.MethodName);
调用测试方法。f(自我);捕获failureException监视器。testCaseFailure(自我,failureException);Did_pass = false;结束
self.tearDown ();
捕获错误异常监视器。testCaseError(自我,errorException);Did_pass = false;结束
班长。testComponentFinished(自我,did_pass);结束
阶段1设置测试夹具通过隐式安装电话,self.setUp ().基类设置()方法什么也不做。
阶段2和3(在测试下运行系统并验证预期的结果)由测试方法处理,该方法由f(自我).
阶段4通过隐式拆卸电话,self.tearDown ().基类tearDown ()方法什么也不做。
类捕获和处理测试失败和测试错误异常run ()方法,因此测试方法不需要使用try-catch。这有助于编写简单、直线的测试方法代码。
注意:监控对象将在后面讨论。
测试用例发现
静态方法TestSuite.fromName基于m文件的名称构造一个测试套件。如果m文件定义了一个TestCase子类,然后fromName类的方法,并构造TestCase对象为名称以“[tT]est”开头的每个方法。如果m文件没有定义TestCase子类,然后fromName尝试构造一个简单的过程测试用例或一组基于子功能的测试用例。(请参阅下一节)。
静态方法TestSuite.fromPwd通过发现当前工作目录中的所有测试用例来构造一个测试套件。它发现了一切TestCase目录中的子类。此外,它从以“[tT]est”开头的目录中的所有过程性m文件构建测试套件。
的文件系统测试运行程序,runxunit,为自动执行测试用例发现提供了方便的语法。
FunctionHandleTestCase:用于过程世界
大多数MATLAB用户更习惯于过程式编程。MATLAB xUnit的一个重要设计目标是使几乎没有面向对象编程经验的MATLAB用户尽可能容易地创建和运行他们自己的测试。FunctionHandleTestCase提供了支持过程性测试函数所需的管道:万博1manbetx
私有财产SetupFcn,TestFcn,TeardownFcn是程序函数处理(类似于其他语言中的函数指针或函数引用)。
runTestCase ()是用于构造TestCase对象的测试方法。
管理测试fixture需要特别的考虑,因为过程式函数句柄不能访问对象实例数据来访问测试fixture。
的覆盖设置()方法查看函数句柄的输出数量SetupFcn.如果它有输出参数,则该参数保存在private中TestData财产,TestData然后传递给两者TestFcn而且TeardownFcn供他们使用。
编写过程性测试用例
程序测试用例可以用两种方式编写:
- 一个简单的m文件函数,它被视为一个单独的测试用例
- 包含多个子函数的m文件,每个子函数都被视为一个测试用例。
在任何一种情况下,如果测试用例没有错误地执行,就认为它通过了。
为每个文件编写一个测试用例并不理想;这将导致无数的小测试文件,或者长测试方法显示各种糟糕的测试气味(多种测试条件,灵活的测试,条件测试逻辑,希望测试,模糊测试所以我们需要一种方法在一个过程性的m文件中编写多个测试用例。自然的MATLAB方法是使用子函数。
然而,基于子功能的测试用例需要特别考虑。考虑下面的m文件结构:
=== File a.m. === function A…
函数B…
函数C…
函数D…
文件中的第一个函数,一个,与文件名称相同。当此函数外部的其他代码调用时一个,它是第一个函数被调用。功能B,C,D被称为子功能.通常情况下,这些子函数只能由一个.这是其他地方的代码能够调用的唯一方法B,C,或Dif函数一个向它们形成句柄,并将这些句柄传递到其作用域之外。通常,这将通过返回函数句柄作为输出参数来完成。
注意,在a.m.中函数作用域之外执行的代码不能形成to的函数句柄B,C,或D,或者甚至可以确定这些函数的存在。
这显然给测试发现带来了一个问题!
MATLAB xUnit解决方案是为基于子函数的测试建立以下约定。包含子函数测试的测试m文件中的第一个函数必须以这些行开始:
=== File a.m. === function testSuite = A testSuite = buildFunctionHandleTestSuite(localfunctions);...
buildFunctionHandleTestSuite (localfunctions)确定哪些子函数是测试函数,以及设置或拆卸函数。它形成了这些函数的句柄,并构造了一组FunctionHandleTestCase对象一个作为输出参数返回testSuite.
TestRunMonitor
抽象的TestRunMonitor类为“观察”测试套件正在执行的对象定义接口。的两个子类TestRunMonitor:
- TestRunLogger静默地记录测试套件事件,并捕获任何测试失败或测试错误的详细信息。
- CommandWindowTestRunDisplay将执行测试套件的进度打印到命令窗口。
TestRunMonitor被传递给run ()TestComponent对象的方法。的run ()方法调用监视器的适当通知方法。
下面是在MATLAB xUnit自己的测试套件上使用CommandWindowTestRunDisplay对象时的输出:
runxunit与92年开始测试运行测试用例 . .................... .................... .................... .................... ............以7.040秒的成绩通过。
文件系统测试运行程序
MATLAB xUnit提供了一个命令行文件系统测试运行程序被称为runxunit.当不带输入参数调用时,runxunit收集当前目录中的所有测试用例并运行它们,将结果汇总到命令窗口。runxunit还可以接受一个字符串参数,指定要运行哪个测试文件,以及可选的具体测试用例。
测试选择
中支持测试选择万博1manbetxrunxunit通过传入一个形式的字符串:
的位置:名称
或者是:
“位置”
这两个表单都由runxunit并通过TestSuite.fromName.
'Location'是包含测试用例的m文件的名称。'Name'是一个特定测试用例的名称。通常,测试用例的名称是对应的TestCase方法的名称。对于FunctionHandleTestCase对象,'Name'是子函数名。
断言方法
MATLAB xUnit提供了以下断言方法:
- 陈述结果断言(assertTrue,assertFalse)
- 平等的主张(assertEqual)
- 模糊等式断言(assertElementsAlmostEqual,assertVectorsAlmostEqual)
- 预期异常断言(assertExceptionRaised)
断言函数通过全局可访问的名称提供(例如,assertEqual).断言函数可以移动到xunit包,但是MATLAB用户还不习惯包和包名称-作用域语法。
'message'是断言函数的最后一个输入,是可选的。(关于……的讨论见下文断言轮盘赌.)
的预期异常断言,assertExceptionRaised通过从预计会出错的表达式中形成匿名函数句柄,然后将该函数句柄传递给assertExceptionRaised以及预期的异常标识符。例如:
F = @() sin(1,2,3);assertExceptionRaised (f, MATLAB: maxrhs)
通过使用这种机制,测试编写人员可以验证异常,而无需在测试代码中使用try-catch逻辑。
堆栈跟踪和“断言轮盘赌”
xUnit测试模式这就解释了气味断言轮盘赌这样:“很难判断同一测试方法中的几个断言中的哪一个导致了测试失败。
MATLAB xUnit缓解断言轮盘赌通过捕获整个堆栈跟踪,包括每个测试失败和测试错误的行号。(MATLAB MException对象,您可以通过抓子句,包含堆栈跟踪。)堆栈跟踪显示在命令窗口中,其中有可单击的链接,这些链接将相应的m文件加载到适当的行号编辑器中。
不过,堆栈跟踪可能相当长。此外,测试框架管道倾向于占用断言和用户测试代码之间的跟踪,从而使缺乏经验的用户难以解释跟踪。因此,MATLAB xUnit使用堆栈过滤启发式方法来显示测试故障跟踪:从最深的调用层开始,一旦跟踪离开MATLAB xUnit框架函数,所有进一步的框架函数都从堆栈跟踪中过滤出来。
的输出中显示堆栈跟踪的示例runxunit:
>> runxunit testSample
使用1个测试用例开始测试运行。
F
0.081秒失败。
=====测试用例失败=====
工作地点:c: \ \ matlab_xunit \ \ testSample.m架构
名称:testMyCode
c: \ \ matlab_xunit \ \ testSample架构工作。米在6号线
输入元素在相对公差1.49012e-008范围内并非全部相等
第一个输入:
1
第二个输入:
1.1000
单击上面带下划线的蓝色链接,将相应的文件加载到编辑器中,位于相应的行。
扩展框架
MATLAB xUnit框架主要可以通过子类化来扩展TestCase,TestSuite,TestMonitor.
TestCase可以子类化以启用一组新的测试用例,这些用例都共享一些特定的行为。MATLAB xUnit测试框架包含三个扩展示例TestCase这样的行为:
- FunctionHandleTestCase提供基于过程函数句柄定义测试用例的能力。
- TestCaseInDir定义必须在特定目录中运行的测试用例。的设置而且拆卸在运行测试用例之前重写MATLAB的工作目录,然后在测试用例结束时恢复原来的工作目录。这个类由框架自己的测试套件使用。
- TestCaseInPath定义一个测试用例,该用例必须在临时添加到MATLAB路径的特定目录下运行。其实现类似于TestCaseInDir,框架自己的测试套件也使用它。
TestSuite可以类似地通过子类化进行扩展。这可能会在将来提供一种方法来定义一个包含在单独目录中的测试组件集合的测试套件,目前还不支持这种方法。万博1manbetx
最后TestRunMonitor可以子类化以支持各种测试监视机制,例如一个万博1manbetx图形测试运行器.