1. Exploring expect statements
Welcome back.
2. Most common expect statements
Let's explore creating unit tests with expect statements, which serve as the basis for validating the behavior of R functions, which we can think of as units.
These are the most common expectations also known as expect statements from the testthat package.
expect_equal is used to compare two objects for equality, allowing a small tolerance for numerical differences. This can be helpful to prevent rounding errors from causing the expectation to fail.
With expect_identical, we can check if two objects are exactly equal, with no tolerance for differences.
expect_output allows us to test if any portion of the text output produced by a specific object matches an expected pattern.
Use expect_error to verify that a specific object expression throws an error when executed. Remember that errors halt code execution whereas warnings don't.
With expect_warning, we can check if a particular object expression produces a warning.
3. From example to unit test
It's often easiest if we are just getting started with writing unit tests to convert examples into them.
An example we could have added to the temp_converter roxygen2 header @examples portion would show how to convert 32 degrees Fahrenheit into Celsius. The result is 0 degrees Celsius.
Our expectations are stored in a file for each function. For temp_converter, they would be in the tests-slash-testhat-test-temp_converter-dot-R file.
We'll use the expect_equal function.
Its first argument is the example R code to test as an object.
Its second argument is what we expect the output of the function call to be, 0.
When we run this, we get no output. It will only provide output if there are issues with object and expected not matching.
4. Expecting identical and expecting equal
When comparing numerical values like our temperature conversions, it is best to use expect_equal when checking for sameness of object and expected.
A similar expectation is expect_identical. Let's see what happens if we try to square the square root of three and compare that to the value of three. We get an error.
Running the same test with expect_equal produces no output, denoting a successful test.
expect_equal is not as conservative in its comparison as expect_identical. It has a tolerance argument that has a default that works in most situations, but can be changed.
5. Expecting output
expect_output will check to see if the expected text argument is contained in the text output, without it being a perfect match.
It can be used for checking the output of a function that returns text.
Its first argument is an expression. Here we print a message.
Its second argument is the text expression we'd like to check in our output. Here we check for funk.
This returns an error since funk is not in our output.
6. Expecting warning
If we expect our code to produce a warning, we use the expect_warning function. For the temp_converter function, it will return a warning if the unit_from and unit_to arguments are either both Celsius or both Fahrenheit.
This will produce no output since the warning is what is expected, but would have produced a message if no warning was outputted.
7. Expecting error
If our code is expected to produce an error, we use the expect_error function. For temp_converter, it will return an error and stop any analysis if the unit_from or unit_to arguments are not Celsius or Fahrenheit.
This will produce no output since the error is what is expected because our code doesn't work for Kelvin conversion.
8. Recap
We should have expectations for any edge cases as well as testing core functionality. Ideally, expectations are written to test all of the functionality of our code. We want to get to as close as we can to 100 percent test coverage of our package. This ensures our package behaves in the way we expect and bugs are reduced to a minimum.
9. Let's practice!
Next check to see if your functions give what you expect.