10

I am building a package which works with data.table and which should be tested using package testthat. While the code works fine when calling from the command line, I run into issues when calling from a test case. It seems that the [] function from the base package, i.e. the function for data.frames is used when running the tests.

I have created a minimum example which can be found here: https://github.com/utalo/test_datatable_testthat

The package contains a single function:

test <- function() {
   dt <- data.table(MESSAGE="Test 1234567890",TYPE="ERROR")
   dt[,.(MESSAGE=strwrap(MESSAGE,width = 10)),by=.(TYPE)]
}

When calling test.datatable.testthat:::test() from the command line I get the expected result:

    TYPE    MESSAGE
 1: ERROR       Test
 2: ERROR 1234567890

However, when executing the following unit test:

test_that("Test package",{
  dt <- test()

  expected_res <- structure(list(TYPE = c("ERROR", "ERROR"),
                             MESSAGE = c("Test","1234567890")),
                        row.names = c(NA, -2L), class = c("data.table","data.frame"),
                        .Names = c("TYPE", "MESSAGE"))

  expect_equal(dt,expected_res)
})

I get an error:

1
1. Error: Test package -------------------------------------------------------------------------------------------------------
could not find function "."
1: withCallingHandlers(eval(code, new_test_environment), error = capture_calls, message = function(c) invokeRestart("muffleMessage"))
2: eval(code, new_test_environment)
3: eval(expr, envir, enclos)
4: test() at test.R:4
5: dt[, .(MESSAGE = strwrap(MESSAGE, width = 10)), by = .(TYPE)] at test.datatable.testthat/R/hello.R:5
6: `[.data.table`(dt, , .(MESSAGE = strwrap(MESSAGE, width = 10)), by = .(TYPE)) at C:\Users\D057806\Documents\R\test.datatable.testthat/R/hello.R:5
7: `[.data.frame`(x, i, j)

As you can see, within the test the [] of data.frame is called. My first guess was that the dependency to the data.table package is not declared correctly. This is my DESCRIPTION file:

Package: test.datatable.testthat
Type: Package
Title: What the Package Does (Title Case)
Version: 0.1
Date: 2016-04-07
Authors@R: person("First", "Last", email = "first.last@example.com", role = c("aut", "cre"))
Description: More about what it does (maybe more than one line)
License: What license is it under?
LazyData: TRUE
Depends:
    data.table
Suggests:
     testthat
RoxygenNote: 5.0.1

According to Using data.table package inside my own package it should be sufficient to declare data.table as a dependent package. However, this does not seem to be the case here.

Any clues as to why my function is working when being called directly but not in the context of testthat?

Community
  • 1
  • 1
utal
  • 101
  • 4
  • 2
    Does the issue persist if you *import* data.table, and add `import(data.table)` to your namespace? I ask because [this post](http://stackoverflow.com/a/23279604/559784) comes to mind.. and I'm guessing it's the same issue with `testthat`. – Arun Apr 11 '16 at 15:51
  • @Arun Thanks for the pointer! This seems to be part of the issue. If I change the depends statement to import it works in the test example, however not in my original code. I will try to reproduce this behavior also in the example. – utal Apr 11 '16 at 16:11
  • 1
    That's new.. Did you also add import(data.table) to your NAMESPACE? – Arun Apr 11 '16 at 16:20
  • Yes, I did. I could in the meanwhile fix the issues in the original coding. For some reason, one of my data.tables became a list after applying rbind and even after applying setDT it was still a list. I had to explicitely copy and cast to a data.table using as.data.table. I'm trying to reproduce this also in the example. – utal Apr 14 '16 at 12:40
  • @utal is it still an issue for you with recent versions of testthat and data.table? is my answer applicable? – jangorecki Jun 13 '20 at 19:15

2 Answers2

1

To long for comment so posting as answer.

  1. Don't use underscore in package name, it breaks the standard. Underscores will be turned to dots.

  2. Can't really tell you why testthat failed to process your test. You can try to export test function. It is not exported so should be used only with ::: explicitly. Maybe testthat depends on that in some way, don't know.

  3. Test is passing when I move tests out of testthat. If you fail to resolve it I would look for support in testthat issues.

You can see my fork jangorecki/test_datatable_testthat of your pkg (url won't work in few days from now so fetch the changes if you want to access them later).
Your test moved out of testthat is in tests/test.R, content below.

dt <- test.datatable.testthat:::test()
expected_res <- structure(list(TYPE = c("ERROR", "ERROR"),
                               MESSAGE = c("Test","1234567890")),
                          row.names = c(NA, -2L), class = c("data.table","data.frame"),
                          .Names = c("TYPE", "MESSAGE"))
stopifnot(all.equal(dt,expected_res))

Testthat test is suppressed by changing it to dummy, kind of TRUE==TRUE. Now your test defined outside of testthat pass OK.
Related part from 00check.log:

* checking tests ...
  Running ‘test.R’
  Running ‘testthat.R’
 OK
* DONE
jangorecki
  • 16,384
  • 4
  • 79
  • 160
  • ad 2. I have successfully tested non-exported functions before, so I do not expect the issue to be there. ad 3. I had a look at testthat issues. There seems to be a discussion around whether the related issue https://github.com/hadley/devtools/issues/192 is resolved or not, e.g. here http://stackoverflow.com/questions/23252231/r-data-table-breaks-in-exported-functions – utal Apr 11 '16 at 12:46
  • @utal consider accepting answer, otherwise please provide feedback why it doesn't address your question – jangorecki Jun 08 '21 at 11:09
0

See this issue to learn of the complicated history of testthat and data.table. The good news is, it is solved.

This data.table vignette is very helpful

Testing using testthat

It is very common to use the testthat package for purpose of tests. Testing a package that imports data.table is no different from testing other packages. An example test script tests/testthat/test-pkg.R:

context("pkg tests")

test_that("generate dt", { expect_true(nrow(gen()) == 100) }) test_that("aggregate dt", { expect_true(nrow(aggr(gen())) < 100) })

If data.table is in Suggests (but not Imports) then you need to declare .datatable.aware=TRUE in one of the R/* files to avoid “object not found” errors when testing via testthat::test_package or testthat::test_check.

Soren Havelund Welling
  • 1,823
  • 1
  • 16
  • 23