Testing a Function That Uses Enquo() for a Null Parameter

Testing a function that uses enquo() for a NULL parameter

This problem doesn't really have to do with quo and enquo returning different things, it's really about evaluating objects before you really want to. If you were to use the browser() to step through your function, you'd see the error occurs at the if (is.null(new_var_name)) statement.

When you do is.null(new_var_name), you are evaluating the variable passed as new_var_name so it's too late to enquo it. That's because is.null needs to look at the value of the variable rather than just the variable name itself.

A function that does not evaluate the parameter passed to the function but checks to see if it is there is missing().

my_fun <- function(df, col_name, new_var_name=NULL) {
target <- enquo(col_name)

c <- df %>% pull(!!target) * 3 # here may be more complex calculations

# handling NULL name
if (missing(new_var_name)) {
new_name <- "default_name"
} else{
new_name <- quo_name(enquo(new_var_name))
}

data_frame(
abc = df %>% pull(!!target),
!!new_name := c
)
}

Then you can run both of these

my_fun(dataframe, a)
my_fun(dataframe, a, NEW_NAME)

How to test null or missing for enquos-type quosures

Use length(dot_vars) to determine if it has a length of 0.

Check if object is Null or undefined

{{ is the combination of enquo() and !! in one step. To inspect the contents of var, you need to decompose these two steps. enquo() defuses the argument and returns a quosure that you can inspect. !! injects the quosure into other calls.

Below we enquo() the argument at the start of the function. Inspect it with quo_is_null() (you could also use quo_get_expr() to see what's inside it). Then inject it inside group_by() with !!:

myfun <- function(dat, group = NULL, var = NULL) {
var <- enquo(var)

if (!quo_is_null(var)) {
print("It works!")
}

# Use `!!` instead of `{{` because we have decomposed the
# `enquo()` and `!!` steps that `{{` bundles
dat %>%
group_by({{ group }}, !!var) %>%
summarize(mean = mean(value), .groups = "drop")
}

Testing conditions on a function's parameter using testthat

testthat checks if the result of the function is what you expect.

If you want to test the result of the function to NAs, you can make a specific test for this :

library(testthat)
library(assertthat)

func <- function(expr,data.sizes) {
assert_that(noNA(data.sizes))
eval(expr)
}

test_that("data.sizes test for func", {
# Success
expect_error(func(expression(data.sizes[1]+data.sizes[2]), data.sizes = c(1,NA)))
expect_equal(func(expression(data.sizes[1]+data.sizes[2]), data.sizes = c(1,2)),3)
# Failure
expect_equal(func(expression(data.sizes[1]+data.sizes[2]), data.sizes = c(1,2)),4)
})

To test validity of parameters inside the function, you can use assertive programming packages like assertthat.

If/else condition in dplyr 0.7 function

The problem here is that when you supply unquoted arguments, is.null doesn't know what to do with it. So this code tries to check whether object B is null and errors because B does not exist in that scope. Instead, you can use missing() to check whether an argument was supplied to the function, like so. There may be a cleaner way but this at least works, as you can see at the bottom.

library(tidyverse)
test <- tibble(
A = c(1:5,1:5),
B = c(1,2,1,2,3,3,3,3,3,3),
C = c(1,1,1,1,2,3,4,5,4,3)
)

# begin function, set default for group var to NULL.
prop_tab <- function(df, column, group) {

col_name <- enquo(column)
group_name <- enquo(group)

# if group_by var is not supplied, then:
if(!missing(group)) {
temp <- df %>%
select(!!col_name, !!group_name) %>%
group_by(!!group_name) %>%
summarise(Percentages = 100 * length(!!col_name) / nrow(df))

} else {
# if group_by var is null, then...
temp <- df %>%
select(!!col_name) %>%
group_by(col_name = !!col_name) %>%
summarise(Percentages = 100 * length(!!col_name) / nrow(df))

}

temp
}

test %>% prop_tab(column = C) # works
#> # A tibble: 5 x 2
#> col_name Percentages
#> <dbl> <dbl>
#> 1 1 40
#> 2 2 10
#> 3 3 20
#> 4 4 20
#> 5 5 10

test %>% prop_tab(column = A, group = B)
#> # A tibble: 3 x 2
#> B Percentages
#> <dbl> <dbl>
#> 1 1 20
#> 2 2 20
#> 3 3 60

Created on 2018-06-29 by the reprex package (v0.2.0).



Related Topics



Leave a reply



Submit