我有以下非常简单的实用功能:
function vfprintf(verbose, varargin)
% VFPRINTF Display output optionally depending on the level of verbosity.
%
% VFPRINTF(TF, ARGS) passes the arguments ARGS to the built-in MATLAB
% command |fprintf| if TF is logical true. If TF is logical false, VFPRINTF
% does nothing.
assert(islogical(verbose),...
'utils:InvalidVerbose',...
'VERBOSE must be logical true or false');
if verbose
fprintf(varargin{:});
end
事实证明,尽管该功能非常简单,但它有一个问题导致我出现问题(assert
条件应该是islogical(verbose) && isscalar(verbose)
,而不仅仅是islogical(verbose)
),所以我想围绕它实施一些单元测试。
请注意,我不想测试fprintf
- 我假设没问题。那么我有没有办法测试类似的东西:
verbose
的逻辑标量为true,则调用fprintf
" verbose
的逻辑标量为false,则不会调用fprintf
" verbose
符合逻辑非标量,则不会致电fprintf
" verbose
不符合逻辑,则不会致电fprintf
" 我无法找到验证是否针对特定功能进行呼叫的方法。有任何想法吗?我唯一能想到的就是用我自己的函数模拟fprintf
,这个函数会影响MATLAB路径上的真实函数,它会以某种方式引发一个fprintfCalled
事件,该事件由测试代码监听什么时候打电话。这是唯一的方法吗?看起来像是矫枉过正。
或者我可能以错误的方式接近这个 - 也许我应该忘记测试所做的调用,而是直接测试vfprintf
的命令行和/或文件输出。但感觉就像我在测试fprintf
而不是vfprintf
。
也许我会过度思考,但我想改进我的测试实践,所以会很感激一些建议。谢谢!
答案 0 :(得分:2)
我认为在这一点上你真的有4种选择。我喜欢第四节,但我会仔细研究它们:
<强> VerboseArgumentsHolder.m 强>
classdef VerboseArgumentsHolder < handle
properties
Arguments = {};
end
end
<强> VerbosePrinterSpy.m 强>
classdef VerbosePrinterSpy
properties(Constant)
ArgumentsHolder = VerboseArgumentsHolder;
end
end
*(测试文件夹)/overloads/fprintf/fprintf.m *
function fprintf(varargin)
argHolder = VerbosePrinterSpy.ArgumentsHolder;
argHolder.Arguments = varargin;
end
<强> vfprintfTest.m 强>
classdef vfprintfTest < matlab.unittest.TestCase
methods(Test)
function testWhenScalarTrue(testCase)
import matlab.unittest.fixtures.PathFixture;
testCase.applyFixture(PathFixture(...
fullfile((test folder),'overloads','fprintf')));
argHolder = VerbosePrinterSpy.ArgumentsHolder;
argHolder.Arguments = {}; % reset values since this is global and stateful.
vfprintf(true,'dummy input');
testCase.verifyEqual(argHolder.Arguments, 'dummy input');
end
function testWhenScalarFalse(testCase)
testCase.applyFixture(PathFixture(...
fullfile((test folder),'overloads','fprintf')));
argHolder = VerbosePrinterSpy.ArgumentsHolder;
argHolder.Arguments = {}; % reset values
vfprintf(false,'dummy input');
testCase.verifyEmpty(argHolder.Arguments);
end
end
end
重构您的生产代码以具有打印界面,然后您可以添加特定于测试的间谍作为该界面。这是一种很好的方法,但对您的软件结构有一定的影响,可能并不容易调整,特别是如果您的代码库已经严重依赖于此实用程序。
由于您只是直接将varargin传递给fprintf,因此您可以使用fprintf方法创建一个test double来专门测试它。然后,fprintf调用将调度到您的测试特定类,它可以简单地监视输入。它可能看起来像这样:
<强> VerbosePrinterSpy.m 强>
classdef VerbosePrinterSpy < handle
properties
WasInvoked = false;
ArgumentsUsedInPrintCall = {'Not invoked'};
end
methods
function fprintf(spy, varargin)
spy.WasInvoked = false;
spy.ArgumentsUsedInPrintCall = varargin;
end
end
end
<强> vfprintfTest.m 强>
classdef vfprintfTest < matlab.unittest.TestCase
methods(Test)
function testWhenScalarTrue(testCase)
spy = VerbosePrinterSpy;
vfprintf(true, spy, 'dummy input');
testCase.verifyTrue(spy.WasInvoked);
testCase.verifyEqual(spy.ArgumentsUsedInPrintCall, 'dummy input');
end
function testWhenScalarFalse(testCase)
spy = VerbosePrinterSpy;
vfprintf(false, spy, 'dummy input');
testCase.verifyFalse(spy.WasInvoked);
end
end
end
希望有所帮助!