Changes

Jump to navigation Jump to search
4,204 bytes added ,  06:15, 18 March 2018
→‎Shared functions: "between" is only for two
Writing tests for function Having a thorough [https://en.wikipedia.org/wiki/Test_suite test suite] is an something very important thing that which is usually overlooked. It helps a lot is an incredible help in preventing regressionbugs and quickly assess the status of old code. There's a section For example, many packages in the Octave manual Forge become deprecated after losing their maintainer simply because they have no test suite. GNU Octave has multiple tools that help in creating a comprehensive test suite, accessible to both developers and end-users, as detailed on the [http://www.gnu.org/software/octave/doc/interpreter/Test-Functions.htmlOctave manual]. Basically, test blocks are {{codeline|%!test}} comment blocks, typically at the end of a source file, which are ignored by the Octave interpreter and only read by the {{manual|test}} function. == Running tests == To run all the tests of a specific function, simply use the {{manual|test}} command at the Octave prompt. For example, to run the tests of the Octave function {{manual|mean}} type:  >> test mean PASSES 17 out of 17 tests These tests are written in the Octave language [http://hg.savannah.gnu.org/hgweb/octave/file/6443693a176f/scripts/statistics/base/mean.m#Test-Functions Test Functionsl130 at the bottom of <code>mean.m</code>] which defines the {{manual|mean}} function. It is important that these tests are also available for the end users so they can test the status of their installation. The whole Octave test suite can be run with:  >> __run_test_suite__ Integrated test scripts: [...] Summary: PASS 11556 FAIL 3 XFAIL 6 SKIPPED 38 See the file test/fntests.log for additional details. To run tests in a specific file, one can simply specify the path instead of a function name:  test /full/path/to/file.m
== Writing tests ==
Octave provides for robust testing Tests appear as <code>%!</code> blocks at the bottom of functionsthe source file, together with <code>%!demo</code> blocks. The manual includes a section A typical m function file, will have the following structure: <syntaxhighlight lang="Octave">## Copyright#### A block with the copyright notice ## -*- texinfo -*-#### A block with the help text function [x, y, z] = foo (bar) ## some amazing codeendfunction %!assert (foo (1))%!assert (foo (1:10))%!assert (foo ("on "), "off")%!error <must be positive integer> foo (-1)%!error <must be positive integer> foo (1.5) %!demo%! ## see how cool foo() is:%! foo([1:100])</syntaxhighlight> Tests can be added to oct functions in the C++ sources just as easily, see[http://wwwhg.savannah.gnu.org/softwarehgweb/octave/docfile/f5ad7470d957/libinterp/corefcn/find.cc#l566 find.cc]for example. The syntax is exactly the same, but done within C comment blocks.During installation, these lines are automatically extracted from the sourcesand special test scripts are generated. A typical C++ source file has thefollowing structure: <syntaxhighlight lang="c++">//interpreterCopyright//// A block with the copyright notice DEFUN_DLD (foo, args, ,"-*- texinfo -*-\n\A block with the help text"){ // some amazing code} /Test*%!assert (foo (1))%!assert (foo (1:10))%!assert (foo ("on"), "off")%!error <must be positive integer> foo (-Functions1)%!error <must be positive integer> foo (1.html5)*/</syntaxhighlight> === Assert === {{codeline|%!assert}} lines are the simplest tests to write and also the mostcommon: <syntaxhighlight lang="Octave">%!assert (foo (bar)) # test fails if "foo (bar)" returns false%!assert (foo (bar), qux) #test fails if "foo (bar)" is different from "qux"</syntaxhighlight> These are actually a shorthand version of{{codeline|%!test assert (foo (bar))}}, and {{codeline|assert}} is simplyan Octave function that throws an error when two arguments fail to compare. === Test-Functions === While single {{codeline|%!assert}} lines are the most common used tests, {{codeline|%!test}} blocks offer more features and flexibility. The code within {{codeline|%!test}} blocks is simply processed through the Octave interpreter. If the code generates an error, the test is said to fail. Often {{codeline|%!test}} blocks end with a call to {{codeline|assert}}: <syntaxhighlight lang="Octave">%!test%! a = [0 1 0 0 3 0 0 5 0 2 1];%! b = [2 5 8 10 11];%! for i = 1:5%! assert (find (a, i), b(1:i))%! endfor</syntaxhighlight> ==== Test Functions]for no failure ==== In a few cases, there is the situation where a function returns nothing,and the only thing to test is that it causes no error. Several examples are included.This can be testedsimply with:
<syntaxhighlight lang===Declaring Functions Inside a Test Block==="Octave">%!test foo (bar)</syntaxhighlight>
Octave's ''test'' function automatically inserts the contents of each test block into a function. Although it is admittedly hacky=== Error /ugly, this implies that addition functions may be declared within a test block. For example, the empty function below named {{Codeline|experience}} is accompanied by a single test block which includes two function definitions.Warning ===
It is also important to test that a function experience () %!test %! experience_design_mat %! experience_obs_eqs %! assert (experience_design_mat == pi);performs its checks correctly %! assert (experience_obs_eqs == expand throws errors (1or warnings)); %! %! endfunction % this is a trickwhen it receives garbage. %! % now we This can declare functions to be used by the test above. %!done with %! function a = experience_design_mat %! a = pi; %! endfunction %! %! function b = experience_obs_eqs %! b = exp{{codeline|error}} (1or {{codeline|warning}}); %! % endfunctionblocks: don't add it here. Let test() do it.
<syntaxhighlight lang="Octave">%!error foo () # test that causes any error%!error <BAR must be a positive integer> foo (-1.5) # test that throws specific error message%!error id= Running Tests ==Octave:invalid-fun-call foo () # test that throws specific error id
Tests are run tests in m%!warning foo () # test that causes any warning%!warning <negative values might give inaccurate results> foo (-files by using the {{Codeline|1.5) # test}} function/commandthat triggers a specific warning message%!warning id=BAR:possibly-inaccurate-result foo (-1. 5) For example, to # test the {{Codeline|experience}} above use the command below.that triggers a specific warning id</syntaxhighlight>
test experience=== Shared functions ===
Or alternativelyIt is often useful to share a function among multiple tests. Sometimesthese are only small helper functions, use but more often these are just simplerlow performance implementations of the functional formfunction being tested. These arecreated in {{codeline|%!function}} blocks:
test (<syntaxhighlight lang="experienceOctave">%!function x = slow_foo (bar)%! ## a simple implementation of foo, definitely correct, but%! ## unfortunately too slow for anything other than tests.%!endfunction
To run tests in .cc files%!assert (foo (bar), the path to the file must be provided.slow_foo (bar))
%!test%! for i = -100:100%! test /full/path/tobar = qux (i);%! assert (foo (bar), slow_foo (bar))%! endfor</file.ccsyntaxhighlight>
[[Category:Testing]]
[[Category:Development]]
Anonymous user

Navigation menu