No BSD License  

Highlights from
MUnit: a unit testing framework in Matlab

MUnit: a unit testing framework in Matlab

by

 

05 Jun 2006 (Updated )

A complete unit testing framework in Matlab

testcollect(files,recursive)
function ts = testcollect(files,recursive)
% TESTCOLLECT  Collects tests in a set of testset from files
%
%  This function allows to create a complex test set from files and
% directories. The structure of the test set is defined from the directory
% arganization and from the filenames organization.
%
%  Params
%  ------
% IN:
%  files        =  A string related to an m file, or to a directory, or a
%                 cell containing strings. (def=pwd)
%  recursive    =  True to introspect recursively listed directories
%                 (def=true)

% Check for params:
if nargin<1 files=pwd; end
if nargin<2 recursive=true; end

% Get the name:
if isa(files,'char')
    [path,name,ext] = fileparts(files);
else
    name = 'Main';
end

% The testset can be created with a single call:
ts = CollectTests(files,recursive,name);

% ------------------------ LOCAL FUNCTIONS ------------------------

% Collects tests from a cell of strings:
function ts = CollectTests(files,recursive,name)

% Check if the set of files is reduced to a single filename:
if isa(files,'char')
    % Is it a directory?
    if isdir(files)
        % A directory must be treated a part!
        ts = CollectFromDir(files,recursive);
    else
        % A single file must be managed:
        ts = CollectFromFile(files);
    end
elseif isa(files,'cell')
    % Iteratively collects in a new testset:
    tests = cell(1,numel(files));
    for ind=1:numel(files)
        % A single testset is created:
        tests{ind} = CollectTests(files{ind},recursive, ...
            sprintf('%s%3.3d',name,ind));
    end
    % Now a testset can be generated:
    ts = testset(name,name,tests);
else
    % Cannot be of other types!
    error('Cell or filename required for testset collectioning!');
end

% -----------------------------------------------------------------

% Inspect a directory:
function ts = CollectFromDir(dirname,recursive)

% Obtain filenames in the directory:
files = dirfiles(dirname);

% Iterating on files and generating the filenames cell:
c = {};
for ind=1:size(files,2)
    % Skipping bad files:
    [path,name,ext] = fileparts(files{ind});
    if strcmp([name,ext],'.') || strcmp([name,ext],'..') || ...
       (not(recursive) && isdir(files{ind})) || ...
       not(isdir(files{ind}) || strcmpi(ext,'.m'))
        continue;
    end
    
    % Collecting:
    c = {c{:},files{ind}};
end

% All is collected... now the testset can be generated:
[path,name,ext] = fileparts(dirname);
ts = CollectTests(c,recursive,name);

% -----------------------------------------------------------------

% Inspect a file:
function ts = CollectFromFile(filename)

%  To generate a testset from a file a set of informations must be
% collected:

% The name of the test is the filename:
[path,name,ext] = fileparts(filename);

% The file have to exist:
fp = fopen(filename);
if fp<0 error(['Cannot find the file "',filename,'"!']); end

% The first line is read:
L = fgetl(fp);

% The file cannot be empty:
if ~ischar(L) error('Empty tests file!'); end

% If the first line is comment... than it is the description:
if L(1)=='%'
    desc = strtrim(L(2:numel(L)));
    L = fgetl(fp);
else
    desc = '<nodesc>';
end

% Iterating to collect functions:
lnames = {};
ldescs = {};
lfuncs = {};
callSetUp = 0;
callShoutDown = 0;
callReset = 0;
callDone = 0;
while ischar(L)
    % Get the index of the word 'function'
    pos = regexp(L, '^function\>');
    % Check the line to see if this is a function:
    if numel(pos)==1 && pos==1
        % This is a function, check the name:
        pos = regexp(L, '\<MUnitTest_');
        if numel(pos)>0
            % This is a test, get the name:
            lname = L(pos(1):numel(L));
            pos = regexp(lname, '\W');
            if numel(pos)>0
                lname = lname(1:pos(1)-1);
            end
            pos = findstr(lname, '_');
            lname = lname(pos+1:numel(lname));
            % The description can be the following line:
            L = fgetl(fp);
            if isa(L,'char') && L(1)=='%'
                ldesc = strtrim(L(2:numel(L)));
                L = fgetl(fp);
            else
                ldesc = '<nodesc>';
            end
            % Generating the function name:
            lfunc = ['MUnitTest_',lname];
            % Collecting:
            lnames = {lnames{:},lname};
            ldescs = {ldescs{:},ldesc};
            lfuncs = {lfuncs{:},lfunc};
            % Skip the line read:
            continue;
        elseif numel(regexp(L, '\<MUnitSetUp\>'))>0
            % Memorize the function name:
            callSetUp = 'MUnitSetUp';
        elseif numel(regexp(L, '\<MUnitShoutDown\>'))>0
            % Memorize the function name:
            callShoutDown = 'MUnitShoutDown';
        elseif numel(regexp(L, '\<MUnitReset\>'))>0
            % Memorize the function name:
            callReset = 'MUnitReset';
        elseif numel(regexp(L, '\<MUnitDone\>'))>0
            % Memorize the function name:
            callDone = 'MUnitDone';
        end
    end
    % Another line is read:
    L = fgetl(fp);
end

% Close the file:
fclose(fp);

% At least a single test is required:
if numel(lnames)==0
    error('At least a test function is required!');
end

% Generating the function handlers:
[path,testfunc,ext] = fileparts(filename);

% Generating tests callbacks:
if isa(callReset,'char')
    % Generating the handler:
    eval(['callReset = ',testfunc,'(callReset);']);
end
if isa(callDone,'char')
    % Generating the handler:
    eval(['callDone = ',testfunc,'(callDone);']);
end

% Generating tests:
tests = cell(1,numel(lnames));
for ind=1:numel(tests)
    % Creating the test:
    eval(['lfunc = ',testfunc,'(lfuncs{ind});']);
    tests{ind} = testunit(lfunc,{},lnames{ind},ldescs{ind});
    % Adding the callbacks:
    if isa(callReset,'function_handle')
        tests{ind} = addCallback(tests{ind},callReset,1);
    end
    if isa(callDone,'function_handle')
        tests{ind} = addCallback(tests{ind},callDone,2);
    end
end

% Generating the testset:
ts = testset(name,desc,tests);

% Generating the callbacks:
if isa(callSetUp,'char')
    % Adding the callback:
    eval(['callSetUp = ',testfunc,'(callSetUp);']);
    ts = addCallback(ts,callSetUp,3);
end
if isa(callShoutDown,'char')
    % Adding the callback:
    eval(['callShoutDown = ',testfunc,'(callShoutDown);']);
    ts = addCallback(ts,callShoutDown,4);
end

Contact us