首页 > 解决方案 > 使用 matlab 测试框架对异常执行单元测试时出错

问题描述

我在文件夹中有以下课程+WTrade/+Database/@PostgreSQLConnectionOptions

classdef PostgreSQLConnectionOptions < handle

  properties (Access = private)
    databaseHost
  end

  methods (Access = public)

    function this = PostgreSQLConnectionOptions()
      this.databaseHost = "";
    end

    function setHostname(this, name)
      if ~isstring(name)
        me = MException("WTrade:invalidParameter", "WTrade.Database.PostgreSQLConnectionOption.setHostname: name must be a string");
        throw(me);
      end
      if 1 ~= length(name)
        me = MException("WTrade:invalidParameter", "WTrade.Database.PostgreSQLConnectionOption.setHostname: name array size must be 1");
        throw(me);
      end

      this.databaseHost = name;
    end

  end
end

我想对这个类进行单元测试。我有以下测试课

classdef PostgreSQLConnectionOptionsTest < matlab.unittest.TestCase

  methods (Test)

    function testWrongHostnameArray(this)
      options = WTrade.Database.PostgreSQLConnectionOptions();
      hostName = ["h1" "h2"];
      this.verifyError(options.setHostname(hostName), 'WTrade:invalidParameter');
    end

  end
end

当我尝试使用以下脚本运行测试时:

import matlab.unittest.TestSuite
import matlab.unittest.constraints.Throws;

databaseSuite = TestSuite.fromFolder("tests/WTrade/Database");
result = run(databaseSuite);

我收到以下错误:

>> runtests('PostgreSQLConnectionOptionsTest','ProcedureName','testWrongHostnameArray')
Running PostgreSQLConnectionOptionsTest
32        options = WTrade.Database.PostgreSQLConnectionOptions();

================================================================================
Error occurred in PostgreSQLConnectionOptionsTest/testWrongHostnameArray and it did not run to completion.
    ---------
    Error ID:
    ---------
    'MATLAB:TooManyOutputs'
    --------------
    Error Details:
    --------------
    Error using WTrade.Database.PostgreSQLConnectionOptions/setHostname
    Too many output arguments.

    Error in PostgreSQLConnectionOptionsTest/testWrongHostnameArray (line 34)
          this.verifyError(options.setHostname(hostName), 'WTrade:invalidParameter');
================================================================================
.
Done PostgreSQLConnectionOptionsTest
__________

Failure Summary:

     Name                                                    Failed  Incomplete  Reason(s)
    =======================================================================================
     PostgreSQLConnectionOptionsTest/testWrongHostnameArray    X         X       Errored.

ans = 

  TestResult with properties:

          Name: 'PostgreSQLConnectionOptionsTest/testWrongHostnameArray'
        Passed: 0
        Failed: 1
    Incomplete: 1
      Duration: 2.0606
       Details: [1×1 struct]

Totals:
   0 Passed, 1 Failed (rerun), 1 Incomplete.
   2.0606 seconds testing time.

我不明白这个'MATLAB:TooManyOutputs'错误。我已经直接在matlab中尝试了该方法,它按预期工作;我测试参数是否为字符串,如果不是,则启动异常。

当我运行以下命令时:

a = WTrade.Database.PostgreSQLConnectionOptions
a.setHostname(["p1", "p2")

我得到了我期望的错误。

Error using WTrade.Database.PostgreSQLConnectionOptions/setHostname (line 43)
WTrade.Database.PostgreSQLConnectionOption.setHostname: name array size must be 1

那么为什么我无法在测试用例中正确捕获异常呢?如何正确检查是否抛出异常以便通过测试?

标签: matlabunit-testingexception

解决方案


You need to pass a function handle to verifyError. What is happening now is you are calling this.verifyError(options.setHostname(hostName), 'WTrade:invalidParameter'); which is actually invoking options.setHostname(hostName) with one output argument to pass as an argument to verifyError. Instead it should be:

this.verifyError(@() options.setHostname(hostName), 'WTrade:invalidParameter');

Also, I would recommend using a standard property Hostname and instead of writing a setter method use the validation syntax, like so:

classdef PostgreSQLConnectionOptions < handle

  properties 
    Hostname(1,1) string = "";
  end

end

Not, if you need to do more custom validation you can always write a setter method like so:

methods
    function set.Hostname(options, hostname)
        % some additional validation here
    end
end

Note though when you use the properties, in order to use verifyError you'll need to wrap it in a function:

classdef PostgreSQLConnectionOptionsTest < matlab.unittest.TestCase

  methods (Test)

    function testWrongHostnameArray(this)
      options = WTrade.Database.PostgreSQLConnectionOptions();
      hostName = ["h1" "h2"];
      this.verifyError(@setHostname, 'WTrade:invalidParameter');
      function setHostname
          options.Hostname = hostname;
      end
    end

  end
end

Even though you need to wrap this in a function for testing, it is by and large a better experience to use properties as they are. We have built in encapsulation with matlab, and I think it's best to leverage it.


推荐阅读