To evaluate student solutions written in R, you need to write tests using testthat.
All test files should have the test-
prefix.
Let's start with a basic exercise. Your student is to implement a hello_world()
function that returns the string "Hello World". For the sake of simplicity, it doesn't print anything.
Here is an example solution:
exercise.R
hello_world <- function() {'hello world'}
And this is an example test of the student's code:
test-exercise.R
setwd("..")source("exercise.R", chdir = TRUE)​library(testthat)​test_that("returns hello world string", {expect_equal(hello_world(), 'hello world')})
Let's examine the above test code.
setwd("..")
setwd
specifies a working directory. This allows us to source
the files without specifying the path.
source("exercise.R", chdir = TRUE)
source
causes R
to accept the input from the named file, so the tests know what function to run.
library(testthat)
It is used to load a testthat
package, that we use to run the tests.
test_that
This is a function provided by `testthat and is used to group individual tests together. The argument is a name of the test. See the reference here​
expect_equal
This is a function provided by testthat
compares the result of the code to an expected result. See a list of the expectations in the reference here​
Out test has a test case "returns hellow world string"
that asserts equality of "Hello world" string and the students' function output.
Let's change the previous example a little bit and ask students to print "Hello World" using several prints rather than returning the string.
Here is the example solution:
exercise.R
hello_world <- function() {print("Hello", quote=FALSE)print("World", quote=FALSE)}
And this is an example test of the student's code:
test-exercise.R
setwd("..")source("exercise.R", chdir = TRUE)​library(testthat)​test_that("prints hello world string", {expected <- "[1] Hello\n[1] World"actual <- capture_output(hello_world())​expect_equal(actual, expected)})
There can also be an alternative test for this exercise
test-exercise.R
setwd("..")source("exercise.R", chdir = TRUE)​library(testthat)​test_that("prints hello world string", {expected <- c("[1] Hello", "[1] World")actual <- capture_output_lines(hello_world())​expect_equal(actual, expected)})
There are a few differences between this exercise and the previous one:
We use print()
function to print the argument. We are using quote=FALSE
argument to remove the quote from printting, print prints quotes the output by default.
To verify the printed data in the first test, we use the capture_output
function that is provided by testthat
package. This function captures the output and returns a single string.
To verify the printed data in the second test, we use a capture_output_lines
function that returns a character vector with one entry for each line like this.
In the second test we use the c()
function to form a vector.
exercise.R
make_matrix <- function() {data <- matrix(1:4, 2, 2)​data}
And this is an example test of the student's code:
test-exercise.R
setwd("..")source("exercise.R", chdir = TRUE)​library(testthat)​test_that("can check a matrix", {actual <- make_matrix()​expected <- matrix(1:4, 2, 2)​expect_is(actual, "matrix")expect_equal(actual, expected)})
In the exercise we create the following 2x2 matrix:
[,1] [,2][1,] 1 3[2,] 2 4
And in the test we:
ensure that the function returned a matrix
ensure that the returned matrix matches the expected one
exercise.R
read_data <- function() {data <- read.csv('data.csv')​data}
data.csv
Name, Test1, Test2, Test3Test Student, 60, 73, 79
test-exercise.R
setwd("..")source("exercise.R", chdir = TRUE)​library(testthat)​test_that("can load from csv file", {actual <- read_data()expected <- data.frame("Name" = "Test Student", "Test1" = 60, "Test2" = 73, "Test3" = 79)​expect_is(actual, 'data.frame')​expect_equal(colnames(actual), colnames(expected))​expect_equal(dim(actual), dim(expected))​expect_equal(dim(merge(actual, expected)), dim(actual))})
Let's examine the exercise:
We are using read.csv
to read the data from csv-file. It returns a data frame.
Let's examine the unfamiliar parts of the test code.
data.frame("Name" = "Test Student", "Test1" = 60, "Test2" = 73, "Test3" = 79)
Here we create a data frame to test the result of our function against.
You can not compare two data frames directly, so this test has multiple steps
expect_is(actual, 'data.frame')
We check that the result of our function is of correct type data.frame
.
expect_equal(colnames(actual), colnames(expected))
We check that the column names of the result dataframe match the column names of the expected data frame.
expect_equal(dim(actual), dim(expected))
We check that the dimensions of the result dataframe match the dimensions of the expected data frame.
expect_equal(dim(merge(actual, expected)), dim(actual))
You could use expect_equal(actual, expected)
for small dataframes instead, but for the large ones we'll have to merge the expected data frame with the result data frame and check that the dimensions of result is the same.
The supported version of R language is 3.6.3.
We use testthat 2.3.1.
The list of bundled packages:
gdata 2.18.0
data.table 1.12.8
tidyverse 1.3.0
blob 1.2.1
DBI 1.1.0
dplyr 0.8.4
focats 0.4.0
ggplot2 3.2.1
glue 1.3.1
haven 2.2.0
hms 0.5.3
httr 1.4.1
jsonlite 1.6.1
magrittr 1.5
purr 0.3.3
readr 1.3.1
readxl 1.3.1
rvest 0.3.5
stringr 1.4.0
tibble 2.1.3
tidyr 1.0.2
lubridate 1.7.4
We do not support remotes
and devtools
libraries
We do not support install.packages
We do not support loading packages via http
or https