testthat_translate_file

0th

Percentile

Convert a testthat Test File to a unitizer

Converts a copy of an existing testthat test file to a unitizer test file and test store, or a directory of such files to a corresponding unitizer directory. See examples.

Usage
testthat_translate_file(file.name, target.dir = file.path(dirname(file.name),
  "..", "unitizer"), state = getOption("unitizer.state"),
  keep.testthat.call = TRUE, prompt = "always",
  interactive.mode = interactive(), ...)

testthat_translate_dir(dir.name, target.dir = file.path(dir.name, "..", "unitizer"), filter = "^test.*\\.[rR]", state = getOption("unitizer.state"), keep.testthat.call = TRUE, force = FALSE, interactive.mode = interactive(), ...)

testthat_translate_name(file.name, target.dir = file.path(dirname(file.name), "..", "unitizer"), name.new = NULL, name.pattern = "^(?:test\\W*)?(.*)(?:\\.[rR])$", name.replace = "\\1")

Arguments
file.name

a path to the testthat test file to convert

target.dir

the directory to create the unitizer test file and test store in; for testthat_translate_file only: if NULL will return as a character vector what the contents of the translated file would have been instead of writing the file

state

what state control to use (see same argument for unitize)

keep.testthat.call

whether to preserve the testthat call that was converted, as a comment

prompt

character(1L):

  • "always" to always prompt before writing new files

  • "overwrite" only prompt if existing file is about to be overwritten

  • "never" never prompt

interactive.mode

logical(1L) primarily for testing purposes, allows us to force prompting in non-interactive mode; note that unitize and unitize_dir are always called in non-interactive mode by these functions, this parameter only controls prompts generated directly by these functions.

...

params to pass on to testthat_translate_name

dir.name

a path to the testthat directory to convert

filter

regular expression to select what files in a director are translated

force

logical(1L) whether to allow writing to a target.dir that contains files (implies prompt="never" when testthat_translate_dir runs testthat_translate_file)

name.new

character(1L) the base name for the unitizer files; do not include an extension as we will add it (".R" for the testfile, ".unitizer" for the data directory); set to NULL to generate the name from the testthat file name

name.pattern

character(1L) a regular expression intended to match the testthat test file name (see name.replace) if name.pattern matches, then the new file name will be constructed with this (used as replace parameter to sub); in addition we will add ".R" and ".unitizer" as the extensions for the new files so do not include extensions in your name.replace parameter

name.replace

character(1L) the replacement token, typically would include a "\1" token that is filled in by the match group from name.pattern

Value

a file path or a character vector (see target.dir)

Note

In order for the conversion to succeed testthat must be installed on your system. We do not rely on NAMESPACE imports to avoid an import dependency on testthat that is only required for these ancillary functions, especially since none of the testthat functions are called. We use the functions as the definition argument of match.call to find the object argument.

Translation of testthat is not strictly necessary; you can just copy them to a new location and unitize them. unitizer will just capture the results of the expect_* functions and will alert you if those change. You can then just review the tests that change. While this may seem pointless, one benefit is that you are dropped into the environment of the test that failed, so you can inspect variables, etc. without further ado.

Disclaimers

If you already have an extensive test suite in testthat and you do not intend to modify your tests or code very much there is little benefit (and likely some drawbacks) to migrating your tests to unitizer. Please see the introduction vignette for a (biased) view of the pros and cons of unitizer relative to testthat.

These translation functions are provided for your convenience. The unitizer author does not use them very much since he seldom needs to migrate testthat tests. As a result, they have not been tested as thoroughly as the rest of unitizer. Translation is designed to work for the most common testthat use cases, but may not for yours. Make sure you review the resulting unitizers to make sure they contain what you expect before you start relying on them. This is particularly important if your testthat test files are not meant to be run stand-alone with just test_file (see "Differences That May Cause Problems").

Note you can also unitize your testthat files without translating them (see notes).

Workflow

  1. Start a fresh R session

  2. Run your testthat tests with test_dir to ensure they are still passing. If your tests are are runnable only via test_check because they directly access the namespace of your package, see "Differences That May Cause Problems" below

  3. Run testthat_dir_translate

  4. [optional] use review to review the resulting unitizer(s)

We recommend using testthat_translate_dir over testthat_translate_file because the former also copies and loads any helper files that may be defined. Since libraries used by multiple test files are commonly loaded in these helper files, it is likely that just translating a single file without also copying the helper files will not work properly.

How the Conversion Works

We start by identifying calls to exported testthat functions that have an object argument. Generally speaking this includes functions of the form expect_* (e.g. expect_equal). We then extract the object parameter and replace the original expect_* statement with just the object parameter. For example

expect_equal(my_fun(25), 1:10)

becomes

my_fun(25)

Not all expect_* functions are substituted. For example, expect_is and expect_that are left unchanged because the tests for those functions do not or might not actually test the values of object. For example, expect_is tests the class of object. It is perfectly fine to unitize an expect_* call unsubstituted. unitizer captures conditions, values, etc., so if an expect_* test starts failing, it will be detected.

unitizer will then evaluate and store the results of such expressions. Since in theory we just checked our testthat tests were working, presumably the re-evaluated expressions will produce the same values. Please note that the translation process does not actually check this is true (see "Differences That May Cause Problems") so reviewing the results is a good idea.

test_that calls are converted to unitizer_sect calls, and the contents thereof are processed as described above. Calls to context are commented out since there currently is no unitizer equivalent. Other testthat calls are left unchanged and their return values used as part of the unitizer tests.

Only top level calls are converted. For example, code like for(i in 1:10) expect_equal(my_fun(i), seq(i)) or even (expect_equal(my_fun(10), 1:10)) will not be converted since expect_equal is nested inside a for and ( respectively. You will need to manually edit these calls (or just let them remain as is, which is not an issue).

We identify calls to extract based purely on the function symbols (i.e. we do not check whether expect_equal actually resolves to testthat::expect_equal in the context of the test file).

The unitizer files will be created in a sibling folder to the folder containing the testthat files. The names of the new files will be based on the old files. See params target.dir, name.new, name.pattern, and name.replace for more details. We encourage you to try the default settings first as those should work well in most cases.

When using testthat_translate_dir, any files that match "^helper.*[rR]$" are copied over to a '/_pre' subdirectory in "target.dir", and are pre-loaded by default before the tests are unitized.

unitizer Differences That May Cause Problems

If you run your tests during development with test_dir odds are the translation will work just fine. On the other hand, if you rely exclusively on test_check you may need to use state=unitizerStateNoOpt(par.env="pkgName") when you translate to make sure your tests have access to the internal namespace functions. See unitizerState for details on how to modify state tracking.

If your tests were translated with the state parameter changed from its default value, you will have to use the same value for that parameter in future unitize or unitize_dir runs.

See Also

unitize, unitizerState

Aliases
  • testthat_translate_file
  • testthat_translate_name
  • testthat_translate_dir
  • testthat_translate_dir
  • testthat_translate_name
Examples
# NOT RUN {
library(testthat)  # required
testthat_translate_file("tests/testthat/test-random.R")

# Translate `dplyr` tests (assumes `dplyr` source is in './dplyr')
# Normally we would use default `state` value but we cannot in this case
# due to conflicting packages and setup

testthat_translate_dir(
  "dplyr/tests/testthat", state=unitizerStateSafe(par.env="dplyr")
)
# Make sure translation worked (checking one file here)
# *NOTE*: folder we are looking at has changed

review("dplyr/tests/unitizer/summarise.unitizer")

# Now we can unitize any time we change our code

unitize_dir(
  "dplyr/tests/unitizer", state=unitizerStateSafe(par.env="dplyr")
)
# }
Documentation reproduced from package unitizer, version 1.4.3, License: GPL (>= 2)

Community examples

Looks like there are no examples yet.