为单元测试公开M文件子功能的最简单方法是什么?

Sco*_*ott 14 matlab unit-testing

我最近一直在修补将完整的连续测试集成到我的Matlab开发周期中,遇到了一个我不知道如何解决的问题.正如几乎所有用户都知道的那样,Matlab从M文件之外的任何函数的视图中隐藏了M文件中的子函数.下面是一个玩具示例:

function [things] = myfunc(data)
  [stuff] = mysubfunc(data)
  things = mean(stuff);
end
Run Code Online (Sandbox Code Playgroud)

我想在subfunc本身上执行单元测试.这是AFAIK,不可能,因为我无法从任何外部功能调用它.

我目前正在使用Steve Eddins的Matlab xUnit,无法解决这个问题.简单的解决方案 - 将子函数拆分为自己的M文件 - 在实践中是不可接受的,因为我将拥有许多我想要测试的小函数,并且不希望使用单独的M文件污染我的文件系统.如果不为我要测试的每个函数创建新文件,我该怎么做才能编写和执行简单的单元测试?

gno*_*ice 14

您通常需要做的是从主函数中获取子函数的函数句柄,并将它们传递到可以对它们进行单元测试的函数之外.一种方法是修改你的主要功能,这样,给定一组特定的输入参数(即没有输入,参数的某些标志值等),它将返回你需要的函数句柄.

例如,您可以在函数的开头添加几行代码,以便在未指定输入时返回所有子函数句柄:

function things = myfunc(data)

  if nargin == 0                            % If data is not specified...
    things = {@mysubfunc @myothersubfunc};  % Return a cell array of
                                            %   function handles
    return                                  % Return from the function
  end

  % The normal processing for myfunc...
  stuff = mysubfunc(data);
  things = mean(stuff);

end

function mysubfunc
  % One subfunction
end

function myothersubfunc
  % Another subfunction
end
Run Code Online (Sandbox Code Playgroud)

或者,如果您更喜欢指定输入标志(以避免与Jonas在其注释中提到的意外调用函数而没有任何输入相关的混淆),则可以在输入参数data是特定字符串时返回子函数句柄.例如,您可以将上面代码中的输入检查逻辑更改为:

if ischar(data) && strcmp(data, '-getSubHandles')
Run Code Online (Sandbox Code Playgroud)

  • +1 - 虽然我使用`returnSubfunctionHandles`输入参数创建函数句柄.调用一个否则需要输入零输入参数的函数是偶尔会发生的错误,并且可能需要一段时间来追踪这些奇怪的句柄来自哪里. (3认同)

Wil*_*iam 2

我有一个非常古怪的方法来做到这一点。并不完美,但至少是可能的。

function [things] = myfunc(data)

global TESTING

if TESTING == 1
    unittests()
else
    [stuff] = mysubfunc(data);
    things = mean(stuff);
end

end

function unittests()

%%Test one
tdata = 1;
assert(mysubfunc(tdata) == 3)

end

function [stuff] = mysubfunc(data)

stuff = data + 1;

end
Run Code Online (Sandbox Code Playgroud)

然后在提示符下就可以解决问题了:

>> global TESTING; TESTING = 1; myfunc(1)
??? Error using ==> myfunc>unittests at 19
Assertion failed.

Error in ==> myfunc at 6
    unittests()

>> TESTING = 0; myfunc(1)

ans =

     2

>> 
Run Code Online (Sandbox Code Playgroud)