The real reset button for local mess fom tests: withr::deferred_run()

[This article was first published on Maëlle's R blog on Maëlle Salmon's personal website, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Following last week’s post on my testing workflow enhancements, Jenny Bryan kindly reminded me of the existence of an actual reset button when you’ve been interactively running tests that include some “local mess”: withr::local_envvar(), withr::local_dir(), usethis::local_project()… The reset button is withr::deferred_run().

It is documented in Jenny’s article about test fixtures:

Since the global environment isn’t perishable, like a test environment is, you have to call deferred_run() explicitly to execute the deferred events. You can also clear them, without running, with deferred_clear().

It is also mentioned in messages from withr.

For some reason it hadn’t clicked for me until now?! But now I know better!

Example: making a withr::local_ mess and wiping it with withr::deferred_run()

Imagine a test file1

test_that("My function works", {
  temp_dir <- withr::local_tempdir()
  withr::local_options(blop = TRUE)
  usethis::local_project(temp_dir, force = TRUE)
  withr::local_envvar("TEST_SWITCH" = "something")
  expect_something(my_function()) # not actual test code, you get the idea
})

Imagine the test fails and I run this in my R session probably after throwing a browser()2 somewhere and running devtools::load_all():

temp_dir <- withr::local_tempdir()
withr::local_options(blop = FALSE)
usethis::local_project(temp_dir, force = TRUE)
#> ✔ Setting active project to '/tmp/RtmpFH1MM4/file645e1b25d736'
withr::local_envvar("TEST_SWITCH" = "something")

Then I do the actual debugging. At the end my session is all messy!

Sys.getenv("TEST_SWITCH")
#> [1] "something"
getOption("blop")
#> [1] FALSE
usethis::proj_sitrep() # cool function!
#> •   working_directory: '/home/maelle/Documents/blog/simplymaelle/content/post/2023-10-16-deferred-run'
#> • active_usethis_proj: '/tmp/RtmpFH1MM4/file645e1b25d736'
#> • active_rstudio_proj: <unset>
#> • Your working directory is not the same as the active usethis project.
#>   Set working directory to the project: `setwd(proj_get())`
#>   Set project to working directory:     `proj_set(getwd())`

Instead of fixing each thing by hand I can run

withr::deferred_run()

And now all is right in my session again, you’ll have to believe me or run the example yourself: indeed, demonstrating all of this in a knitr document makes it a bit more challenging. I swear that outside of a knitr document, this all works even for code that changes the current directory!

Sys.getenv("TEST_SWITCH")
getOption("blop")
usethis::proj_get()

So I can go and debug the next failing test. 😸

What about rlang’s local mess?

rlang itself has rlang::local_interactive() and rlang::local_options(). Luckily they are reset by withr::deferred_run().

I’m not sure exactly where the compatibility comes from, maybe from the standalone defer script. In any case, that’s good news!

Conclusion

So, in summary, if you’re running test code interactively to debug them, and this test code changed some things using withr::local_ or other compatible local_ functions, to get back your session back to its initial state without restarting R, run withr::deferred_run()! Thanks Jenny for the reminder!


  1. Test switches are sooo handy. ↩︎

  2. For better debugging advice, refer to Shannon Pileggi’s materials! ↩︎

To leave a comment for the author, please follow the link and comment on their blog: Maëlle's R blog on Maëlle Salmon's personal website.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)