MATLAB unit testing a function call -


i have following simple utility function:

function vfprintf(verbose, varargin) % vfprintf display output optionally depending on level of verbosity. % % vfprintf(tf, args) passes arguments args built-in matlab % command |fprintf| if tf logical true. if tf logical false, vfprintf % nothing.  assert(islogical(verbose),...     'utils:invalidverbose',...     'verbose must logical true or false');  if verbose     fprintf(varargin{:}); end 

it turns out though function super simple, had issue caused me problem (the assert condition should have been islogical(verbose) && isscalar(verbose), not islogical(verbose)), i'd implement unit tests around it.

note don't want test fprintf - i'm assuming that's ok. there way can test like:

  • "if verbose logical scalar true, call made fprintf"
  • "if verbose logical scalar false, no call made fprintf"
  • "if verbose logical nonscalar, no call made fprintf"
  • "if verbose not logical, no call made fprintf"

i can't find way verify call made out particular function. ideas? thing can think of mock out fprintf own function shadows real 1 on matlab path, somehow raises fprintfcalled event listened testing code tell when it's called. approach? seems overkill.

or perhaps i'm approaching wrong way - maybe should forget testing calls made, , instead testing command-line and/or file output of vfprintf directly. feels i'm testing fprintf rather vfprintf.

maybe i'm overthinking things, i'd improve testing practices, appreciate advice. thanks!

i think @ point have 4 options. 4th, i'll run through them all:

  1. execute calls vfprintf within evalc validate printed command window or create file , print file. drawbacks 1: kind of tests fprintf (athough more academic since there low chance fprintf change or not honor contract). drawback 2: both cases interact global state - either global command window output (which other things can print to) or filesystem. not end of world, avoid if can. nicer test avoid touching outside world.
  2. shadow fprintf function. can putting in folder off path , adding own fprintf function in folder, using pathfixture in test add top of path. drawback: still relies on changing global state (the path) , may slower because path manipulation expensive language execution perspective. not big fan, here how might play out. if can i'd suggest going #4 below on this:

verboseargumentsholder.m

    classdef verboseargumentsholder < handle         properties             arguments = {};         end     end 

verboseprinterspy.m

    classdef verboseprinterspy         properties(constant)             argumentsholder = verboseargumentsholder;         end     end 

* (test folder)/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 global , 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 
  1. restructure production code have interface printing, can add test specific spy interface. nice approach, has implication on software structure may not easy adjust , if codebase heavily reliant on utility.

  2. since passing on varargin fprintf directly, can create test double fprintf method test out. then, fprintf call dispatch testing specific class can spy on inputs. may this:

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 

hope helps!


Comments

Popular posts from this blog

aws api gateway - SerializationException in posting new Records via Dynamodb Proxy Service in API -

asp.net - Problems sending emails from forum -