n or Enter to execute current line, continue to next
c to run function from the current line to end
Q to quit
any variable, expression is evaluated in the current environment
undebug(<function-name>) to restore normal behavior
browser to set stop points when running code:
Add browser() command to code at strategic locations
Function will execute to browser and open debugger as above
Rstudio Debug menu: similar fucntionality, but can only be started for R scripts
Example
f1 =function(x, y, flag =TRUE, n =1000) {if ( missing(y) ) {if (flag | (x >0)) y =abs(x) } g =function(z) z + x acc =0## What happened to ?cumsum for (i in1:1000) acc = acc +runif(1) g(y)}
Run tests:
f1(1)f1(-1)f1(1, flag =FALSE)f1(-1, flag =FALSE)
Run traceback (not very useful)
Use debug to run the critical case line-by-line as far as practical
Note how the focus jumps between editor and console; editor has some decent Debug menu items, but inspection of local vars (e.g. ls()) is in the console
Add a browser() statement that allows you to pass over the loop (or use the menu item)
Fix the function, remove the browser if necessary & undebug
Minimal replicable example
Simplify any example that generates an error
Smallest self-contained set of data & code that generates the error reliably
Often finds the problem
Easier to read & understand on Stackoverflow etc.
Shows respect for other people’s time
Automated testing at build
Up until now, your workflow probably looks like this:
Write a function.
Load it with or devtools::load_all().
Experiment with it in the console to see if it works.
Go back to 1.
While this is testing, sometimes a more formal approach is better.
Let’s start by setting up our package to use the testthat: usethis::use_testthat().
Unit tests
Advantages:
Better code, you are explicit about how the code behaves
Better structure, many small components working together
Easier to start up, all your tests are documented in a script
Fearless development, don’t have to worry about unknowingly breaking something
Unit tests with testthat are defined in terms of expectations. The package provides a suite for functions that have the expect_ prefix that compare the values of different objects:
library(testthat)expect_equal(1, 1+1)
Error: 1 not equal to 1 + 1.
1/1 mismatches
[1] 1 - 2 == -1
expect_lt(1, 1+1)
General principles:
When you are tempted to write a “print” statement, write a test instead.
Write tests for complex code with lots of interdependencies