• 如何使用MATLAB写测试(3)combinatorial explosion? 参数化!


    如何使用MATLAB写测试(3)combinatorial explosion? 参数化!

    原文:如何使用MATLAB写测试(3)combinatorial explosion? 参数化! - 知乎 (zhihu.com)

    最近我们的俄罗斯实习生有些头大,他为foo程序写的正向测试只有single一种情况。

    1. function out = foo(in)
    2. validateattributes(in,{'numeric'},{'nonempty'});
    3. % Returns zero
    4. out = zeros(size(in),'like',in);
    5. end

    他的老板看到他的测试后问他,你知道MATLAB中数据类型有几种吗?俄罗斯实习生虽然没读过孔乙己的故事,但至少也知道有double, single, uint8几种常见的类型。于是他尝试更新了下他的测试。

    1. classdef myTest < matlab.unittest.TestCase
    2. methods (Test)
    3. function testSingle(test) %function唯一的参数test是你的测试对象
    4. % Verifies single input case
    5. in = single(10); %输入
    6. expOut = zeros(1,'single'); %期待的输出
    7. actualOut = foo(in); %调用待测程序
    8. test.verifyEqual(actualOut,expOut); %比较实际输出与期待输出
    9. end
    10. function testDouble(test)
    11. % Verifies double input case
    12. in = double(10); %输入
    13. expOut = zeros(1,'double'); %期待的输出
    14. actualOut = foo(in); %调用待测程序
    15. test.verifyEqual(actualOut,expOut); %比较实际输出与期待输出
    16. end
    17. % Negative test case
    18. function testEmptyError(test)
    19. % Verifies error on empty input
    20. in = [];
    21. expErrorId = 'MATLAB:expectedNonempty';
    22. %传入function handle, 给出期待的error id
    23. test.verifyError(@()foo(in),expErrorId);
    24. end
    25. end
    26. end

    作为一个合格的实习生,他一下就发现了接下来会发生的事情。对于每一个数据类型,他都要写一个完全一样的测试。公司招他来可不是做ctrl+c,ctrl+v的。而且要是以后有更多的测试,每个都需要对不同数据类型做相同的test case, 那要多少啊?

    还好我们的数学教育不差

    他心想。手上迅速算着帐。

    假设MATLAB有N种数据类型,而我为每个数据类型都需要写M个测试,假设M个测试对每个数据类型都是相同的,那我就会有
    𝐶𝑁1∗𝑀=𝑁∗𝑀
    个测试,这还是以我的程序需要一个输入为前提。
    这是如果我的程序需要两个输入,比如foo(x,y)
    那我要写的测试数量就变成了
    𝐶𝑁1∗𝐶𝑁1∗𝑀=𝑁2∗𝑀
    ...
    如果程序需要k个输入,那要写的测试数量就变成了
    𝑁𝑘∗𝑀

    想到这里他背后直冒冷汗,难道自己的一生就耗在写测试上了?

    MATLAB这么高大上的语言一定不会允许这件事发生的。

    他边这么想着边翻阅着文档,突然发现了Parametrized Tests这篇教程。他按部就班地更新了自己的测试

    1. classdef myTest < matlab.unittest.TestCase
    2. properties(TestParameter) %定义测试参数
    3. type = {'double','single','uint8'}
    4. end
    5. methods (Test)
    6. function testInput(test, type) %传入测试参数
    7. % Verifies single input case
    8. in = cast(10,type); %输入
    9. expOut = zeros(1,type); %期待的输出
    10. actualOut = foo(in); %调用待测程序
    11. test.verifyEqual(actualOut,expOut); %比较实际输出与期待输出
    12. end
    13. end
    14. end

    跑test

    1. >> result = runtests('myTest')
    2. Running myTest
    3. ...
    4. Done myTest
    5. __________
    6. result =
    7. 1x3 TestResult array with properties:
    8. Name
    9. Passed
    10. Failed
    11. Incomplete
    12. Duration
    13. Details
    14. Totals:
    15. 3 Passed, 0 Failed, 0 Incomplete.
    16. 0.12308 seconds testing time.

    注意到了吗,虽然只写了1个test case, 但是结果result中却有3个TestResult。展开看看究竟是什么?

    1. >> result.Name
    2. ans =
    3. myTest/testInput(supportedClass=double)
    4. ans =
    5. myTest/testInput(supportedClass=single)
    6. ans =
    7. myTest/testInput(supportedClass=uint8)

    哦!

    掌握了基本参数化测试的俄罗斯实习生决定试试更高级的技巧,他为自己的源程序加入了一个新的输入

    1. function out = foo(in1 , in2)
    2. assert(isequal(size(in1),size(in2)),'input 1 and input 2 must be of same size'); % ugly but works
    3. validateattributes(in1,{'numeric'},{'nonempty'});
    4. validateattributes(in2,{'numeric'},{'nonempty'});
    5. % Cast everything into input 1's class
    6. in2 = cast(in2,class(in1));
    7. % Returns zero
    8. out = zeros(size(in1),'like',in1) * zeros(size(in2),'like',in2) ;
    9. end

    并更新了测试

    1. classdef myTest < matlab.unittest.TestCase
    2. properties(TestParameter) %定义测试参数
    3. type1 = {'double','single','uint8'}
    4. type2 = {'double','single','uint8'}
    5. end
    6. methods (Test)
    7. function testInput(test, type1, type2) %传入测试参数
    8. % Verifies single input case
    9. in1 = cast(10,type1); %输入
    10. in2 = cast(10,type2); %输入
    11. expOut = zeros(1,type1); %期待的输出
    12. actualOut = foo(in1,in2); %调用待测程序
    13. test.verifyEqual(actualOut,expOut); %比较实际输出与期待输出
    14. end
    15. end
    16. end

    跑tests

    1. >> result = runtests('myTest')
    2. Running myTest
    3. .........
    4. Done myTest
    5. __________
    6. result =
    7. 1x9 TestResult array with properties:
    8. Name
    9. Passed
    10. Failed
    11. Incomplete
    12. Duration
    13. Details
    14. Totals:
    15. 9 Passed, 0 Failed, 0 Incomplete.
    16. 0.10923 seconds testing time.

    有9个测试了,心算下……

    3个数据类型,2个输入,1个测试方法
    𝑁=3,𝑘=2,𝑀=1,𝑁𝑘∗𝑀=32∗1=9

    对哦!

    这下combinatorial explosion的问题就给计算机去解决吧!我1000刀买来配Oculus Rift的机器跑这点test还是可以的……

    有兴趣的玩家(读者 可以阅读如何利用ParameterCombination来减少测试的数量

    -参考资料

    Create Basic Parameterized Test

    Create Advanced Parameterized Test

  • 相关阅读:
    性能测试 —— Jmeter定时器
    动环监控系统什么牌子好?动环监控有哪些厂家
    使用三重损失和孪生神经网络训练大型类目的嵌入表示
    C# 压缩图片
    Asp.Net 6.0集成 Log4Net
    if else 替代方案
    Linux docker(01) 基础操作
    CSDN 编程竞赛五十五期题解
    LabVIEW专栏八、类
    30天Python入门(第十四天:深入了解Python中的高阶函数))
  • 原文地址:https://blog.csdn.net/m0_69824302/article/details/139453269