The following function accepts a numeric vector, and returns a list of up to three elements. Negative inputs appear in the element named -1
, zero inputs appear in the element 0
, and positive inputs appear in the element 1
.
split_by_sign <- function(x)
{
split(x, sign(x))
}
Write some unit tests for this function.
# your tests here
test_that(
"split_by_sign, with inputs -5:5, returns a list with elements -1, 0, 1",
{
expected <- list(`-1` = -5:-1, `0` = 0, `1` = 1:5)
actual <- split_by_sign(-5:5)
expect_equal(actual, expected)
}
)
The usual tests for failures.
test_that(
"split_by_sign, with a missing input, throws an error",
{
expect_error(
split_by_sign(),
'argument "x" is missing, with no default'
)
}
)
test_that(
"split_by_sign, a character input, throws an error",
{
expect_error(
split_by_sign("x"),
"non-numeric argument to binary operator"
)
}
)
## Error: Test failed: 'split_by_sign, a character input, throws an error'
## Not expected: split_by_sign("x") does not match 'non-numeric argument to binary operator'. Actual value: "Error in sign(x) : non-numeric argument to mathematical function\n".
What happens if not all the sign categories are present?
test_that(
"split_by_sign, with inputs 1:10, returns a list with elements -1, 0, 1",
{
expected <- list(`-1` = numeric(), `0` = numeric(), `1` = 1:10)
actual <- split_by_sign(1:10)
expect_equal(actual, expected)
}
)
## Error: Test failed: 'split_by_sign, with inputs 1:10, returns a list with elements -1, 0, 1'
## Not expected: actual not equal to expected
## Names: 1 string mismatch
## Length mismatch: comparison on first 1 components
## Component 1: Numeric: lengths (0, 10) differ.
Based upon your experience writing these tests, can you improve the function to make it easier to test and to use?
I think it would be easier if the elements (-1
, 0
, 1
) were always present in the return value. We can enforce this by converting the return value from sign to be a factor.
# modify this function
split_by_sign2 <- function(x)
{
split(x, factor(sign(x), levels = -1:1))
}
# now include some tests
test_that(
"split_by_sign2, with inputs 1:10, returns a list with elements -1, 0, 1",
{
expected <- list(`-1` = numeric(), `0` = numeric(), `1` = 1:10)
actual <- split_by_sign2(1:10)
expect_equal(actual, expected)
}
)