tests/testthat/test-quick_anova.R

#===============================================================================
# Test: quick_anova()
# File: test-quick_anova.R
# Description: Unit tests for the quick_anova() function
#===============================================================================

#------------------------------------------------------------------------------
# Setup: Create test data
#------------------------------------------------------------------------------

# Set seed for reproducibility
set.seed(123)

# Normal distribution, 3 groups (for standard ANOVA)
test_data_normal <- data.frame(
  group = rep(c("A", "B", "C"), each = 25),
  value = c(rnorm(25, mean = 10, sd = 2),
            rnorm(25, mean = 12, sd = 2),
            rnorm(25, mean = 14, sd = 2)),
  stringsAsFactors = FALSE
)

# Unequal variances, 3 groups (for Welch ANOVA)
test_data_unequal_var <- data.frame(
  group = rep(c("X", "Y", "Z"), each = 20),
  value = c(rnorm(20, mean = 10, sd = 1),
            rnorm(20, mean = 12, sd = 3),
            rnorm(20, mean = 15, sd = 5)),
  stringsAsFactors = FALSE
)

# Skewed data, 4 groups (for Kruskal-Wallis)
test_data_skewed <- data.frame(
  treatment = rep(c("T1", "T2", "T3", "T4"), each = 20),
  score = c(rexp(20, 1), rexp(20, 1.5), rexp(20, 2), rexp(20, 2.5)),
  stringsAsFactors = FALSE
)

# Small sample data
test_data_small <- data.frame(
  group = rep(c("Low", "Medium", "High"), each = 5),
  response = c(rnorm(5, 5, 1), rnorm(5, 6, 1), rnorm(5, 7, 1)),
  stringsAsFactors = FALSE
)

# Data with NA values
test_data_na <- test_data_normal
test_data_na$value[1:3] <- NA

# Two groups only (should work but suggest using quick_ttest)
test_data_two_groups <- data.frame(
  group = rep(c("Control", "Treatment"), each = 20),
  value = c(rnorm(20, 10, 2), rnorm(20, 12, 2)),
  stringsAsFactors = FALSE
)

#------------------------------------------------------------------------------
# Basic Functionality Tests
#------------------------------------------------------------------------------

test_that("quick_anova() creates a quick_anova_result object", {
  result <- quick_anova(test_data_normal,
                        group = group,
                        value = value,
                        verbose = FALSE)
  expect_s3_class(result, "quick_anova_result")
})

test_that("quick_anova() performs standard one-way ANOVA", {
  result <- quick_anova(test_data_normal,
                        group = group,
                        value = value,
                        method = "anova",
                        verbose = FALSE)
  expect_equal(result$method_used, "anova")
  expect_true(!is.null(result$omnibus_result))
  expect_true("p_value" %in% names(result$omnibus_result))
})

test_that("quick_anova() performs Welch ANOVA", {
  result <- quick_anova(test_data_unequal_var,
                        group = group,
                        value = value,
                        method = "welch",
                        verbose = FALSE)
  expect_equal(result$method_used, "welch")
  expect_true(!is.null(result$omnibus_result))
  expect_true("p_value" %in% names(result$omnibus_result))
})

test_that("quick_anova() performs Kruskal-Wallis test", {
  result <- quick_anova(test_data_skewed,
                        group = treatment,
                        value = score,
                        method = "kruskal",
                        verbose = FALSE)
  expect_equal(result$method_used, "kruskal")
  expect_true(!is.null(result$omnibus_result))
  expect_true("p_value" %in% names(result$omnibus_result))
})

test_that("quick_anova() auto-selects appropriate method", {
  # Normal data with equal variances should select ANOVA
  result_normal <- quick_anova(test_data_normal,
                                group = group,
                                value = value,
                                method = "auto",
                                verbose = FALSE)
  expect_true(result_normal$method_used %in% c("anova", "welch"))
})

test_that("quick_anova() creates ggplot object", {
  result <- quick_anova(test_data_normal,
                        group = group,
                        value = value,
                        verbose = FALSE)
  expect_s3_class(result$plot, "ggplot")
})

#------------------------------------------------------------------------------
# Parameter Validation Tests
#------------------------------------------------------------------------------

test_that("quick_anova() validates data parameter", {
  expect_error(quick_anova(NULL, group = group, value = value),
               "`data` must be a data frame")
  expect_error(quick_anova(list(a = 1), group = group, value = value),
               "`data` must be a data frame")
})

test_that("quick_anova() validates conf.level parameter", {
  expect_error(quick_anova(test_data_normal, group = group, value = value,
                          conf.level = 1.5),
               "`conf.level` must be between 0 and 1")
  expect_error(quick_anova(test_data_normal, group = group, value = value,
                          conf.level = -0.5),
               "`conf.level` must be between 0 and 1")
})

test_that("quick_anova() validates add_jitter parameter", {
  expect_error(quick_anova(test_data_normal, group = group, value = value,
                          add_jitter = "yes"),
               "`add_jitter` must be TRUE or FALSE")
})

test_that("quick_anova() validates show_p_value parameter", {
  expect_error(quick_anova(test_data_normal, group = group, value = value,
                          show_p_value = "yes"),
               "`show_p_value` must be TRUE or FALSE")
})

test_that("quick_anova() validates verbose parameter", {
  expect_error(quick_anova(test_data_normal, group = group, value = value,
                          verbose = "yes"),
               "`verbose` must be TRUE or FALSE")
})

test_that("quick_anova() validates column names", {
  expect_error(quick_anova(test_data_normal,
                          group = nonexistent,
                          value = value,
                          verbose = FALSE),
               "not found")
  expect_error(quick_anova(test_data_normal,
                          group = group,
                          value = nonexistent,
                          verbose = FALSE),
               "not found")
})

test_that("quick_anova() validates value is numeric", {
  bad_data <- test_data_normal
  bad_data$value <- as.character(bad_data$value)
  expect_error(quick_anova(bad_data, group = group, value = value,
                          verbose = FALSE),
               "must be numeric")
})

test_that("quick_anova() requires at least 2 groups", {
  single_group_data <- data.frame(
    group = rep("A", 20),
    value = rnorm(20)
  )
  expect_error(quick_anova(single_group_data, group = group, value = value,
                          verbose = FALSE),
               "requires at least 2 groups")
})

test_that("quick_anova() works with exactly 2 groups", {
  result <- quick_anova(test_data_two_groups,
                        group = group,
                        value = value,
                        verbose = FALSE)
  expect_s3_class(result, "quick_anova_result")
})

#------------------------------------------------------------------------------
# Post-hoc Tests Validation
#------------------------------------------------------------------------------

test_that("quick_anova() performs Tukey HSD post-hoc after ANOVA", {
  result <- quick_anova(test_data_normal,
                        group = group,
                        value = value,
                        method = "anova",
                        post_hoc = "tukey",
                        verbose = FALSE)
  expect_true(!is.null(result$post_hoc))
  expect_equal(result$post_hoc$method, "tukey")
})

test_that("quick_anova() performs Welch post-hoc after Welch ANOVA", {
  result <- quick_anova(test_data_unequal_var,
                        group = group,
                        value = value,
                        method = "welch",
                        post_hoc = "welch",
                        verbose = FALSE)
  expect_true(!is.null(result$post_hoc))
  expect_equal(result$post_hoc$method, "welch")
})

test_that("quick_anova() performs Wilcoxon post-hoc after Kruskal-Wallis", {
  result <- quick_anova(test_data_skewed,
                        group = treatment,
                        value = score,
                        method = "kruskal",
                        post_hoc = "wilcox",
                        verbose = FALSE)
  expect_true(!is.null(result$post_hoc))
  expect_equal(result$post_hoc$method, "wilcox")
})

test_that("quick_anova() auto-selects appropriate post-hoc test", {
  result <- quick_anova(test_data_normal,
                        group = group,
                        value = value,
                        method = "anova",
                        post_hoc = "auto",
                        verbose = FALSE)
  expect_true(!is.null(result$post_hoc))
})

test_that("quick_anova() skips post-hoc when post_hoc = 'none'", {
  result <- quick_anova(test_data_normal,
                        group = group,
                        value = value,
                        method = "anova",
                        post_hoc = "none",
                        verbose = FALSE)
  expect_true(is.null(result$post_hoc))
})

#------------------------------------------------------------------------------
# Statistical Tests Validation
#------------------------------------------------------------------------------

test_that("quick_anova() performs normality checks", {
  result <- quick_anova(test_data_normal,
                        group = group,
                        value = value,
                        method = "auto",
                        verbose = FALSE)
  expect_true(!is.null(result$assumption_checks$normality))
  expect_true("recommendation" %in% names(result$assumption_checks$normality))
})

test_that("quick_anova() checks variance equality for ANOVA", {
  result <- quick_anova(test_data_normal,
                        group = group,
                        value = value,
                        method = "anova",
                        verbose = FALSE)
  # Should have variance test if method is ANOVA and auto decision was made
  expect_true(is.null(result$assumption_checks$variance) ||
              !is.null(result$assumption_checks$variance))
})

test_that("quick_anova() handles method = 'auto' correctly", {
  # For normal data, should choose parametric method
  result <- quick_anova(test_data_normal,
                        group = group,
                        value = value,
                        method = "auto",
                        verbose = FALSE)
  expect_true(result$method_used %in% c("anova", "welch"))

  # For skewed data, should choose Kruskal-Wallis
  result_skewed <- quick_anova(test_data_skewed,
                                group = treatment,
                                value = score,
                                method = "auto",
                                verbose = FALSE)
  expect_true(result_skewed$method_used %in% c("anova", "welch", "kruskal"))
})

#------------------------------------------------------------------------------
# Plot Customization Tests
#------------------------------------------------------------------------------

test_that("quick_anova() supports different plot types", {
  result_box <- quick_anova(test_data_normal, group = group, value = value,
                            plot_type = "boxplot", verbose = FALSE)
  expect_s3_class(result_box$plot, "ggplot")

  result_violin <- quick_anova(test_data_normal, group = group, value = value,
                               plot_type = "violin", verbose = FALSE)
  expect_s3_class(result_violin$plot, "ggplot")

  result_both <- quick_anova(test_data_normal, group = group, value = value,
                             plot_type = "both", verbose = FALSE)
  expect_s3_class(result_both$plot, "ggplot")
})

test_that("quick_anova() supports jitter customization", {
  result_no_jitter <- quick_anova(test_data_normal, group = group, value = value,
                                  add_jitter = FALSE, verbose = FALSE)
  expect_s3_class(result_no_jitter$plot, "ggplot")

  result_custom <- quick_anova(test_data_normal, group = group, value = value,
                               add_jitter = TRUE, point_size = 3,
                               point_alpha = 0.8, verbose = FALSE)
  expect_s3_class(result_custom$plot, "ggplot")
})

test_that("quick_anova() supports p-value label formats", {
  result_stars <- quick_anova(test_data_normal, group = group, value = value,
                              p_label = "p.signif", verbose = FALSE)
  expect_s3_class(result_stars$plot, "ggplot")

  result_numeric <- quick_anova(test_data_normal, group = group, value = value,
                                p_label = "p.format", verbose = FALSE)
  expect_s3_class(result_numeric$plot, "ggplot")
})

test_that("quick_anova() supports hiding p-value", {
  result <- quick_anova(test_data_normal, group = group, value = value,
                        show_p_value = FALSE, verbose = FALSE)
  expect_s3_class(result$plot, "ggplot")
})

test_that("quick_anova() accepts palette parameter", {
  result <- quick_anova(test_data_normal, group = group, value = value,
                        palette = "qual_bold", verbose = FALSE)
  expect_s3_class(result$plot, "ggplot")
})

test_that("quick_anova() accepts NULL palette", {
  result <- quick_anova(test_data_normal, group = group, value = value,
                        palette = NULL, verbose = FALSE)
  expect_s3_class(result$plot, "ggplot")
})

#------------------------------------------------------------------------------
# Return Object Structure Tests
#------------------------------------------------------------------------------

test_that("quick_anova() returns object with required components", {
  result <- quick_anova(test_data_normal, group = group, value = value,
                        verbose = FALSE)

  expect_true("plot" %in% names(result))
  expect_true("omnibus_result" %in% names(result))
  expect_true("post_hoc" %in% names(result))
  expect_true("method_used" %in% names(result))
  expect_true("descriptive_stats" %in% names(result))
  expect_true("assumption_checks" %in% names(result))
  expect_true("auto_decision" %in% names(result))
  expect_true("timestamp" %in% names(result))
  expect_true("parameters" %in% names(result))
})

test_that("quick_anova() result contains descriptive statistics", {
  result <- quick_anova(test_data_normal, group = group, value = value,
                        verbose = FALSE)

  expect_s3_class(result$descriptive_stats, "data.frame")
  expect_true("n" %in% names(result$descriptive_stats))
  expect_true("mean" %in% names(result$descriptive_stats))
  expect_true("sd" %in% names(result$descriptive_stats))
  expect_true("median" %in% names(result$descriptive_stats))
})

test_that("quick_anova() stores parameters correctly", {
  result <- quick_anova(test_data_normal,
                        group = group,
                        value = value,
                        method = "anova",
                        post_hoc = "tukey",
                        conf.level = 0.95,
                        plot_type = "boxplot",
                        verbose = FALSE)

  expect_equal(result$parameters$method, "anova")
  expect_equal(result$parameters$post_hoc, "tukey")
  expect_equal(result$parameters$conf.level, 0.95)
  expect_equal(result$parameters$plot_type, "boxplot")
})

#------------------------------------------------------------------------------
# Edge Cases and Special Scenarios
#------------------------------------------------------------------------------

test_that("quick_anova() handles small samples", {
  result <- quick_anova(test_data_small, group = group, value = response,
                        verbose = FALSE)
  expect_s3_class(result, "quick_anova_result")
})

test_that("quick_anova() handles data with NA values", {
  result <- quick_anova(test_data_na, group = group, value = value,
                       verbose = FALSE)
  expect_s3_class(result, "quick_anova_result")
  # Check that rows with NA were removed
  expect_true(nrow(result$descriptive_stats) == 3)
})

test_that("quick_anova() handles different confidence levels", {
  result_90 <- quick_anova(test_data_normal,
                           group = group,
                           value = value,
                           conf.level = 0.90,
                           verbose = FALSE)
  expect_equal(result_90$parameters$conf.level, 0.90)

  result_99 <- quick_anova(test_data_normal,
                           group = group,
                           value = value,
                           conf.level = 0.99,
                           verbose = FALSE)
  expect_equal(result_99$parameters$conf.level, 0.99)
})

test_that("quick_anova() handles unbalanced sample sizes", {
  unbalanced_data <- data.frame(
    group = c(rep("A", 10), rep("B", 20), rep("C", 30)),
    value = rnorm(60)
  )
  result <- quick_anova(unbalanced_data, group = group, value = value,
                       verbose = FALSE)
  expect_s3_class(result, "quick_anova_result")
  # Check descriptive stats show different sample sizes
  expect_true(length(unique(result$descriptive_stats$n)) > 1)
})

test_that("quick_anova() handles 4+ groups", {
  many_groups_data <- data.frame(
    group = rep(c("A", "B", "C", "D", "E"), each = 15),
    value = c(rnorm(15, 10, 2), rnorm(15, 11, 2), rnorm(15, 12, 2),
              rnorm(15, 13, 2), rnorm(15, 14, 2))
  )
  result <- quick_anova(many_groups_data, group = group, value = value,
                       verbose = FALSE)
  expect_s3_class(result, "quick_anova_result")
  expect_equal(nrow(result$descriptive_stats), 5)
})

test_that("quick_anova() p-value is within valid range", {
  result <- quick_anova(test_data_normal, group = group, value = value,
                        verbose = FALSE)
  expect_true(result$omnibus_result$p_value >= 0)
  expect_true(result$omnibus_result$p_value <= 1)
})

#------------------------------------------------------------------------------
# S3 Methods Tests
#------------------------------------------------------------------------------

test_that("print.quick_anova_result works", {
  result <- quick_anova(test_data_normal, group = group, value = value,
                        verbose = FALSE)
  # print method displays plot and descriptive stats
  expect_output(print(result), "Method:|group|value")
})

test_that("summary.quick_anova_result works", {
  result <- quick_anova(test_data_normal, group = group, value = value,
                        verbose = FALSE)
  # summary should produce output - just check it runs without error
  expect_output(summary(result))
})

test_that("quick_anova_result contains plot", {
  result <- quick_anova(test_data_normal, group = group, value = value,
                        verbose = FALSE)
  # Result should contain a ggplot object
  expect_s3_class(result$plot, "ggplot")
})

#------------------------------------------------------------------------------
# Verbose Mode Tests
#------------------------------------------------------------------------------

test_that("quick_anova() prints messages when verbose = TRUE", {
  # Function should produce diagnostic messages when verbose = TRUE
  result <- quick_anova(test_data_normal, group = group, value = value,
                       verbose = TRUE)
  # Just verify the result is created - verbose messages are visible in test output
  expect_s3_class(result, "quick_anova_result")
})

test_that("quick_anova() minimizes output when verbose = FALSE", {
  # verbose = FALSE should minimize output
  result <- quick_anova(test_data_normal, group = group, value = value,
                       verbose = FALSE)
  # Just check the result is created successfully
  expect_s3_class(result, "quick_anova_result")
})

#------------------------------------------------------------------------------
# Integration Tests
#------------------------------------------------------------------------------

test_that("quick_anova() end-to-end workflow for ANOVA", {
  result <- quick_anova(
    data = test_data_normal,
    group = group,
    value = value,
    method = "anova",
    post_hoc = "tukey",
    plot_type = "boxplot",
    add_jitter = TRUE,
    show_p_value = TRUE,
    p_label = "p.signif",
    palette = "qual_vivid",
    verbose = FALSE
  )

  expect_s3_class(result, "quick_anova_result")
  expect_s3_class(result$plot, "ggplot")
  expect_equal(result$method_used, "anova")
  expect_true(!is.null(result$post_hoc))
  expect_true(result$omnibus_result$p_value >= 0 && result$omnibus_result$p_value <= 1)
})

test_that("quick_anova() end-to-end workflow for Welch ANOVA", {
  result <- quick_anova(
    data = test_data_unequal_var,
    group = group,
    value = value,
    method = "welch",
    post_hoc = "welch",
    plot_type = "violin",
    show_p_value = TRUE,
    p_label = "p.format",
    verbose = FALSE
  )

  expect_s3_class(result, "quick_anova_result")
  expect_s3_class(result$plot, "ggplot")
  expect_equal(result$method_used, "welch")
  expect_true(!is.null(result$post_hoc))
  expect_true(result$omnibus_result$p_value >= 0 && result$omnibus_result$p_value <= 1)
})

test_that("quick_anova() end-to-end workflow for Kruskal-Wallis", {
  result <- quick_anova(
    data = test_data_skewed,
    group = treatment,
    value = score,
    method = "kruskal",
    post_hoc = "wilcox",
    plot_type = "both",
    show_p_value = TRUE,
    verbose = FALSE
  )

  expect_s3_class(result, "quick_anova_result")
  expect_s3_class(result$plot, "ggplot")
  expect_equal(result$method_used, "kruskal")
  expect_true(!is.null(result$post_hoc))
  expect_true(result$omnibus_result$p_value >= 0 && result$omnibus_result$p_value <= 1)
})

#===============================================================================
# End: test-quick_anova.R
#===============================================================================

Try the evanverse package in your browser

Any scripts or data that you put into this service are public.

evanverse documentation built on March 10, 2026, 5:07 p.m.