patrick/0000755000176200001440000000000014745751405011723 5ustar liggesuserspatrick/tests/0000755000176200001440000000000014745016213013054 5ustar liggesuserspatrick/tests/testthat/0000755000176200001440000000000014745751405014725 5ustar liggesuserspatrick/tests/testthat/test-with_parameters.R0000644000176200001440000001402714745016213021216 0ustar liggesusers# Copyright 2018 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. with_parameters_test_that( "Running tests:", { if (test_outcome == "success") { testthat::expect_success(testthat::expect_true(case)) } else { failure_message <- "`case` (isn't true|is not TRUE)" testthat::expect_failure(testthat::expect_true(case), failure_message) } }, test_outcome = c("success", "fail", "null"), case = list(TRUE, FALSE, NULL), .test_name = c("success", "fail", "null") ) with_parameters_test_that( "Names are added", { testthat::expect_identical(.test_name, "case=TRUE") }, case = TRUE ) with_parameters_test_that( "Names can be extracted from cases", { testthat::expect_identical( .test_name, "logical=FALSE, number=1, string=hello" ) }, .cases = data.frame( logical = FALSE, number = 1, string = "hello", stringsAsFactors = FALSE ) ) with_parameters_test_that( "Cases are correctly evaluated:", { testthat::expect_length(vec, len) }, cases( one = list(vec = 1, len = 1), ten = list(vec = 1:10, len = 10) ) ) with_parameters_test_that( "Cases are correctly evaluated with names added:", { testthat::expect_identical(.test_name, "vec=1, len=1") }, cases(list(vec = 1, len = 1)) ) with_parameters_test_that( "Data frames can be passed to cases:", { result <- rlang::as_function(FUN)(input) testthat::expect_equal(result, out) }, .cases = tibble::tribble( ~.test_name, ~FUN, ~input, ~out, "times", ~ .x * 2, 2, 4, "plus", ~ .x + 3, 3, 6 ) ) with_parameters_test_that( "Patrick doesn't throw inappropriate warnings:", { testthat::expect_warning(fun(), regexp = message) }, cases( shouldnt_warn = list(fun = function() 1 + 1, message = NA), should_warn = list( fun = function() warning("still warn!"), message = "still warn" ) ) ) test_that("Patrick catches the right class of warning", { testthat::local_mocked_bindings( test_that = function(...) { rlang::warn("New warning", class = "testthat_braces_warning") } ) testthat::expect_warning( with_parameters_test_that( "No more warnings:", { testthat::expect_true(truth) }, truth = TRUE ), regexp = NA ) }) # From testthat/tests/testthat/test-test-that.R # Use for checking that line numbers are still correct expectation_lines <- function(code) { srcref <- attr(substitute(code), "srcref") if (!is.list(srcref)) { stop("code doesn't have srcref", call. = FALSE) } results <- testthat::with_reporter("silent", code)$expectations() unlist(lapply(results, function(x) x$srcref[1])) - srcref[[1]][1] } test_that("patrick reports the correct line numbers", { lines <- expectation_lines({ # line 1 with_parameters_test_that("simple", { # line 2 expect_true(truth) # line 3 }, # line 4 cases( true = list(truth = TRUE), false = list(truth = FALSE) )) }) expect_equal(lines, c(3, 3)) }) test_that('patrick gives a deprecation warning for "test_name"', { testthat::expect_warning( with_parameters_test_that( "Warn about `test_name` argument:", { testthat::expect_true(truth) }, truth = TRUE, test_name = "true" ), regexp = "deprecated" ) testthat::expect_warning( with_parameters_test_that( "Warn about `test_name` column:", { testthat::expect_true(truth) }, .cases = tibble::tribble( ~test_name, ~truth, "true", TRUE ) ), regexp = "deprecated" ) }) expectation_names <- function(code) { expectations <- testthat::with_reporter("silent", code)$expectations() vapply(expectations, function(e) as.character(e$test), character(1L)) } test_that("glue-formatted descriptions and test names supported", { expect_identical( expectation_names(with_parameters_test_that( "testing for (x, y, z) = ({x}, {y}, {z})", { testthat::expect_true(x + y + z > 0) }, x = 1:10, y = 2:11, z = 3:12 )), sprintf("testing for (x, y, z) = (%d, %d, %d)", 1:10, 2:11, 3:12) ) expect_identical( expectation_names(with_parameters_test_that( "testing for (x, y, z):", { testthat::expect_true(x + y + z > 0) }, x = 1:10, y = 2:11, z = 3:12, .test_name = "({x}, {y}, {z})" )), sprintf("testing for (x, y, z): (%d, %d, %d)", 1:10, 2:11, 3:12) ) expect_warning( expect_warning( expect_identical( expectation_names(with_parameters_test_that( "testing for (x, y): ({x}, {y})", { testthat::expect_equal(x, y) }, x = list(NULL, 1:10), y = list(NULL, 1:10) )), sprintf( "testing for (x, y): ({x}, {y}) x=%1$s, y=%1$s", c("NULL", toString(1:10)) ) ), "produced output of length 0" ), "produced output of length 10" ) # but fail kindly for potential accidental use of glue # c.f. https://github.com/r-lib/lintr/issues/2706 expect_error( with_parameters_test_that("a{b}", { expect_true(TRUE) }, .cases = data.frame(d = 1)), "Attempt to interpret test stub 'a{b}' with glue failed", fixed = TRUE ) # as well as an escape hatch to work around needing ugly escapes expect_no_error( with_parameters_test_that("a{b}", { expect_true(TRUE) }, .cases = data.frame(d = 1), .interpret_glue = FALSE) ) }) patrick/tests/testthat.R0000644000176200001440000000117114745016213015037 0ustar liggesusers# Copyright 2018 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. library(patrick) library(testthat) test_check("patrick") patrick/MD50000644000176200001440000000102314745751405012227 0ustar liggesusers96a320cf9df0a492e0a5e2145d59b2c3 *DESCRIPTION 5f9919c074c95379b6a0452548df0c85 *NAMESPACE 8d2b469e0e61be64406048b32dbb6574 *NEWS.md 9be6aceab5e8945d9d7a60a76d03ea0c *R/patrick-package.R 4069db640727fe731280becd39407e6a *R/with_parameters.R cf844cdc477e0841a844b8084c74d9f8 *README.md e4a94b744bf21e12e7be4b346916b268 *man/patrick-package.Rd be939f8d5b1a4c7789587afec1b7eaa9 *man/with_parameters_test_that.Rd 7d396051ec7db71be954bcac78dcd191 *tests/testthat.R e52a116bb049a9781dc03f64d62f6b73 *tests/testthat/test-with_parameters.R patrick/R/0000755000176200001440000000000014745016213012113 5ustar liggesuserspatrick/R/patrick-package.R0000644000176200001440000000250314745016213015264 0ustar liggesusers# Copyright 2018 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #' Parameterized Unit Testing #' #' `patrick` (parameterized testing in R is kind of cool!) is a `testthat` #' extension that lets you create reusable blocks of a test codes. Parameterized #' tests are often easier to read and more reliable, since they follow the DNRY #' (do not repeat yourself) rule. To do this, define tests with the function #' [with_parameters_test_that()]. Multiple approaches are provided for passing #' sets of cases. #' #' This package is inspired by parameterized testing packages in other #' languages, notably the #' [`parameterized`](https://github.com/wolever/parameterized) library in #' Python. #' @keywords internal #' @importFrom glue glue_data #' @importFrom testthat test_that #' @inherit with_parameters_test_that examples "_PACKAGE" patrick/R/with_parameters.R0000644000176200001440000001741714745016213015446 0ustar liggesusers# Copyright 2018 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #' Execute a test with parameters. #' #' This function is an extension of [testthat::test_that()] that lets you pass #' a series of testing parameters. These values are substituted into your #' regular testing code block, making it reusable and reducing duplication. #' #' You have a couple of options for passing parameters to you test. You can #' use named vectors/ lists. The function will assert that you have correct #' lengths before proceeding to test execution. Alternatively you can used #' a `data.frame` or list in combination with the splice unquote operator #' \code{\link[rlang]{!!!}}. Last, you can use the constructor `cases()`, which #' is similar to building a `data.frame` rowwise. If you manually build the #' data frame, pass it in the `.cases` argument. #' #' ## Naming test cases #' #' If the user passes a character vector as `.test_name`, each instance is #' combined with `desc_stub` to create the completed test name. Similarly, the #' named argument from `cases()` is combined with `desc_stub` to create the #' parameterized test names. When names aren't provided, they will be #' automatically generated using the test data. #' #' Names follow the pattern of "name=value, name=value" for all elements in a #' test case. #' #' @param desc_stub A string scalar. Used in creating the names of the #' parameterized tests. #' @param code Test code containing expectations. #' @param ... Named arguments of test parameters. All vectors should have the #' same length. #' @param .cases A data frame where each row contains test parameters. #' @param .test_name An alternative way for providing test names. If provided, #' the name will be appended to the stub description in `desc_stub`. If not #' provided, test names will be automatically generated. #' @param .interpret_glue Logical, default `TRUE`. If `FALSE`, and glue-like #' markup in `desc_stub` is ignored, otherwise [glue::glue_data()] is #' attempted to produce a more complete test description. #' @examples #' with_parameters_test_that("trigonometric functions match identities:", #' { #' testthat::expect_equal(expr, numeric_value) #' }, #' expr = c(sin(pi / 4), cos(pi / 4), tan(pi / 4)), #' numeric_value = c(1 / sqrt(2), 1 / sqrt(2), 1), #' .test_name = c("sin", "cos", "tan") #' ) #' #' # Run the same test with the cases() constructor #' with_parameters_test_that( #' "trigonometric functions match identities", #' { #' testthat::expect_equal(expr, numeric_value) #' }, #' cases( #' sin = list(expr = sin(pi / 4), numeric_value = 1 / sqrt(2)), #' cos = list(expr = cos(pi / 4), numeric_value = 1 / sqrt(2)), #' tan = list(expr = tan(pi / 4), numeric_value = 1) #' ) #' ) #' #' # If names aren't provided, they are automatically generated. #' with_parameters_test_that( #' "trigonometric functions match identities", #' { #' testthat::expect_equal(expr, numeric_value) #' }, #' cases( #' list(expr = sin(pi / 4), numeric_value = 1 / sqrt(2)), #' list(expr = cos(pi / 4), numeric_value = 1 / sqrt(2)), #' list(expr = tan(pi / 4), numeric_value = 1) #' ) #' ) #' # The first test case is named "expr=0.7071068, numeric_value="0.7071068" #' # and so on. #' #' # Or, pass a data frame of cases, perhaps using a helper function #' make_cases <- function() { #' tibble::tribble( #' ~.test_name, ~expr, ~numeric_value, #' "sin", sin(pi / 4), 1 / sqrt(2), #' "cos", cos(pi / 4), 1 / sqrt(2), #' "tan", tan(pi / 4), 1 #' ) #' } #' #' with_parameters_test_that( #' "trigonometric functions match identities", #' { #' testthat::expect_equal(expr, numeric_value) #' }, #' .cases = make_cases() #' ) #' @importFrom dplyr .data #' @export with_parameters_test_that <- function(desc_stub, code, ..., .cases = NULL, .test_name = NULL, .interpret_glue = TRUE) { stopifnot( is.logical(.interpret_glue), length(.interpret_glue) == 1L, !is.na(.interpret_glue) ) if (is.null(.cases)) { pars <- tibble::tibble(...) possibly_add_column <- purrr::possibly(tibble::add_column, otherwise = pars) all_pars <- possibly_add_column(pars, .test_name = .test_name) } else { all_pars <- .cases } # TODO: drop this once downstream users upgrade their version of patrick. if ("test_name" %in% names(all_pars)) { msg <- paste( 'The argument and cases column "test_name" is deprecated. Please use the', "new `.test_name` argument instead. See `?with_parameters_test_that`", "for more information" ) rlang::warn(msg, class = "patrick_test_name_deprecation") # It would be nicer to do this with rename(), but that function doesn't # support overwriting existing columns. all_pars <- dplyr::mutate( all_pars, .test_name = .data$test_name, test_name = NULL ) } if (!".test_name" %in% names(all_pars)) { all_pars$.test_name <- build_test_names(all_pars) } captured <- rlang::enquo(code) purrr::pmap( all_pars, build_and_run_test, desc = desc_stub, code = captured, .interpret_glue = .interpret_glue ) invisible(TRUE) } #' Generate test names from cases, if none are provided. #' #' @param all_cases A tibble containing test cases. #' @return A character vector, whose length matches the number of rows in #' `all_cases`. #' @noRd build_test_names <- function(all_cases) { case_names <- names(all_cases) purrr::pmap_chr(all_cases, build_label, case_names = case_names) } build_label <- function(..., case_names) { row <- format(list(...)) toString(sprintf("%s=%s", case_names, row)) } build_description <- function(args, desc, .test_name, .interpret_glue) { if (.interpret_glue) { completed_desc <- tryCatch(glue_data(args, desc), error = identity) if (inherits(completed_desc, "error")) { rlang::abort(sprintf( paste( "Attempt to interpret test stub '%s' with glue failed with error:\n%s\n\n", "Set .interpret_glue=FALSE if this test name does not use glue." ), # indent for clarity (the purrr error has similar mark-up) desc, gsub("(^|\n)", "\\1 ", conditionMessage(completed_desc)) )) } } else { completed_desc <- desc } desc_n <- length(completed_desc) if (desc_n != 1L || completed_desc == desc) { completed_desc <- paste(desc, .test_name) if (desc_n != 1L) { rlang::warn( paste("glue_data() on desc= produced output of length", desc_n) ) } else if (.interpret_glue) { completed_desc <- glue_data(args, completed_desc) } } completed_desc } build_and_run_test <- function(..., .test_name, desc, code, env, .interpret_glue) { args <- list(..., .test_name = .test_name) completed_desc <- build_description(args, desc, .test_name, .interpret_glue) withCallingHandlers( test_that(completed_desc, rlang::eval_tidy(code, args)), testthat_braces_warning = rlang::cnd_muffle ) } #' @rdname with_parameters_test_that #' @export cases <- function(...) { all_cases <- list(...) nested <- purrr::modify_depth(all_cases, 2L, list) dplyr::bind_rows( nested, .id = if (!is.null(names(nested))) ".test_name" ) } patrick/NAMESPACE0000644000176200001440000000026014745016213013127 0ustar liggesusers# Generated by roxygen2: do not edit by hand export(cases) export(with_parameters_test_that) importFrom(dplyr,.data) importFrom(glue,glue_data) importFrom(testthat,test_that) patrick/NEWS.md0000644000176200001440000000332714745023353013020 0ustar liggesusers# patrick (0.3.0) * Patrick can build test names as {glue}-formatted strings, e.g. ```r with_parameters_test_that( "col2hex works for color {color_name}", { expect_equal(col2hex(color_name), color_hex) }, color_name = c("red", "blue", "black"), color_hex = c("#FF0000", "#0000FF", "#000000") ) ``` This also works for supplying such a formatted string as `.test_name`. To disable this behavior, use `.interpret_glue = FALSE`. Thanks @chiricom! # patrick 0.2.0 ## New features * Patrick will try to generate names automatically if not provided. This also works when cases are provided as a data frame. # patrick 0.1.0 Breaking changes: * Setting test names should now happen with `.test_name`, instead of the implicit `test_name` variable from before. This is now an explicit argument for the function `with_parameters_test_that()`, and the leading dot should help distinguish this from values passed as cases. # patrick 0.0.4 Update `patrick` for testthat 3e. * Catch warnings for code not being braced. We still produce the right code. * Make sure patrick uses the right line numbers. # patrick 0.0.3 * Add more examples and tests for how patrick works with data frames. * Update `with_parameters_test_that()` to use [data, dots, details](https://design.tidyverse.org/dots-after-required.html#whats-the-pattern) * Modernize package files: DESCRIPTION and `R/patrick-package.R`. # patrick 0.0.2 * This is a minor update. Tests are compatible with the next version of `testthat`. # patrick 0.0.1 Welcome to `patrick`, a package for parameterizing tests within testthat. Check out the README.md file to learn more about this package. patrick/README.md0000644000176200001440000000720514745016213013175 0ustar liggesusers [![R-CMD-check](https://github.com/google/patrick/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/google/patrick/actions/workflows/R-CMD-check.yaml) [![CRAN](https://www.r-pkg.org/badges/version/patrick)](https://cran.r-project.org/package=patrick) # Introducing patrick This package is an extension to `testthat` that enables parameterized unit testing in R. ## Installing The release version of `patrick` is available on CRAN. Install it in the usual manner: ``` install.packages("patrick") ``` The development version of `patrick` is currently only available on GitHub. Install it using `devtools`. ``` devtools::install_github("google/patrick") ``` To use `patrick` as a testing tool within your package, add it to your list of `Suggests` within your package's `DESCRIPTION`. ``` Suggests: patrick ``` ## Use Many packages within R employ the following pattern when writing tests: ``` test_that("Data is a successfully converted: numeric", { input <- convert(numeric_data) expect_type(input, "double") }) test_that("Data is a successfully converted: character", { input <- convert(character_data) expect_type(input, "character") }) ``` While explicit, recycling a test pattern like this is prone to user error and other issues, as it is a violation of the classic DNRY rule (do not repeat yourself). `patrick` eliminates this problem by creating test parameters. ``` with_parameters_test_that("Data is successfully converted:", { input <- convert(test_data) expect_type(input, type) }, test_data = list(numeric_data, character_data), type = c("double", "character"), .test_name = type ) ``` Parameterized tests behave exactly the same as standard `testthat` tests. Per usual, you call all of your tests with `devtools::test`, and they'll also run during package checks. Each executes independently and then your test report will produce a single report. A complete name for each test will be formed using the initial test description and the strings in the `.test_name` parameter. Small sets of cases can be reasonably passed as parameters to `with_parameters_test_that`. This becomes less readable when the number of cases increases. To help mitigate this issue, `patrick` provides a case generator helper function. ``` with_parameters_test_that("Data is successfully converted:", { input <- convert(test_data) expect_type(input, type) }, cases( double = list(test_data = numeric_data, type = "double"), character = list(test_data = character_data, type = "character") ) ) ``` More complicated testing cases can be constructed using data frames. This is usually best handled within a helper function and in a `helper-.R` file. ``` make_cases <- function() { tibble::tribble( ~ .test_name, ~ expr, ~ numeric_value, "sin", sin(pi / 4), 1 / sqrt(2), "cos", cos(pi / 4), 1 / sqrt(2), "tan", tan(pi / 4), 1 ) } with_parameters_test_that( "trigonometric functions match identities", { testthat::expect_equal(expr, numeric_value) }, .cases = make_cases() ) ``` If you don't provide test names when generating cases, `patrick` will generate them automatically from the test data. ## Inspiration This package is inspired by parameterized testing packages in other languages, notably the [`parameterized`](https://github.com/wolever/parameterized) library in Python. ## Contributing Please read the [`CONTRIBUTING.md`](https://github.com/google/patrick/blob/master/CONTRIBUTING.md) for details on how to contribute to this project. ## Disclaimer This is not an officially supported Google product. patrick/man/0000755000176200001440000000000014745016213012465 5ustar liggesuserspatrick/man/with_parameters_test_that.Rd0000644000176200001440000000731514745016213020237 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/with_parameters.R \name{with_parameters_test_that} \alias{with_parameters_test_that} \alias{cases} \title{Execute a test with parameters.} \usage{ with_parameters_test_that( desc_stub, code, ..., .cases = NULL, .test_name = NULL, .interpret_glue = TRUE ) cases(...) } \arguments{ \item{desc_stub}{A string scalar. Used in creating the names of the parameterized tests.} \item{code}{Test code containing expectations.} \item{...}{Named arguments of test parameters. All vectors should have the same length.} \item{.cases}{A data frame where each row contains test parameters.} \item{.test_name}{An alternative way for providing test names. If provided, the name will be appended to the stub description in `desc_stub`. If not provided, test names will be automatically generated.} \item{.interpret_glue}{Logical, default `TRUE`. If `FALSE`, and glue-like markup in `desc_stub` is ignored, otherwise [glue::glue_data()] is attempted to produce a more complete test description.} } \description{ This function is an extension of [testthat::test_that()] that lets you pass a series of testing parameters. These values are substituted into your regular testing code block, making it reusable and reducing duplication. } \details{ You have a couple of options for passing parameters to you test. You can use named vectors/ lists. The function will assert that you have correct lengths before proceeding to test execution. Alternatively you can used a `data.frame` or list in combination with the splice unquote operator \code{\link[rlang]{!!!}}. Last, you can use the constructor `cases()`, which is similar to building a `data.frame` rowwise. If you manually build the data frame, pass it in the `.cases` argument. ## Naming test cases If the user passes a character vector as `.test_name`, each instance is combined with `desc_stub` to create the completed test name. Similarly, the named argument from `cases()` is combined with `desc_stub` to create the parameterized test names. When names aren't provided, they will be automatically generated using the test data. Names follow the pattern of "name=value, name=value" for all elements in a test case. } \examples{ with_parameters_test_that("trigonometric functions match identities:", { testthat::expect_equal(expr, numeric_value) }, expr = c(sin(pi / 4), cos(pi / 4), tan(pi / 4)), numeric_value = c(1 / sqrt(2), 1 / sqrt(2), 1), .test_name = c("sin", "cos", "tan") ) # Run the same test with the cases() constructor with_parameters_test_that( "trigonometric functions match identities", { testthat::expect_equal(expr, numeric_value) }, cases( sin = list(expr = sin(pi / 4), numeric_value = 1 / sqrt(2)), cos = list(expr = cos(pi / 4), numeric_value = 1 / sqrt(2)), tan = list(expr = tan(pi / 4), numeric_value = 1) ) ) # If names aren't provided, they are automatically generated. with_parameters_test_that( "trigonometric functions match identities", { testthat::expect_equal(expr, numeric_value) }, cases( list(expr = sin(pi / 4), numeric_value = 1 / sqrt(2)), list(expr = cos(pi / 4), numeric_value = 1 / sqrt(2)), list(expr = tan(pi / 4), numeric_value = 1) ) ) # The first test case is named "expr=0.7071068, numeric_value="0.7071068" # and so on. # Or, pass a data frame of cases, perhaps using a helper function make_cases <- function() { tibble::tribble( ~.test_name, ~expr, ~numeric_value, "sin", sin(pi / 4), 1 / sqrt(2), "cos", cos(pi / 4), 1 / sqrt(2), "tan", tan(pi / 4), 1 ) } with_parameters_test_that( "trigonometric functions match identities", { testthat::expect_equal(expr, numeric_value) }, .cases = make_cases() ) } patrick/man/patrick-package.Rd0000644000176200001440000000520114745017403016002 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/patrick-package.R \docType{package} \name{patrick-package} \alias{patrick} \alias{patrick-package} \title{Parameterized Unit Testing} \description{ `patrick` (parameterized testing in R is kind of cool!) is a `testthat` extension that lets you create reusable blocks of a test codes. Parameterized tests are often easier to read and more reliable, since they follow the DNRY (do not repeat yourself) rule. To do this, define tests with the function [with_parameters_test_that()]. Multiple approaches are provided for passing sets of cases. } \details{ This package is inspired by parameterized testing packages in other languages, notably the [`parameterized`](https://github.com/wolever/parameterized) library in Python. } \examples{ with_parameters_test_that("trigonometric functions match identities:", { testthat::expect_equal(expr, numeric_value) }, expr = c(sin(pi / 4), cos(pi / 4), tan(pi / 4)), numeric_value = c(1 / sqrt(2), 1 / sqrt(2), 1), .test_name = c("sin", "cos", "tan") ) # Run the same test with the cases() constructor with_parameters_test_that( "trigonometric functions match identities", { testthat::expect_equal(expr, numeric_value) }, cases( sin = list(expr = sin(pi / 4), numeric_value = 1 / sqrt(2)), cos = list(expr = cos(pi / 4), numeric_value = 1 / sqrt(2)), tan = list(expr = tan(pi / 4), numeric_value = 1) ) ) # If names aren't provided, they are automatically generated. with_parameters_test_that( "trigonometric functions match identities", { testthat::expect_equal(expr, numeric_value) }, cases( list(expr = sin(pi / 4), numeric_value = 1 / sqrt(2)), list(expr = cos(pi / 4), numeric_value = 1 / sqrt(2)), list(expr = tan(pi / 4), numeric_value = 1) ) ) # The first test case is named "expr=0.7071068, numeric_value="0.7071068" # and so on. # Or, pass a data frame of cases, perhaps using a helper function make_cases <- function() { tibble::tribble( ~.test_name, ~expr, ~numeric_value, "sin", sin(pi / 4), 1 / sqrt(2), "cos", cos(pi / 4), 1 / sqrt(2), "tan", tan(pi / 4), 1 ) } with_parameters_test_that( "trigonometric functions match identities", { testthat::expect_equal(expr, numeric_value) }, .cases = make_cases() ) } \seealso{ Useful links: \itemize{ \item \url{https://github.com/google/patrick} \item Report bugs at \url{https://github.com/google/patrick/issues} } } \author{ \strong{Maintainer}: Michael Quinn \email{msquinn@google.com} Other contributors: \itemize{ \item Michael Chirico \email{chiricom@google.com} [contributor] } } \keyword{internal} patrick/DESCRIPTION0000644000176200001440000000207714745751405013437 0ustar liggesusersPackage: patrick Title: Parameterized Unit Testing Version: 0.3.0 Authors@R: c( person(given = "Michael", family = "Quinn", role = c("aut", "cre"), email = "msquinn@google.com"), person(given = "Michael", family = "Chirico", role = "ctb", email = "chiricom@google.com")) Description: This is an extension of the 'testthat' package that lets you add parameters to your unit tests. Parameterized unit tests are often easier to read and more reliable, since they follow the DNRY (do not repeat yourself) rule. License: Apache License 2.0 URL: https://github.com/google/patrick BugReports: https://github.com/google/patrick/issues Depends: R (>= 3.1) Imports: dplyr, glue, purrr, rlang, testthat (>= 3.1.5), tibble Config/testthat/edition: 3 Encoding: UTF-8 RoxygenNote: 7.3.2 NeedsCompilation: no Packaged: 2025-01-27 18:29:07 UTC; rstudio Repository: CRAN Date/Publication: 2025-01-27 18:40:05 UTC Author: Michael Quinn [aut, cre], Michael Chirico [ctb] Maintainer: Michael Quinn