Editing Tests

Jump to navigation Jump to search

Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. If you log in or create an account, your edits will be attributed to your username, along with other benefits.

The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then save the changes below to finish undoing the edit.

Latest revision Your text
Line 1: Line 1:
Having a thorough [https://en.wikipedia.org/wiki/Test_suite test suite] is something very important which is usually overlooked. It is an incredible help in preventing regression bugs and quickly assess the status of old code.  For example, many packages in Octave Forge become deprecated after losing their maintainer simply because they have no test suite.
+
= Tests =
 
+
Writing tests for function is an important thing that is usually overlooked. It helps a lot in preventing regression.
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.html Octave 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#l130 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 ==
 
== Writing tests ==
 +
=== in .m files ===
 +
=== in .cc files ===
 +
===declaring functions inside a test block===
  
Tests appear as <code>%!</code> blocks at the bottom of the source file, together with <code>%!demo</code> blocks. A typical m function file, will have the following structure:
+
  function experience
 
+
%!test
<syntaxhighlight lang="Octave">
+
  %! experience_design_mat
## Copyright
+
%! experience_obs_eqs
##
+
%! assert (experience_design_mat == pi);
## A block with the copyright notice
+
%! assert (experience_obs_eqs == exp(1));
 
+
  %!
## -*- texinfo -*-
+
  %! endfunction % this is a trick.
##
+
  %! % now we can declare functions to be used by the test above.
## A block with the help text
+
  %!
 
+
%! function a = experience_design_mat
function [x, y, z] = foo (bar)
+
%!     a = pi;
  ## some amazing code
+
  %! endfunction
endfunction
+
%!
 
+
%! function b = experience_obs_eqs
%!assert (foo (1))
+
%!     b = exp(1);
%!assert (foo (1:10))
+
%! % endfunction: don't add it here. Let test() do it.
%!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://hg.savannah.gnu.org/hgweb/octave/file/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 sources
 
and special test scripts are generated.  A typical C++ source file has the
 
following structure:
 
 
 
<syntaxhighlight lang="c++">
 
// Copyright
 
//
 
// A block with the copyright notice
 
 
DEFUN_DLD (foo, args, ,
 
"-*- texinfo -*-\n\
 
A block with the help text")
 
{
 
  // some amazing code
 
}
 
   
 
/*
 
%!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)
 
*/
 
</syntaxhighlight>
 
 
 
=== Assert ===
 
 
 
{{codeline|%!assert}} lines are the simplest tests to write and also the most
 
common:
 
 
 
<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 simply
 
an Octave function that throws an error when two arguments fail to compare.
 
 
 
=== Test ===
 
 
 
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 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. This can be tested
 
simply with:
 
 
 
<syntaxhighlight lang="Octave">
 
%!test foo (bar)
 
</syntaxhighlight>
 
 
 
=== Error / Warning ===
 
 
 
It is also important to test that a function performs its checks correctly
 
and throws errors (or warnings) when it receives garbage. This can be done with
 
{{codeline|error}} (or {{codeline|warning}}) blocks:
 
 
 
<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=Octave:invalid-fun-call foo () # test that throws specific error id
 
 
 
%!warning foo ()  # test that causes any warning
 
%!warning <negative values might give inaccurate results> foo (-1.5)  # test that triggers a specific warning message
 
%!warning id=BAR:possibly-inaccurate-result foo (-1.5)  # test that triggers a specific warning id
 
</syntaxhighlight>
 
 
 
=== Shared functions ===
 
 
 
It is often useful to share a function among multiple tests. Sometimes
 
these are only small helper functions, but more often these are just simpler
 
low performance implementations of the function being tested. These are
 
created in {{codeline|%!function}} blocks:
 
 
 
<syntaxhighlight lang="Octave">
 
%!function x = slow_foo (bar)
 
%! ## a simple implementation of foo, definitely correct, but
 
%! ## unfortunately too slow for anything other than tests.
 
%!endfunction
 
 
 
%!assert (foo (bar), slow_foo (bar))
 
 
 
%!test
 
%! for i = -100:100
 
%!   bar = qux (i);
 
%!   assert (foo (bar), slow_foo (bar))
 
%! endfor
 
</syntaxhighlight>
 
  
[[Category:Testing]]
+
== running tests ==
[[Category:Development]]
+
=== from m files ===
 +
=== from .cc files ===
 +
You can run tests in .cc files by doing something like
 +
  test /full/path/to/file.cc

Please note that all contributions to Octave may be edited, altered, or removed by other contributors. If you do not want your writing to be edited mercilessly, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource (see Octave:Copyrights for details). Do not submit copyrighted work without permission!

To edit this page, please answer the question that appears below (more info):

Cancel Editing help (opens in new window)

Templates used on this page: