The RTest package shall allow you to write human readible test cases. If you wonder why to build human readible tests, you can read this blog entry.
Our package RTest is basically a wrapper around testthat functions. Instead of comparing two values by a function call, we will show you how to compare two values by an XML file. As a general principle, you can say, that you define the test case inside an XML file + a test-adapter R script. The test-adapter contains the "How to?" test, meaning the cuntion call and what to take out of the XML file. You do not neccesarily have to provide a test-adapter. RTest also provides you with a "generic" test adapter that will check the values inside your XML file and see what you want to test.
The XML file contains the parameters and reference values and the function you want to call. The function name can be the package function name or the test-adapter method name. All three combined make the call
reference %>% compare_to( function_call ( parameters ) )
The compare_to
part is what RTest provides you with.
The XML is handed over
to the RTest package, that calls testthat and
produces a nice report. Please see the figure below for the general principle.
# All defaults knitr::include_graphics("general_principle.jpg",dpi=NA)
This is a step by step guide how to build a test case. The final test case can be found under: RTest_TC-generic.xml
To show you how you can test some simple functions, a test collection was prepared as an example. We want to test 5 functions:
1) example_data_frame
- Adding up rowwise and multiplying the values
by a parameter called mult
.
2) example_image
- Returning the Roche Logo as a PNG by returning
a path
3) example_list
- Creates a list with one element called by the name_1
input parameter with the value "VALUE1", an element valled "NAME2" with the
value of the value_2
parameter and an element called "data.frame"
with a two column data.frame
4) example_vector
- Returns a vector containing the word "RTest" rep
times
5) example_value
- Returns (x-y)/(x)
These functions are set up within the RTest package and you can directly call them from within the package.
First an empty test case in RTest contains a synopsis and input-data:
<?xml version="1.0" encoding="UTF-8"?> <RTestCase xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../xsd/RTest.xsd"> <ID>RTest_TC-01</ID> <synopsis> <version>01</version> <author>Matthias Pfeifer</author> <short-description>RTest Template TC</short-description> <description> <![CDATA[ Extended Description of the test case allowing also <some><special>/characters ]]> </description> <creation-date>2016-01-25</creation-date> <change-history> <change author="Matthias Pfeifer" date="2016-01-25">Initial Version</change> </change-history> </synopsis> <input-data> <data.frame name="test01"> <col-defs> <coldef name="x" type="numeric" /> <coldef name="y" type="numeric" /> </col-defs> <row> <cell>1</cell> <cell>2</cell> </row> <row> <cell>1</cell> <cell>2</cell> </row> </data.frame> </input-data> <tests> ... </tests> </RTestCase>
As you can see, the XML file that we'll create links to the RTest.xsd. This allows to pre-write certain parts of the document and define structures, like "What does a data.frame look like?". To visualize XML and XSD we highly recommend using Altova XML Spy. The input data output we created here can be generated using:
my_data <- data.frame(x=c(1,2),y=c(1,2)) RTest::xmlWriteData_data.frame("data.frame",my_data,"test01")
To test the example_data_frame we want to use the input-data
part
test01
as an input. Therefore we define the test case as:
<example_data_frame test-desc="Test data.frame"> <params> <RTestData_input_data param="data" name="test01" /> <mult value="1" type="numeric" /> </params> ... </example_data_frame>
You can see that the RTestData_input_data
grabs the test01
element
from input-data
and hands it over to the data
argument of
example_data_frame
. Additionally we create a parameter called mult
with value 1.
Now we want to define a reference data.frame inside the XML and tell that the function shall be executed silently:
<example_data_frame test-desc="Test data.frame"> <params> <RTestData_input_data param="data" name="test01" /> <mult value="1" type="numeric" /> </params> <reference> <col-defs> <coldef name="x" type="numeric" /> <coldef name="y" type="numeric" /> <coldef name="sum" type="numeric" /> </col-defs> <row> <cell>1</cell> <cell>2</cell> <cell>3</cell> </row> <row> <cell>1</cell> <cell>2</cell> <cell>3</cell> </row> </reference> <testspec> <execution execution-type="silent" /> <return-value compare-type="equal" diff-type="absolute" tolerance="0.001" /> </testspec> </example_data_frame>
It shall be clear, that the reference
tag marks what the
function call shall be compared against. The testspec
tag
shows
1) in execution
how the execution of example_data_frame
shall
take place (silent, message, warning, error)
2) How the return value shall be compared, here with a tolerance
of 1E-3.
You can check all other definitions of the testspec
inside the
RTest.xsd file that can be found in file.path(find.package("RTest"),"xsd/RTest.xsd")
We will continue writing the function calls inside the XML after the same principe. You can check out the whole test in RTest_TC-generic.xml
To execute the test cases you just need to call the
RTest included function RTest.execute
. It let's you
choose where your test cases are located and what
shall be the name of the output file. If we now
want to perform this task for our described
5 Test cases we need to run:
library(magrittr) library(RTest) RTest::RTest.execute( testcase.directory = list.dirs(find.package('RTest'), recursive=TRUE) %>% grep(pattern="xml-templates",value=TRUE), open=FALSE, f.pattern = "RTest_TC-generic.xml" )
And you are done and will get a nice output.
# All defaults knitr::include_graphics("report_generic.jpg",dpi=NA)
DONE!
To use RTest for other packages you need to write your own xsd
file
and your own .xml
test cases. For the xsd
please use the
RTest.xsd
as a schema you can build on.
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.