Nothing
# Tests for verify_precision() - Phase 4
# Precision verification against manufacturer claims
# Test Data Setup ----
#' Create simple test data for verification
#' @noRd
create_verification_data <- function(seed = 42, n = 25, mean_val = 100, sd = 3.5) {
set.seed(seed)
rnorm(n, mean = mean_val, sd = sd)
}
#' Create precision study data for verification testing
#' @noRd
create_prec_study_data <- function(seed = 42, mean_val = 100,
sd_day = 1.5, sd_error = 2.5) {
set.seed(seed)
n_days <- 5
n_reps <- 5
data <- expand.grid(
day = 1:n_days,
replicate = 1:n_reps
)
day_effects <- rnorm(n_days, 0, sd_day)
errors <- rnorm(nrow(data), 0, sd_error)
day_effect <- day_effects[as.numeric(as.factor(data$day))]
data$value <- mean_val + day_effect + errors
data
}
# Input Validation Tests ----
test_that("verify_precision validates claimed values", {
x <- create_verification_data()
# Must provide at least one of claimed_cv or claimed_sd
expect_error(
verify_precision(x, mean_value = 100),
"Either `claimed_cv` or `claimed_sd` must be provided"
)
# Invalid claimed_cv
expect_error(
verify_precision(x, claimed_cv = -5, mean_value = 100),
"`claimed_cv` must be a single positive number"
)
expect_error(
verify_precision(x, claimed_cv = 0, mean_value = 100),
"`claimed_cv` must be a single positive number"
)
expect_error(
verify_precision(x, claimed_cv = c(3, 4), mean_value = 100),
"`claimed_cv` must be a single positive number"
)
# Invalid claimed_sd
expect_error(
verify_precision(x, claimed_sd = -3, mean_value = 100),
"`claimed_sd` must be a single positive number"
)
expect_error(
verify_precision(x, claimed_sd = 0, mean_value = 100),
"`claimed_sd` must be a single positive number"
)
})
test_that("verify_precision validates alpha", {
x <- create_verification_data()
expect_error(
verify_precision(x, claimed_cv = 5, mean_value = 100, alpha = 0),
"`alpha` must be a single number between 0 and 1"
)
expect_error(
verify_precision(x, claimed_cv = 5, mean_value = 100, alpha = 1),
"`alpha` must be a single number between 0 and 1"
)
expect_error(
verify_precision(x, claimed_cv = 5, mean_value = 100, alpha = -0.1),
"`alpha` must be a single number between 0 and 1"
)
expect_error(
verify_precision(x, claimed_cv = 5, mean_value = 100, alpha = c(0.05, 0.1)),
"`alpha` must be a single number between 0 and 1"
)
})
test_that("verify_precision validates conf_level", {
x <- create_verification_data()
expect_error(
verify_precision(x, claimed_cv = 5, mean_value = 100, conf_level = 0),
"`conf_level` must be a single number between 0 and 1"
)
expect_error(
verify_precision(x, claimed_cv = 5, mean_value = 100, conf_level = 1),
"`conf_level` must be a single number between 0 and 1"
)
expect_error(
verify_precision(x, claimed_cv = 5, mean_value = 100, conf_level = 1.5),
"`conf_level` must be a single number between 0 and 1"
)
})
test_that("verify_precision validates numeric vector input", {
# Non-numeric input
expect_error(
verify_precision("not numeric", claimed_cv = 5, mean_value = 100),
"`x` must be a numeric vector"
)
# Too few observations
expect_error(
verify_precision(c(1, 2), claimed_cv = 5, mean_value = 100),
"At least 3 observations are required"
)
# Empty vector after NA removal
expect_error(
verify_precision(rep(NA_real_, 5), claimed_cv = 5, mean_value = 100),
"At least 3 observations are required"
)
})
# Basic Functionality Tests ----
test_that("verify_precision returns correct class", {
x <- create_verification_data()
result <- verify_precision(x, claimed_cv = 5, mean_value = 100)
expect_s3_class(result, "verify_precision")
expect_s3_class(result, "valytics_precision")
expect_s3_class(result, "valytics_result")
})
test_that("verify_precision returns expected structure", {
x <- create_verification_data()
result <- verify_precision(x, claimed_cv = 5, mean_value = 100)
# Check main components
expect_named(result, c("input", "observed", "claimed", "test",
"verification", "ci", "settings", "call"))
# Check input
expect_named(result$input, c("n", "df", "mean_value", "source"))
expect_equal(result$input$n, 25)
expect_equal(result$input$df, 24)
# Check observed
expect_named(result$observed, c("sd", "cv_pct", "variance"))
expect_true(is.numeric(result$observed$sd))
expect_true(is.numeric(result$observed$cv_pct))
# Check claimed
expect_named(result$claimed, c("sd", "cv_pct", "variance"))
expect_equal(result$claimed$cv_pct, 5)
# Check test
expect_named(result$test, c("statistic", "df", "p_value",
"alternative", "method"))
expect_true(is.numeric(result$test$statistic))
expect_true(is.numeric(result$test$p_value))
# Check verification
expect_named(result$verification, c("verified", "ratio", "cv_ratio",
"upper_verification_limit"))
expect_true(is.logical(result$verification$verified))
# Check CI
expect_named(result$ci, c("variance_ci", "sd_ci", "cv_ci"))
expect_named(result$ci$sd_ci, c("lower", "upper"))
})
test_that("verify_precision works with claimed_cv", {
set.seed(42)
x <- rnorm(25, mean = 100, sd = 3.5)
result <- verify_precision(x, claimed_cv = 5, mean_value = 100)
# Claimed CV should be as specified
expect_equal(result$claimed$cv_pct, 5)
# Claimed SD should be derived from CV and mean
expect_equal(result$claimed$sd, 5) # 5% of 100
# Observed CV should be reasonable
expect_true(result$observed$cv_pct > 0)
expect_true(result$observed$cv_pct < 20) # Reasonable bound
})
test_that("verify_precision works with claimed_sd", {
set.seed(42)
x <- rnorm(25, mean = 100, sd = 3.5)
result <- verify_precision(x, claimed_sd = 5, mean_value = 100)
# Claimed SD should be as specified
expect_equal(result$claimed$sd, 5)
# Claimed CV should be derived from SD and mean
expect_equal(result$claimed$cv_pct, 5) # 5/100 * 100%
})
test_that("verify_precision works with both claimed_cv and claimed_sd", {
x <- create_verification_data()
result <- verify_precision(x, claimed_cv = 5, claimed_sd = 4, mean_value = 100)
# Both should be used as given
expect_equal(result$claimed$cv_pct, 5)
expect_equal(result$claimed$sd, 4)
})
# Verification Logic Tests ----
test_that("verify_precision correctly verifies when observed < claimed", {
# Generate data with SD = 3, claim CV = 5%
set.seed(123)
x <- rnorm(30, mean = 100, sd = 3)
result <- verify_precision(x, claimed_cv = 5, mean_value = 100)
# Should be verified because observed CV is lower than claimed
expect_true(result$verification$verified)
expect_lt(result$observed$cv_pct, result$verification$upper_verification_limit)
})
test_that("verify_precision correctly fails when observed >> claimed", {
# Generate data with SD = 8, claim CV = 3%
set.seed(123)
x <- rnorm(30, mean = 100, sd = 8)
result <- verify_precision(x, claimed_cv = 3, mean_value = 100)
# Should NOT be verified because observed CV is much higher than claimed
expect_false(result$verification$verified)
expect_gt(result$observed$cv_pct, result$verification$upper_verification_limit)
})
test_that("verify_precision upper verification limit is correct", {
set.seed(42)
x <- rnorm(25, mean = 100, sd = 4)
result <- verify_precision(x, claimed_cv = 5, mean_value = 100, alpha = 0.05)
# Calculate expected UVL manually
df <- 24
chi_sq_crit <- qchisq(0.95, df = df)
claimed_var <- 25 # (5/100 * 100)^2
uvl_var <- claimed_var * chi_sq_crit / df
uvl_cv <- 100 * sqrt(uvl_var) / 100
expect_equal(result$verification$upper_verification_limit, uvl_cv,
tolerance = 0.001)
})
test_that("verify_precision chi-square statistic is correct", {
set.seed(42)
x <- rnorm(25, mean = 100, sd = 4)
result <- verify_precision(x, claimed_cv = 5, mean_value = 100)
# Calculate expected chi-square manually
observed_var <- var(x)
claimed_var <- 25 # (5/100 * 100)^2
expected_chisq <- 24 * observed_var / claimed_var
expect_equal(result$test$statistic, expected_chisq, tolerance = 0.001)
})
# Alternative Hypothesis Tests ----
test_that("verify_precision respects alternative argument", {
set.seed(42)
x <- rnorm(30, mean = 100, sd = 4)
result_less <- verify_precision(x, claimed_cv = 5, mean_value = 100,
alternative = "less")
result_greater <- verify_precision(x, claimed_cv = 5, mean_value = 100,
alternative = "greater")
result_two <- verify_precision(x, claimed_cv = 5, mean_value = 100,
alternative = "two.sided")
# All should have different p-values (generally)
expect_equal(result_less$test$alternative, "less")
expect_equal(result_greater$test$alternative, "greater")
expect_equal(result_two$test$alternative, "two.sided")
# p-values should differ
# For two-sided: p = 2 * min(p_less, p_greater)
expect_true(result_two$test$p_value <= 1)
})
# Confidence Interval Tests ----
test_that("verify_precision confidence intervals are valid", {
x <- create_verification_data()
result <- verify_precision(x, claimed_cv = 5, mean_value = 100, conf_level = 0.95)
# Lower < observed < upper
expect_lt(result$ci$sd_ci["lower"], result$observed$sd)
expect_gt(result$ci$sd_ci["upper"], result$observed$sd)
expect_lt(result$ci$cv_ci["lower"], result$observed$cv_pct)
expect_gt(result$ci$cv_ci["upper"], result$observed$cv_pct)
expect_lt(result$ci$variance_ci["lower"], result$observed$variance)
expect_gt(result$ci$variance_ci["upper"], result$observed$variance)
})
test_that("verify_precision CI width changes with conf_level", {
x <- create_verification_data()
result_90 <- verify_precision(x, claimed_cv = 5, mean_value = 100,
conf_level = 0.90)
result_95 <- verify_precision(x, claimed_cv = 5, mean_value = 100,
conf_level = 0.95)
result_99 <- verify_precision(x, claimed_cv = 5, mean_value = 100,
conf_level = 0.99)
# CI width should increase with conf_level
width_90 <- diff(result_90$ci$sd_ci)
width_95 <- diff(result_95$ci$sd_ci)
width_99 <- diff(result_99$ci$sd_ci)
expect_lt(width_90, width_95)
expect_lt(width_95, width_99)
})
# Input Type Tests ----
test_that("verify_precision works with precision_study object", {
skip_if_not_installed("valytics")
data <- create_prec_study_data()
prec <- precision_study(data, value = "value", day = "day")
result <- verify_precision(prec, claimed_cv = 5)
expect_s3_class(result, "verify_precision")
expect_equal(result$input$source, "precision_study object")
expect_true(result$input$n > 0)
})
test_that("verify_precision works with data frame input", {
skip_if_not_installed("valytics")
data <- create_prec_study_data()
result <- verify_precision(
data,
claimed_cv = 5,
value = "value",
day = "day"
)
expect_s3_class(result, "verify_precision")
expect_equal(result$input$source, "data frame (via precision_study)")
})
test_that("verify_precision handles NA values in numeric vector", {
x <- c(rnorm(20, 100, 3.5), NA, NA, NA)
result <- verify_precision(x, claimed_cv = 5, mean_value = 100)
expect_equal(result$input$n, 20)
expect_equal(result$input$df, 19)
})
test_that("verify_precision uses provided mean_value for CV calculation", {
set.seed(42)
x <- rnorm(25, mean = 100, sd = 4)
# Override mean with a different value
result <- verify_precision(x, claimed_cv = 5, mean_value = 200)
# CV should be calculated using 200 as the mean
expected_cv <- 100 * sd(x) / 200
expect_equal(result$observed$cv_pct, expected_cv, tolerance = 0.001)
})
test_that("verify_precision calculates mean from data when not provided", {
set.seed(42)
x <- rnorm(25, mean = 100, sd = 4)
# When using claimed_sd, mean can be inferred from data
# But when using claimed_cv, we need mean to convert
# Test with claimed_sd:
result <- verify_precision(x, claimed_sd = 4)
expect_equal(result$input$mean_value, mean(x), tolerance = 0.001)
})
# Print and Summary Tests ----
test_that("print.verify_precision runs without error", {
x <- create_verification_data()
result <- verify_precision(x, claimed_cv = 5, mean_value = 100)
expect_output(print(result), "Precision Verification")
expect_output(print(result), "VERIFIED|NOT VERIFIED")
expect_output(print(result), "Chi-square")
})
test_that("summary.verify_precision returns correct class", {
x <- create_verification_data()
result <- verify_precision(x, claimed_cv = 5, mean_value = 100)
summ <- summary(result)
expect_s3_class(summ, "summary.verify_precision")
expect_named(summ, c("call", "input", "observed", "claimed", "test",
"verification", "ci", "settings"))
})
test_that("print.summary.verify_precision runs without error", {
x <- create_verification_data()
result <- verify_precision(x, claimed_cv = 5, mean_value = 100)
summ <- summary(result)
expect_output(print(summ), "Precision Verification - Detailed Summary")
expect_output(print(summ), "Confidence Intervals")
expect_output(print(summ), "Verification Outcome")
})
# Edge Cases ----
test_that("verify_precision handles minimum sample size (n=3)", {
x <- c(100, 102, 98)
result <- verify_precision(x, claimed_cv = 5, mean_value = 100)
expect_s3_class(result, "verify_precision")
expect_equal(result$input$n, 3)
expect_equal(result$input$df, 2)
})
test_that("verify_precision handles perfect precision (zero variance)", {
x <- rep(100, 10) # No variation
result <- verify_precision(x, claimed_cv = 5, mean_value = 100)
expect_equal(result$observed$sd, 0)
expect_equal(result$observed$cv_pct, 0)
expect_true(result$verification$verified) # Zero variance is always verified
})
test_that("verify_precision handles large sample sizes", {
set.seed(42)
x <- rnorm(500, mean = 100, sd = 4)
result <- verify_precision(x, claimed_cv = 5, mean_value = 100)
expect_s3_class(result, "verify_precision")
expect_equal(result$input$n, 500)
expect_equal(result$input$df, 499)
})
test_that("verify_precision handles small mean values", {
set.seed(42)
x <- rnorm(25, mean = 1, sd = 0.04)
result <- verify_precision(x, claimed_cv = 5, mean_value = 1)
expect_s3_class(result, "verify_precision")
expect_true(result$observed$cv_pct > 0)
})
test_that("verify_precision handles large mean values", {
set.seed(42)
x <- rnorm(25, mean = 10000, sd = 400)
result <- verify_precision(x, claimed_cv = 5, mean_value = 10000)
expect_s3_class(result, "verify_precision")
expect_true(result$observed$cv_pct > 0)
})
# Numerical Consistency Tests ----
test_that("verify_precision ratios are consistent", {
x <- create_verification_data()
result <- verify_precision(x, claimed_cv = 5, mean_value = 100)
# CV ratio should equal SD ratio (when mean is same)
expect_equal(result$verification$cv_ratio,
result$observed$cv_pct / result$claimed$cv_pct,
tolerance = 0.001)
# Variance ratio should be SD ratio squared
expect_equal(result$verification$ratio,
(result$observed$sd / result$claimed$sd)^2,
tolerance = 0.001)
})
test_that("verify_precision variance calculations are consistent", {
x <- create_verification_data()
result <- verify_precision(x, claimed_cv = 5, mean_value = 100)
# Observed variance should equal sd^2
expect_equal(result$observed$variance, result$observed$sd^2, tolerance = 0.001)
# Claimed variance should equal sd^2
expect_equal(result$claimed$variance, result$claimed$sd^2, tolerance = 0.001)
})
# Degrees of Freedom Tests ----
test_that("verify_precision uses correct df for numeric vector", {
x <- rnorm(30, 100, 4)
result <- verify_precision(x, claimed_cv = 5, mean_value = 100)
expect_equal(result$input$df, 29)
expect_equal(result$test$df, 29)
})
test_that("verify_precision df equals input n-1 for vector input", {
for (n in c(5, 10, 25, 50)) {
x <- rnorm(n, 100, 4)
result <- verify_precision(x, claimed_cv = 5, mean_value = 100)
expect_equal(result$input$df, n - 1,
info = sprintf("Failed for n = %d", n))
}
})
# Significance Level Tests ----
test_that("verify_precision alpha affects verification limit", {
x <- create_verification_data()
result_01 <- verify_precision(x, claimed_cv = 5, mean_value = 100, alpha = 0.01)
result_05 <- verify_precision(x, claimed_cv = 5, mean_value = 100, alpha = 0.05)
result_10 <- verify_precision(x, claimed_cv = 5, mean_value = 100, alpha = 0.10)
# More stringent alpha -> higher UVL (easier to verify)
expect_gt(result_01$verification$upper_verification_limit,
result_05$verification$upper_verification_limit)
expect_gt(result_05$verification$upper_verification_limit,
result_10$verification$upper_verification_limit)
})
# Integration Tests ----
test_that("verify_precision results are reproducible with same seed", {
set.seed(123)
x1 <- rnorm(25, 100, 4)
result1 <- verify_precision(x1, claimed_cv = 5, mean_value = 100)
set.seed(123)
x2 <- rnorm(25, 100, 4)
result2 <- verify_precision(x2, claimed_cv = 5, mean_value = 100)
expect_equal(result1$observed$cv_pct, result2$observed$cv_pct)
expect_equal(result1$test$statistic, result2$test$statistic)
expect_equal(result1$verification$verified, result2$verification$verified)
})
test_that("verify_precision handles realistic clinical lab scenario", {
# Simulate verification study: 5 days x 5 replicates
# Manufacturer claims CV = 4%
set.seed(42)
n_days <- 5
n_reps <- 5
true_sd <- 3.2 # Actual CV ~ 3.2%
mean_val <- 100
data <- expand.grid(day = 1:n_days, replicate = 1:n_reps)
day_effects <- rnorm(n_days, 0, 1)
errors <- rnorm(nrow(data), 0, 2)
data$value <- mean_val + day_effects[data$day] + errors
# Test with data frame input
result <- verify_precision(
data,
claimed_cv = 4,
value = "value",
day = "day"
)
expect_s3_class(result, "verify_precision")
# With these parameters, should likely be verified
expect_true(is.logical(result$verification$verified))
})
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.