m88 188bet uedbet 威廉希尔 明升 bwin 明升88 bodog bwin 明升m88.com 18luck 188bet unibet unibet Ladbrokes Ladbrokes casino m88明升 明升 明升 m88.com 188bet m88 明陞 uedbet赫塔菲官网 365bet官网 m88 help
188bet论坛 文章 技能专栏 MATLAB工程项目 检查内容

MATLAB单元测验

2019-3-3 09:33| 发布者: ilovematlab| 检查: 30747| 谈论: 1|原作者: oopmatlab

摘要: 本篇是把现代软件工程思维应用到MATLAB工程开发中的精华,期望高档MATLAB用户细心研读。作者用实践的比方解说在开发和逐步改善算法的时分,怎么确保程序已有的功用没有收到影响,稳扎稳打,让算法开发和测验体系的建 ...

文章PDF阅览下载链接

目录:

inputParser章节中,咱们经过不断改善getArea函数对输入参数的处理办法,引进这样一个观念:一个牢靠的科学工程核算项目有必要有一套测验体系,才干避免开发的过程中算法退化,工程项意图推动有必要在算法开发和算法测验之间不断迭代完。在inputParser章节的终究,还依据直觉提出了一个测验体系所应该有的根本功用。在本章中,咱们将学习MATLAB供给的测验解决方案:MATLAB单元测验(MATLAB Unit Test)。

依据函数的(Function-Based)单元测验的结构

MATLAB依据函数的单元测验结构很简略,如图Figure 1所示:用户经过一个主测验函数和若干部分测验函数(也叫做测验点) (Local Function)来安排各个测验。而测验的运转则交给MATLAB的单元测验架构(以下简称Framework)去完结。
Figure.1 单元测验Framework和测验函数
主测验函数和部分测验函数看上去和一般的MATLAB函数没有差异,其结构如图Figure 2 所示,只是命名上有一些规矩罢了,这些特别的规矩是为了Framework能够和测验函数契合而规矩的。
Figure.2 简略的主测验函数和若干部分的测验函数构成的一个单元测验
命名规矩如下:
  • 主函数的称号由用户恣意指定,和其他的MATLAB函数文件相同,该文件的称号需求和函数的称号的相同. (假如主函数的称号是 testmainfunc , 该文件称号则是testmainfunc.m )。
  • 在主函数中,有必要调用一个叫做 functiontests 的函数,收集该函数中的一切部分函数, 发生一个包含这些部分函数的函数部分的测验矩阵并回来给Framework
如下所示:
% testmainfunc.m 
  function tests = testmainfunc
    tests = functiontests(localfunctions);   % 主测验函数中有必要要有这个指令
  end
  ... 
 
其间 localfunctions 是一个MATLAB函数,用来回来一切部分函数的函数句柄。 部分函数的命名有必要以 test 最初,部分函数只承受一个输入参数,即测验目标,即下面比方中的形参 testCase
% testmainfunc.m 
  ...
  function testPoint1(testCase)    % 只承受一个输入参数
      testCase.verifyEqual(.....);
  end 
 
  function testPoint2(testCase)    % 只承受一个输入参数
      testCase.verifyEqual(.....);
  end 
  ...
 
其间testCase由单元测验Framework供给,即Framework将主动的调用该函数,而且供给testCase参数。 依照规矩,要运转单元测验中的一切测验,有必要调用runtests函数
% command line 
   >> runtests('testmainfunc.m') 
 
下面用咱们用依据函数的单元测验来给getArea函数的结构其单元测验。

getArea函数的单元测验: 版别 I

首要给主测验文件起个姓名叫做testGetArea,该姓名是恣意的,为了便于了解姓名里边一般包含test,并包含要测验的首要函数的姓名:
% testGetArea.m 
 function tests = testGetArea
   tests = functiontests(localfunctions);
 end 
 
在该主函数中,localfunctions将收集一切的部分函数,结构函数句柄数组并回来测验矩阵。这儿天然会有一个问题,这个tests句柄数组将回来给谁,这就要了解Framework是怎么和测验彼此效果的。 如图Figure.3 所示,整个测验从 runtests('testmainfunc.m') 指令开端, 指令函数,Framework将首要调用testGetArea的主函数,得到一切的部分函数的函数句柄,如空心箭头线段所示,然后Framework再担任调用每一个测验部分函数,而且把testCase作为参数供给给每个部分函数,如虚线线段所示。咱们能够把Framework幻想成一个流水线,用户只需求经过 runtests('testmainfunc.m') 把"testmainfunc.m"放到流水线上而且翻开开关"就能够了。它是MATLAB的类 matlab.unittest.FunctionTestCase 的目标。
Figure.3 单元测验Framework和测验函数的彼此效果
回来的testCase是类 matlab.unittest.FunctionTestCase 的目标,有许多成员验证办法能够供给给用户调用,咱们的第一版的getArea函数如下, 要求函数承受两个参数,而且都是数值类型:
% 第一版的getArea函数 
   function a = getArea(wd,ht)
 
   p = inputParser;
 
   p.addRequired('width', @isnumeric); % 检查输入有必要是数值型的
   p.addRequired('height',@isnumeric);
 
   p.parse(wd,ht);
   
   a = p.Results.width*p.Results.height;  % 从Results处取成果
 end  
 
咱们先给这个getArea写第一个测验点,确保测验getArea函数在承受两个参数的时分,能给出正确的答案
% testGetArea.m 
 function tests = testGetArea
     tests = functiontests(localfunctions);
 end
 % 增加了第一个测验点
 function testTwoInputs(testCase)
     testCase.verifyTrue(getArea(10,22)==220,'!=220'); 
     testCase.verifyTrue(getArea(3,4)==12,'!=12');    
 end  
 
咱们给testGetArea.m增加一个部分函数叫做testTwoInputs,依照规矩,该部分函数的姓名要以test最初,后边的姓名要能够尽量反应该测验点的实践测验的内容。verifyTrue是一个testCase目标所支撑的办法,它用来验证其第一个参数,作为一个表达式,是否为真。verifyTrue的第二个参数承受字符串,在测验失利时供给确诊提示。 一个很常见的问题是: getArea是一个极端简略的函数,内部的作业便是把两个输入相乘,在这儿验证 getArea(10,22) == 220 真的有必要吗?请读者记住这个问题,它是了解单元测验的精要之一。 下面咱们来运转这个测验:
% command line 
 >> results =runtests('testGetArea')
 Running testGetArea
 .
 Done testGetArea
 __________
 results =    % 测验回来matlab.unittest.TestResult目标
   TestResult with properties:
           Name: 'testGetArea/testTwoInputs'
         Passed: 1              
         Failed: 0
     Incomplete: 0
       Duration: 0.0018
 Totals:
    1 Passed, 0 Failed, 0 Incomplete.
    0.0018203 seconds testing time.
 
测验回来一个 matlab.unittest.TestResult 目标,其间包含运转测验的成果,不出预料咱们的函数经过了这轮简略的测验。 假如函数没有经过测验,比方咱们成心要验证一个过错的成果: getArea(10,22) ==0
% testGetArea.m 
 function tests = testGetArea
     tests = functiontests(localfunctions);
 end
 function testTwoInputs(testCase)
     testCase.verifyTrue(getArea(10,22)==0,'Just A Test'); % 成心让验证失利
 end  
 
Framework将给出翔实的过错陈述, 其间 Test Diagnostic 栏目中陈述的便是verifyTrue函数中的第二个参数所供给的确诊信息。
% command line 
 >> results =runtests('testGetArea')
 Running testGetArea
 ================================================================================
 Verification failed in testGetArea/testTwoInputs.  % 验证失利
     ----------------
     Test Diagnostic:           % 确诊信息
     ----------------
     Just A Test
 
     ---------------------
     Framework Diagnostic:      
     ---------------------
     verifyTrue failed.       % 验证函数verifyTrue犯错  
     --> The value must evaluate to "true". 
                              % 验证的表达式getArea(10,22)==0的值应该为true
     Actual logical:                   
              0               % 表达式的实践值为false
     ------------------
     Stack Information:
     ------------------
     In testGetArea.m (testTwoInputs) at 6 % 测验点testTwoPoints犯错
 ================================================================================
 .
 Done testGetArea
 _________
 Failure Summary:                % 测验简报   
      Name                       Failed  Incomplete  Reason(s)
     ========================================================================
      testGetArea/testTwoInputs    X                 Failed by verification.
                                % 犯错的测验点称号
 results = 
   TestResult with properties:
 
           Name: 'testGetArea/testTwoInputs'
         Passed: 0              % 零个测验点经过
         Failed: 1              % 一个测验点犯错
     Incomplete: 0
       Duration: 0.0342
 Totals:
    0 Passed, 1 Failed, 0 Incomplete.
    0.03422 seconds testing time.  
 
咱们再增加一个负面测验,回想第一版的函数getArea不支撑单个参数,如下:
% command line 
 >> getArea(10)          % 如预期报错 调用少一个参数
 Error using getArea 
 Not enough input arguments.  
 >> [a b] = lasterr      % 调用lasterr得到error ID
 a =
 Error using getArea1 (line 6)
 Not enough input arguments.
 b =
 MATLAB:minrhs
 
咱们能够运用lasterr函数得到了这个过错的Error ID,这个Error ID将在负面测验中用到。 下面是这个负面测验,验证在只需一个输入的状况下,getArea函数能够如预期报错。咱们给测验增加一个新的测验点,叫做 testTwoInputsInvalid
% testGetArea.m 
 function tests = testGetArea
    tests = functiontests(localfunctions);
 end
 
 function testTwoInputs(testCase)
     testCase.verifyTrue(getArea1(10,22)==220,'!=220');
     testCase.verifyTrue(getArea1(3,4)==12,'!=12');    
 end
 % 增加了第2个测验点 
 function testTwoInputsInvalid(testCase)
     testCase.verifyError(@()getArea1(10),'MATLAB:minrhs');
 end
 
testTwoInputsInvalid 中, 咱们运用了测验目标的verifyError成员函数,它的第一个参数是函数句柄,即要履行的言语(会犯错的句子),第二个参数是要验证的MATLAB过错的Error ID, 便是咱们前面用lasterr函数得到的信息。verifyError内部还有try和catch,能够运转函数句柄,捕捉到过错,而且把Error ID和第二个参数做比较。 再举一个比方,咱们先在getArea函数中规矩一切的输入有必要是数值类型,所以假如输入的是字符串,getArea将报错,先再指令行中试验一下,以便得到Error ID:
% 在指令行中得到Error ID 
 >> getArea1('10',22)
 Error using getArea1 (line 6)
 The value of 'width' is invalid. It must satisfy the function: isnumeric. 
 >> [a b] = lasterr
 a =
 Error using getArea1 (line 6)
 The value of 'width' is invalid. It must satisfy the function: isnumeric.
 b =
 MATLAB:InputParser:ArgumentFailedValidation     % 这个Error ID是咱们需求的
 
然后再把这个负面测验增加到testGetArea中去
% testGetArea.m 
 function tests = testGetArea
 tests = functiontests(localfunctions);
 end
 
 function testTwoInputs(testCase)
     testCase.verifyTrue(getArea1(10,22)==220,'!=220');
     testCase.verifyTrue(getArea1(3,4)==12,'!=12');    
 end
  
 function testTwoInputsInvalid(testCase)
     testCase.verifyError(@()getArea1(10),'MATLAB:minrhs');
     testCase.verifyError(@()getArea1('10',22),...    % 新增的test
                         'MATLAB:InputParser:ArgumentFailedValidation')
 end  
 
运转一遍,一个正面测验,一个负面测验都悉数经过。
% command line 
 >> runtests('testGetArea')
 Running testGetArea
 ..
 Done testGetArea
 _________
 ans = 
   1x2 TestResult array with properties:
     Name
     Passed
     Failed
     Incomplete
     Duration
 Totals:
    2 Passed, 0 Failed, 0 Incomplete.
    0.0094501 seconds testing time.  
 

getArea函数的单元测验: 版别II & III

回想getArea函数的开发,第二个版别咱们给getArea增加了能够处理单个参数的才能,而且把inputParser和validateAttributes联合起来运用。新的函数在本来的根底上能够敷衍如下的新的状况
% command line 
 >> getArea(10)    % 正确处理了单个参数的状况
 ans =
    100
 
 >> getArea(10,0)  % 如预期检查出第二个参数的过错,并给出提示
 Error using getArea (line 37)
 The value of 'height' is invalid. Expected input number 2, height, to be nonzero.
  
 >> getArea(0,22)  % 如预期检查出第一个参数的过错,并给出提示
 Error using getArea (line 37)
 The value of 'width' is invalid. Expected input number 1, width, to be nonzero.  
 
在开发完这第二个版别的函数之后,咱们首要运转了一下现已有的testGetArea测验,发现之前增加的一个测验点,验证函数在承受一个参数时会报错的状况已不再适用,由于咱们现已开端支撑单参数的功用了,所以要去掉它,跟着程序算法的不断开发,修正或删去已有的测验是很常见的
% testGetArea.m 
   ...
  % testCase.verifyError(@()getArea1(10),'MATLAB:minrhs');  需求去掉这个测验
   ...
 
去掉不再适用的测验之后,咱们持续给单元测验增加新的测验点,首要增加一个Postive 测验点,确保getArea函数承受单一参数核算成果正确
% 确保单一参数核算正确 
 function tests = testGetArea
    ...从略
  
  function testOneInput(testCase)
       testCase.verifyTrue(getArea2(10) ==100,'!=100');
       testCase.verifyTrue(getArea2(22) ==484,'!=484');
  end
 
再增加一个Negative测验点,确保getArea函数会处理输入是零的状况
% 确保不承受零输入  
 function tests = testGetArea
    ...从略
 
  function testTwoInputsZero(testCase)
      testCase.verifyError(@()getArea(10,0),'MATLAB:expectedNonZero');
      testCase.verifyError(@()getArea(0,22),'MATLAB:expectedNonZero');
  end
 
然后调用
% command line 
 >> runtests('testGetArea')
 ...  
 
每次运转这个指令,会运转之前一切的测验点和新的测验点,这也就确保了对新增加的算法没有损坏曾经有的功用。咱们前面问了一个问题: 验证getArea(10,22) == 220 真的有必要吗。
其必要性之一,也是单元测验功用之一:即这个验证其实是对getArea能正确处理两个参数的才能的一个前史记载。由于咱们在不断的算法开发中,很难确保不会偶尔损坏一些曾经的什么功用,但是只需有这条测验在,不管咱们对getArea函数做怎样翻天复地的修正,只需一运转测验,都会验证这条前史记载,确保咱们没有损坏现已有的功用,换句话说,新的函数是向后兼容的。关于一个科学工程核算体系来说,一个函数会被用在许多不同的当地,向后兼容让咱们定心的持续开发新的功用,而不必忧虑是否要去检查一切其它运用该函数的当地。所以从这个视点说:单元测验是算法开发的堡垒,算法的开发应该以单元测验来稳扎稳打,在确保算法没有退化的根底上开发新的内容。话说回来,为了让这个版别的getArea能够顺畅运转,咱们的确去掉了一个对单一参数报错的测验,由于函数开端支撑这种功用了,这种做法和咱们说以单元测验稳扎稳打并不矛盾,假如新的算法导致旧的测验失利,咱们要依据实践状况,酌情决定是修正算法仍是修正测验。
在getArea的第三个版别中,咱们给函数增加了两个可选的参数:shape和units,而且它们的次序能够彼此倒置的。新的函数能够敷衍如下的状况:
% command line 
 >> getArea(10,22,'shape','square','units','m') %承受两对name-value pair
 ans =            %--name  value  --name   value
      area: 220
     shape: 'square'
     units: 'm'
 
 >> getArea(10,22,'units','m','shape','square')  % 变化了参数的方位
 ans = 
      area: 220
     shape: 'square'
     units: 'm'
 
 
 >> getArea(10,22,'units','m')                   % 只是供给unit参数
 ans = 
      area: 220
     shape: 'rectangle'
     units: 'm'  
 
为其增加的新的测验点如下:
% testGetArea 
 function tests = testGetArea
   ...从略
  
  function testFourInputs(testCase) % 记载能够支撑四个参数的状况
     actStruct = getArea5(10,22,'shape','square','unit','m');
     expStruct = struct('area',220,'shape','square','units','m');
     testCase.verifyEqual(actStruct,expStruct,'structs not equal');
  
     actStruct = getArea5(10,22,'unit','m','shape','square');
     expStruct = struct('area',220,'shape','square','units','m');
     testCase.verifyEqual(actStruct,expStruct,'structs not equal');
  end
  
  
  function testThreeInputs(testCase) % 记载能够支撑三个参数的状况
     actStruct = getArea5(10,22,'units','m');
     expStruct = struct('area',220,'shape','rectangle','units','m');
     testCase.verifyEqual(actStruct,expStruct,'structs not equal');
  end
   
 
在testFourInputs中,咱们从getArea函数那里先得到一个结构体,命名叫做actStruct(实践值) 然后预备了一个结构体叫做 expStruct (期望值),然后把用verifyEqual办法来作比较 在testThreeInputs中,咱们互换的第三和第四个参数的方位,确保成果依然是咱们预期的。

测验的预备和整理作业: Tests Fixtures

本节介绍单元测验体系中另一个很重要的概念叫做Fixture。假定咱们要给图形处理的一系列算法写测验,这些算法需求图画数据作为输入,所以在测验之前,咱们需求先载入图画数据,依照上节的比方,单元测验看上去是这样的。
% testImgProcess 
  function tests = testImgProcess(  )
     tests = functiontests(localfunctions);
 end
 
 
 function testOp1(testCase)
     img = imread('testimg.tif');    % 载入图画
     Op1(img);
     % ... rest of the work 
 end
 
 function testOp2(testCase)          
     img = imread('testimg.tif');   % 载入图画
     Op2(img);
     % ... rest of the work 
 end 
 
能够观察到,在每个测验点的一开端,都有相同的预备作业,便是翻开一个图画。在单元测验中,这叫做Test Fixture, 即每个测验的一起预备作业。假如这个测验函数中有许多这样的测验点,每次都要重复的调用imread操作很费事。关于这样的预备作业,咱们能够把它们放在一个叫做setup的部分函数中,该函数一致地在每个测验点的开端之前被调用。这样就不必在每个测验点中都包含一个imread的调用了。新的测验看上去是这样的:
% 运用setup和teardown 
 function tests = testImgProcess(  )
     tests = functiontests(localfunctions);
 end
 
 function setup(testCase)
     testCase.TestData.img = imread('corn.tif');
    % 其它的预备作业
 end
 function teardown(testCase)
    % 其他整理作业
 end
 function testOp1(testCase)
     newImg = Op1(testCase.TestData.img);   % 直接运用目标testCase的特色TestData
     % ... rest of the work 
 end
 
 function testOp2(testCase)
     newImg = Op2(TestCase.TestData.img);h
     % ... rest of the work 
 end  
 
在setup办法中,咱们翻开一个文件,并把数据动态地增加到testCase目标的TestData结构体上,在之后的每个部分测验点中,咱们能够经过 testCase.TestData.img 来拜访这个数据。 setup中还能够放其他的预备作业,比方创立一个暂时的文件夹放置暂时的数据等候。对应的teardown函数中用来寄存每个部分测验点运转结束之后的整理作业,比方铲除暂时文件夹。 setup和teardown办法在每个部分测验点的开端和结束后运转,所以假如该主测验文件有两个测验点,那么setup和teardown各被运转了两次,流程如图所示:
Figure.4, setup和teardown办法在每个部分测验点的开端和结束后运转
假如还有一些预备和整理作业只需求开端和结束的时分各运转一次,那么能够把他们放到setupOnce和teardownOnce中去,比方咱们要验证一些算法,而给该算法供给的数据来自数据库,在运转算法测验之前,要先衔接数据库,在测验结束之后,要封闭和数据库的衔接,这样的作业就契合setupOnce和teardownOnce的领域,如下所示:
% 运用setupOnce teardownOnce来办理对数据库的衔接 
 function tests = testAlgo(  )
     tests = functiontests(localfunctions);
 end
 
 function setupOnce(testCase)
     testCase.TestData.conn = connect_DB('testdb'); %一个设想的衔接数据库的函数
 end
 function teardownOnce(testCase)
     disconnect_DB();
 end
 function testAlgo1(testCase)
     % retrieve data and do testing
 end
 
 function testAlgo2(testCase)
     % retrieve data and do testing
 
 end
 
setupOnce和teardownOnce办法只是在整个测验开端和结束时运转一次,流程如图 Figure.5 所示
Figure.5, setupOnce和teardownOnce办法只是在整个测验开端和结束是运转一次
setupOnce,teardownOnce和setup,teardown也能够联合起来运用,如图Figure.6 所示:
Figure.6 setupOnce,teardownOnce和setup,teardown联合起来运用

验证办法: Types of Qualification

getArea函数的单元测验: 版别I 节中咱们说到,如下的测验点中:
% testGetArea.m 
 function tests = testGetArea
     tests = functiontests(localfunctions);
 end
 % 增加了第一个测验点
 function testTwoInputs(testCase)
     testCase.verifyTrue(getArea(10,22)==220,'!=220'); 
     testCase.verifyTrue(getArea(3,4)==12,'!=12');    
 end  
 
参数testCase是类 matlab.unittest.FunctionTestCase 的目标,由Framework供给,该类有许多成员验证办法能够供给给用户调用,比方前几节用到的verifyTrueverifyError ,这个两个验证办法最常见。悉数的验证办法下表所示:
验证办法 验证 典型运用
verifyTrue 表达式值为真 testCase.verifyTrue(expr,msg)
verifyFalse 表达式值为假 testCase.verifyFalse(expr,msg)
verifyEqual 两个输入的表达式相同 testCase.verifyEqual(expr1,expr2,msg)
verifyNotEqual 两个输入的表达式不同 testCase.verifyNotEqual(expr1,expr2,msg)
verifySameHandle 两个handle指向同一个目标 testCase.verifySameHandle(h1,h2,msg)
verifyNotSameHanle 两个handle指向不同目标 testCase.verifyNotSameHandle(h1,h2,msg)
verifyReturnsTrue 函数句柄履行回来成果为真 testCase.verifyReturnsTrue(fh,msg)
verifyFail 无条件发生一个过错 testCase.verifyFail(msg)
verifyThat 表达式值满意某条件 testCase.verifyThat(5, IsEqualTo(5), '')
verifyGreatThan 大于 testCase.verifyGreaterThan(3,2)
verifyGreaterThanOrEqual 大于等于 testCase.verifyGreateThanOrEqual(3,2)
verifyLessThan 小于 testCase.verifyLessThan(2,3)
verifyLessThanOrEqual 小于等于 testCase.verifyLessThanOrEqual(2,3)
verifyClass 表达式的类型 testCase.verifyClass(value,className)
verifyInstanceOf 目标类型 testCase.verifyInstanceOf(derive,?Base)
verifyEmpty 表达式为空 testCase.verifyEmpty(expr,msg)
verifyNotEmpty 表达式非空 testCase.verifyNotEmpty(expr,msg)
verifySize 表达式尺度 testCase.verifySize(expr,dims)
verifyLength 表达式长度 testCase.verifyLength(expr,len)
verifyNumElements 表达式中元素的总数 testCase.verifyNumElements(expr,value)
verifySubstring 表达式中含有字串 testCase.verifySubstring('thing','th')
verifyMatches 字串匹配 testCase.verifyMatches('Another', 'An')
verifyError 句柄的履行抛出指定过错 testCase.verifyError(fh,id,msg)
verifyWarning 句柄的履行抛出指定正告 testCase.verifyWarning(fh,id,msg)
verifyWarningFree 句柄的履行没有正告 testCase.verifyWarningFree(fh)
除了verify系列的函数,MATLAB单元测验还供给
  • assume系列
  • assert系列
  • fatalAssert系列
的验证函数,也便是说,上面每一个verify函数,都有一个对应的assume,assert和fatalAssert函数。比方除了verifyTrue,还有assumeTrue,assertTrue,fatalAssertTrue三个验证办法。
assume系列的验证办法一般用来验证一些测验是否满意某些先决条件,假如满意,测验持续,假如不满意,则过滤掉这个测验,但是不发生过错。比方下面的测验点,假如测验者的意图是:在Windows渠道下才履行,没有必要在其它渠道下履行
% tFoo.m 
 function tests = tFoo
     tests = functiontests(localfunctions);
 end
 
 function testSomething_PC(testCase)    
     testCase.assumeTrue(ispc,'only run in PC');   % 假如这个测验点在其它渠道运转,
                                                   % 则显现Incomplete
     % ....
 end    
 
假如咱们在MAC下运转这个测验,则显现
>> runtests('tFoo')
 Running tFoo
 ================================================================================
 tFoo/testSomething_PC was filtered.
     Test Diagnostic: only run in PC
     Details
 ================================================================================
 .
 Done tFoo
 __________
 
 Failure Summary:
 
      Name                   Failed  Incomplete  Reason(s)
     ====================================================================
      tFoo/testSomething_PC              X       Filtered by assumption.
                                                 该测验被过滤掉了
 ans = 
   TestResult with properties:
 
           Name: 'tFoo/testSomething_PC'
         Passed: 0
         Failed: 0
     Incomplete: 1
       Duration: 0.0466
 
 Totals:
    0 Passed, 0 Failed, 1 Incomplete.
    0.046577 seconds testing time.  
 
assert系列的验证办法也是用来验证一些测验是否满意某些先决条件,假如满意,测验持续,假如不满意,则过滤掉这个测验,而且发生过错。但是它不会影响其他的测验点。比方下面这个比方,testSomething测验点中,咱们要求该测验的先决条件是数据库有必要先被衔接,假如没有衔接,那么没有必要进行余下的测验,而且testA的测验成果显现失利。但是这个失利将不会影响testB测验点的运转
function tests = tFoo
     tests = functiontests(localfunctions);
 end
 
 function testA(testCase)    
     testCase.assertTrue(isConnected(),'database must be connected!') 
     % 其它测验内容 
 end  
 
 function testB(testCase)
     testCase.verifyTrue(1==1,'');
 end
 
运转这个测验,显现如下
% command line 
   >> runtests('tFoo')
 Running tFoo
 ================================================================================
 Assertion failed in tFoo/testA and it did not run to completion.
     ----------------
     Test Diagnostic:
     ----------------
     database must be connected!
     ---------------------
     Framework Diagnostic:
     ---------------------
     assertTrue failed.
     --> The value must evaluate to "true".
     
     Actual logical:
              0
     ------------------
     Stack Information:
     ------------------
     In /Users/iamxuxiao/Documents/MATLAB/tFoo.m (testA) at 6
 ================================================================================
 ..
 Done tFoo
 __________
 
 Failure Summary:
 
      Name        Failed  Incomplete  Reason(s)
     ======================================================
      tFoo/testA    X         X       Failed by assertion.
     
 Totals:
    1 Passed, 1 Failed, 1 Incomplete.
    0.036008 seconds testing time.
 
终究,fatalAssert系列的验证办法,望文生义,便是假如失利,当即中止结束一切的测验。假如还有未运转的测验点,则不再运转它们,比方从略。

测验办法论和以测验驱动开发(Test-Driven Development)

开发流程概述

在前节的根底上,本节将笼统的谈论MATLAB常见的开发流程,引进用测验驱动开发的思维。先概述一下常见的开发作业流程。最简略也是最常见的作业流程是:先用代码完结一个功用,然后在指令行测验该代码是否到达预期意图,假如到达了,则该函数放到更大的工程项目中去运用,然后不再去更新,如图所示:
Figure.8 最简略最常见的作业流程
假如比较杂乱的功用,在写好的代码放入更大的工程项目之前,咱们一般需求在指令行中重复的测验各个方面的功用, 便利起见,咱们一般还会写一个专门测验的脚本,比方新的函数假如叫做op1, 一般习气会写一个script1.m来一次性测验op1的一切的功用。测验结束之后,把op1函数放入工程项目中,而该script1.m脚本,一般由于没有很好的办理方法,则不免忘记在某个文件夹中,或忘记在工程项意图最上层目录里边,终究被整理掉。
Figure.9 用脚本测验
本节咱们将引进的作业流程是:开发一个杂乱的功用,从开发最简略的部分开端,按部就班的完结更杂乱的需求,而且在此一起引进该功用配套的单元测验文件,测验和开发同步进行,测验和要测验的代码共生在同一个目录下。即便要测验的内容被参加的更大的项目之中,咱们仍是保存这个测验,单元测验自身也是工程项目中的一部分。
Figure.10 单元测验是工程项意图一部分
测验仍是多人合作项目中不行短少短少的环节。比方A和B一起开发一个项目两人别离担任该项目中的不同部分,他们的作业项目依托彼此调用,乃至有少数的堆叠,即有可能要修正对方的代码。那么怎么确保A在修正B的代码的时分不会损坏B已有的功用呢,这就要依托B写的测验代码了。在A修正完代码之后,但在A提交代码到Repository之前,A有必要在本地的工程项目中运转一切的测验,这些测验确保A不会意外的损坏B的代码的已有的功用,所以B的测验也起到了维护自己代码的效果,由于它起到了对别人的束缚效果
Figure.11 提交之前有必要运转一切的测验
前面咱们提出一个问题:如下测验点里验证清楚明了的getArea(10,22) == 220 真的有必要吗?
% testGetArea.m 
     ...
 function testTwoInputs(testCase)
     testCase.verifyTrue(getArea(10,22)==220,'!=220'); 
     ...
 end  
 ...  
 
再从另一视点看:有必要。由于单元测验其实是程序最好的文档。由于咱们不行能给每一个函数都写文档,或许在函数里边都写清楚具体的注释。天长日久之后,即便有注释或许由于忘记而很难看懂。当咱们要回想一个函数,一个功用怎么运用的时分,最快的办法不是去读它的完结代码或许注释,而是去查找工程项目中其它的当地是怎么运用这个功用的。但是假如工程项目过于杂乱,这也不会是一件简单的作业。假如有了这个函数的单元测验,由于这个单元测验是只是关于这一个功用的,那么咱们会很简单就经过单元测验就能够了解这个函数的功用是什么。所以getArea(10,22) == 220 不行是一个前史的记载,记载这个函数要完结的功用,仍是该函数最好的阐明文档,为了让这个阐明文档今后阅览起来愈加的明晰,咱们还必要过错的提示信息写得愈加具体一些,比方上面的测验点可能够这样改写
%  过错提示信息其实是getArea文档的一部分 
     ...
 function testTwoInputs(testCase)
     testCase.verifyTrue(getArea(10,22)==220,'given width and height, ...
                                              should return 10*22=220'); 
     ...
 end  
 ...  
 
前面所谈论的开发形式,测验总是作为首要功用的辅佐,还有一种盛行的开发形式,测验的位置和要测验的代码的位置是平起平坐,这种测验和开发的作业流程,叫做用测验驱动(Test Driven Development),也值得咱们了解一下。 咱们从前的这些作业流程无一例外都是先写算法,然后补上测验代码;读者有没有想过可不能够先写测验,再写函数的完结呢。为什么要这样开发,这样开发有什么优点,咱们将举例阐明。

用测验驱动开发:Fibonacci例

假定一个教编程的教师给学生安置了一道MATLAB程序,要求写一个核算Fibonacci数列的函数。已知,Fibonacci函数界说如下:
F(n) = F(n-1) + F(n-2)
当n=1;2 时F(1) = F(2) = 1。
而且规矩n=0时,F(0)=0。 要求除了核算正确以外,还有必要能正确的处理各种不合法的输入,比方输入对错整数,负数或许字符串的状况。 所谓以测验驱动做开发就得到程序的需求之后,在这儿即教师的作业要求,先写测验的代码,再写程序。比方依据教师的要求,很简单就写出该函数要满意的条件的一个清单
  • fibonacci(0)= 0
  • fibonacci(1)= 1
  • fibonacci(2)= 1
  • fibonacci(3)= 2 ; fibonacci(4)= 3
  • fibonacci(1.5) 报错
  • fibonacci(-1) 报错
  • fibonacci('a') 报错
依据这些条件,咱们能够很简单的写出两个测验点,一个是正面测验,一个负面测验
function tests = testFib(  )
     tests = functiontests(localfunctions);
 end
 
 function testValidInputs(testCase)
     % fibonacci function only accepts integer 
     testCase.verifyTrue(fibonacci(int8(0))  ==0, 'f(0) Error');
     testCase.verifyTrue(fibonacci(int16(1)) ==1, 'f(1) Error');
     testCase.verifyTrue(fibonacci(int32(2)) ==1, 'f(2) Error');
     testCase.verifyTrue(fibonacci(uint8(3)) ==2, 'f(3) Error');
     testCase.verifyTrue(fibonacci(uint16(4))==3, 'f(4) Error');
     testC

相关阅览

宣布谈论

最新谈论

引证 cliffzq 2019-7-13 16:06
学习了,多谢
引证 蓝色的船 2018-10-27 17:17
我是来崇拜大神的
引证 蓝色de闪电 2018-6-5 14:15
不明觉厉
引证 SongCW 2017-12-7 21:29
用仿真测验的办法Mtest,依据需求开发,便利完好
引证 ArthurB 2017-11-3 00:05
作者写的内容非常丰富,收获颇丰
引证 胖柯基爱代码 2017-8-9 14:32
求问,假如我想测验的函数是没有输出的,比方说 function errorreport(data,xls). 是不是就不适合做单元测验。
我的方程完结的是,测验数据是否超越规矩区域,超越了就把过错记载下来,将过错主动发邮件给担任人。所 ...

检查悉数谈论(1)

MATLAB table数据结构 首篇

MATLAB table是R2013b中引进的一个新的数据结构,尽管不像常用的根本数据类型为人了解,但是在编程中非常有用。它用来寄存表状类型的数据结构,而且支撑常见的表和表之间的运算。 ... ... ... ... ... ... ...

MATLAB映射表数据结构

除了常用的根本数据类型,MATLAB还有许多其它有用的数据类型不为人了解,例如映射表containers.Map,常用的MATLAB高档数据类型。它最大的特色运用便利的索引方法进行快速的查找。本篇介绍为什么需求这种数据结构,以 ...

MATLAB table数据结构 再篇

MATLAB table是R2013b中引进的一个新的数据结构,尽管不像常用的根本数据类型为人了解,但是在编程中非常有用。它用来寄存表状类型的数据结构,而且支撑常见的表和表之间的运算。 ... ... ... ... ... ... ...

对函数的输入进行检查和解析

在工程核算中,假如函数的输入有过错,咱们总是期望能尽早捕捉到这些过错,并及时停止程序。在MATLAB 中,能够运用validateattributes,validatestring和inputParser 类来对输入进行检查。它们供给全面的检查功用和清 ...

MATLAB单元测验

本篇是把现代软件工程思维应用到MATLAB工程开发中的精华,期望高档MATLAB用户细心研读。作者用实践的比方解说在开发和逐步改善算法的时分,怎么确保程序已有的功用没有收到影响,稳扎稳打,让算法开发和测验体系的建 ...

MATLAB映射表数据结构

除了常用的根本数据类型,MATLAB还有许多其它有用的数据类型不为人了解,例如映射表containers.Map,常用的MATLAB高档数据类型。它最大的特色运用便利的索引方法进行快速的查找。本篇介绍为什么需求这种数据结构,以 ...

对函数的输入进行检查和解析

在工程核算中,假如函数的输入有过错,咱们总是期望能尽早捕捉到这些过错,并及时停止程序。在MATLAB 中,能够运用validateattributes,validatestring和inputParser 类来对输入进行检查。它们供给全面的检查功用和清 ...

MATLAB功用测验结构

MATLAB Performance Test 结构是Mathworks 在MATLAB R2016a 中推出的⼀个新的结构,该结构⽤来取得代码功用在计算意义上的数据,还能够⽤来⽐较算法的功用,而且给出具体完好的陈述。 ... ... ... ... ... ... ... ...
封闭

站长引荐上一条 /3 下一条

回来顶部