Nothing
# test-irt_study.R
# TDD tests for irt_study() — Objective 4
# These tests define the expected behavior BEFORE implementation exists.
# --- Shared Fixture -----------------------------------------------------------
make_design_2pl <- function(n = 10) {
irt_design(
model = "2PL",
n_items = n,
item_params = list(a = rlnorm(n, 0, 0.25), b = rnorm(n))
)
}
make_design_1pl <- function(n = 10) {
irt_design(model = "1PL", n_items = n, item_params = list(b = rnorm(n)))
}
make_design_grm <- function(n = 10, n_cat = 5) {
a <- rlnorm(n, 0, 0.25)
b <- t(apply(matrix(rnorm(n * (n_cat - 1)), nrow = n), 1, sort))
irt_design(model = "GRM", n_items = n, item_params = list(a = a, b = b))
}
# --- Basic Construction (missing = "none") ------------------------------------
test_that("irt_study creates valid study with no missing data", {
d <- make_design_2pl()
study <- irt_study(d, sample_sizes = c(100, 250, 500))
expect_s3_class(study, "irt_study")
expect_identical(study$design, d)
expect_equal(study$missing, "none")
expect_equal(study$missing_rate, 0)
expect_equal(study$sample_sizes, c(100L, 250L, 500L))
})
test_that("irt_study defaults missing to 'none'", {
d <- make_design_1pl()
study <- irt_study(d, sample_sizes = 200)
expect_equal(study$missing, "none")
})
test_that("irt_study coerces sample_sizes to integer", {
d <- make_design_1pl()
study <- irt_study(d, sample_sizes = c(100.0, 500.0))
expect_true(is.integer(study$sample_sizes))
expect_equal(study$sample_sizes, c(100L, 500L))
})
test_that("irt_study works with single sample size", {
d <- make_design_1pl()
study <- irt_study(d, sample_sizes = 300)
expect_equal(study$sample_sizes, 300L)
})
# --- Missing Data Mechanisms --------------------------------------------------
test_that("irt_study accepts missing = 'mcar' with missing_rate", {
d <- make_design_2pl()
study <- irt_study(d, sample_sizes = c(200, 400),
missing = "mcar", missing_rate = 0.2)
expect_equal(study$missing, "mcar")
expect_equal(study$missing_rate, 0.2)
})
test_that("irt_study accepts missing = 'mar' with missing_rate", {
d <- make_design_2pl()
study <- irt_study(d, sample_sizes = 500,
missing = "mar", missing_rate = 0.15)
expect_equal(study$missing, "mar")
expect_equal(study$missing_rate, 0.15)
})
test_that("irt_study accepts missing = 'booklet' with test_design", {
d <- make_design_2pl(n = 20)
# Booklet design: 2 booklets, each with 15 of 20 items (10 common + 5 unique)
booklet_matrix <- matrix(
c(rep(1, 15), rep(0, 5), # booklet 1: items 1-15
rep(0, 5), rep(1, 15)), # booklet 2: items 6-20
nrow = 2, ncol = 20, byrow = TRUE
)
study <- irt_study(d, sample_sizes = c(200, 400),
missing = "booklet",
test_design = list(booklet_matrix = booklet_matrix))
expect_equal(study$missing, "booklet")
expect_true(!is.null(study$test_design))
expect_true(!is.null(study$test_design$booklet_matrix))
expect_equal(ncol(study$test_design$booklet_matrix), 20L)
})
test_that("irt_study accepts missing = 'linking' with test_design", {
d <- make_design_2pl(n = 30)
# Linking design: 3 forms with common anchor items
linking_matrix <- matrix(0, nrow = 3, ncol = 30)
linking_matrix[1, 1:15] <- 1 # form 1: items 1-15
linking_matrix[2, 8:22] <- 1 # form 2: items 8-22 (overlap 8-15)
linking_matrix[3, 16:30] <- 1 # form 3: items 16-30 (overlap 16-22)
study <- irt_study(d, sample_sizes = 500,
missing = "linking",
test_design = list(linking_matrix = linking_matrix))
expect_equal(study$missing, "linking")
expect_true(!is.null(study$test_design$linking_matrix))
})
test_that("irt_study sets missing_rate to 0 when missing = 'none'", {
d <- make_design_1pl()
study <- irt_study(d, sample_sizes = 100, missing = "none")
expect_equal(study$missing_rate, 0)
})
# --- Input Validation: design argument ----------------------------------------
test_that("irt_study requires irt_design as first argument", {
expect_error(
irt_study("not_a_design", sample_sizes = 100),
"irt_design"
)
expect_error(
irt_study(list(model = "1PL"), sample_sizes = 100),
"irt_design"
)
})
test_that("irt_study rejects NULL design", {
expect_error(
irt_study(NULL, sample_sizes = 100),
"irt_design|design|NULL"
)
})
# --- Input Validation: sample_sizes -------------------------------------------
test_that("irt_study rejects non-positive sample sizes", {
d <- make_design_1pl()
expect_error(
irt_study(d, sample_sizes = c(100, 0, 500)),
"sample_sizes|positive"
)
expect_error(
irt_study(d, sample_sizes = -10),
"sample_sizes|positive"
)
})
test_that("irt_study rejects non-numeric sample sizes", {
d <- make_design_1pl()
expect_error(
irt_study(d, sample_sizes = "one hundred"),
"sample_sizes|numeric|integer"
)
})
test_that("irt_study rejects NA in sample sizes", {
d <- make_design_1pl()
expect_error(
irt_study(d, sample_sizes = c(100, NA, 500)),
"sample_sizes|NA"
)
})
test_that("irt_study rejects empty sample_sizes", {
d <- make_design_1pl()
expect_error(
irt_study(d, sample_sizes = integer(0)),
"sample_sizes|empty|length"
)
})
test_that("irt_study rejects fractional sample sizes", {
d <- make_design_1pl()
# 100.5 is not a whole number — should error or truncate
expect_error(
irt_study(d, sample_sizes = c(100.5, 200.7)),
"sample_sizes|integer|whole"
)
})
# --- Input Validation: missing & missing_rate ---------------------------------
test_that("irt_study rejects unsupported missing mechanism", {
d <- make_design_1pl()
expect_error(
irt_study(d, sample_sizes = 100, missing = "listwise"),
"missing"
)
})
test_that("irt_study rejects missing_rate outside [0, 1)", {
d <- make_design_1pl()
expect_error(
irt_study(d, sample_sizes = 100, missing = "mcar", missing_rate = 1.0),
"missing_rate"
)
expect_error(
irt_study(d, sample_sizes = 100, missing = "mcar", missing_rate = -0.1),
"missing_rate"
)
expect_error(
irt_study(d, sample_sizes = 100, missing = "mcar", missing_rate = 1.5),
"missing_rate"
)
})
test_that("irt_study requires missing_rate when missing is 'mcar'", {
d <- make_design_1pl()
expect_error(
irt_study(d, sample_sizes = 100, missing = "mcar"),
"missing_rate"
)
})
test_that("irt_study requires missing_rate when missing is 'mar'", {
d <- make_design_1pl()
expect_error(
irt_study(d, sample_sizes = 100, missing = "mar"),
"missing_rate"
)
})
test_that("irt_study ignores missing_rate when missing = 'none'", {
d <- make_design_1pl()
# Providing a missing_rate when missing = "none" should be quietly ignored
study <- irt_study(d, sample_sizes = 100, missing = "none", missing_rate = 0.5)
expect_equal(study$missing_rate, 0)
})
# --- Input Validation: booklet/linking test_design ----------------------------
test_that("irt_study requires test_design for booklet missing", {
d <- make_design_2pl(n = 20)
expect_error(
irt_study(d, sample_sizes = 100, missing = "booklet"),
"test_design|booklet"
)
})
test_that("irt_study requires test_design for linking missing", {
d <- make_design_2pl(n = 20)
expect_error(
irt_study(d, sample_sizes = 100, missing = "linking"),
"test_design|linking"
)
})
test_that("irt_study rejects booklet matrix with wrong number of columns", {
d <- make_design_2pl(n = 20)
# Matrix has 10 columns but design has 20 items
bad_matrix <- matrix(1, nrow = 2, ncol = 10)
expect_error(
irt_study(d, sample_sizes = 100, missing = "booklet",
test_design = list(booklet_matrix = bad_matrix)),
"n_items|columns|items"
)
})
test_that("irt_study rejects linking matrix with wrong number of columns", {
d <- make_design_2pl(n = 20)
bad_matrix <- matrix(1, nrow = 3, ncol = 15)
expect_error(
irt_study(d, sample_sizes = 100, missing = "linking",
test_design = list(linking_matrix = bad_matrix)),
"n_items|columns|items"
)
})
test_that("irt_study rejects booklet matrix with non-binary values", {
d <- make_design_2pl(n = 10)
bad_matrix <- matrix(c(1, 0, 2, 0, 1, 1, 0, 1, 1, 0,
0, 1, 0, 1, 0, 0, 1, 0, 0, 1),
nrow = 2, ncol = 10, byrow = TRUE)
expect_error(
irt_study(d, sample_sizes = 100, missing = "booklet",
test_design = list(booklet_matrix = bad_matrix)),
"binary|0.*1"
)
})
# --- S3 Class Structure -------------------------------------------------------
test_that("irt_study returns an S3 object with correct class", {
d <- make_design_2pl()
study <- irt_study(d, sample_sizes = c(100, 500))
expect_s3_class(study, "irt_study")
expect_true(is.list(study))
})
test_that("irt_study object contains all expected elements", {
d <- make_design_2pl()
study <- irt_study(d, sample_sizes = c(100, 500),
missing = "mcar", missing_rate = 0.1)
expected_names <- c("design", "missing", "missing_rate",
"sample_sizes", "test_design")
expect_true(all(expected_names %in% names(study)))
})
test_that("irt_study preserves irt_design object unchanged", {
d <- make_design_2pl()
study <- irt_study(d, sample_sizes = c(100, 500))
expect_identical(study$design, d)
})
test_that("irt_study object is a plain list (not reference class)", {
d <- make_design_1pl()
study <- irt_study(d, sample_sizes = 100)
expect_false(is.environment(study))
expect_true(is.list(study))
})
# --- Print Method -------------------------------------------------------------
test_that("print.irt_study produces informative output", {
d <- make_design_2pl(n = 20)
study <- irt_study(d, sample_sizes = c(100, 250, 500),
missing = "mcar", missing_rate = 0.2)
output <- capture.output(print(study))
output_text <- paste(output, collapse = "\n")
# Should mention IRT study or study conditions
expect_match(output_text, "study|Study", ignore.case = FALSE)
# Should mention the underlying model
expect_match(output_text, "2PL", fixed = TRUE)
# Should mention sample sizes
expect_match(output_text, "100")
expect_match(output_text, "500")
# Should mention missing data mechanism
expect_match(output_text, "mcar|MCAR", ignore.case = FALSE)
# Should mention missing rate
expect_match(output_text, "0.2|20%")
# Should return the object invisibly
expect_invisible(print(study))
})
test_that("print.irt_study works for booklet design", {
d <- make_design_2pl(n = 20)
booklet_matrix <- matrix(
c(rep(1, 15), rep(0, 5),
rep(0, 5), rep(1, 15)),
nrow = 2, ncol = 20, byrow = TRUE
)
study <- irt_study(d, sample_sizes = 300,
missing = "booklet",
test_design = list(booklet_matrix = booklet_matrix))
output <- capture.output(print(study))
output_text <- paste(output, collapse = "\n")
# Should mention booklet
expect_match(output_text, "booklet|Booklet", ignore.case = FALSE)
# Should mention number of booklets/forms
expect_match(output_text, "2")
})
test_that("print.irt_study works for no-missing design", {
d <- make_design_1pl()
study <- irt_study(d, sample_sizes = c(50, 100))
output <- capture.output(print(study))
output_text <- paste(output, collapse = "\n")
# Should indicate no missing data or complete data
expect_match(output_text, "none|complete|no missing", ignore.case = TRUE)
})
# --- GRM Integration ----------------------------------------------------------
test_that("irt_study works with GRM design", {
d <- make_design_grm()
study <- irt_study(d, sample_sizes = c(200, 500))
expect_s3_class(study, "irt_study")
expect_equal(study$design$model, "GRM")
})
# --- Edge Cases ---------------------------------------------------------------
test_that("irt_study sorts sample_sizes in ascending order", {
d <- make_design_1pl()
study <- irt_study(d, sample_sizes = c(500, 100, 250))
expect_equal(study$sample_sizes, c(100L, 250L, 500L))
})
test_that("irt_study removes duplicate sample sizes", {
d <- make_design_1pl()
study <- irt_study(d, sample_sizes = c(100, 250, 100, 500, 250))
expect_equal(study$sample_sizes, c(100L, 250L, 500L))
})
test_that("irt_study accepts large sample size vector", {
d <- make_design_1pl()
sizes <- seq(50, 2000, by = 50)
study <- irt_study(d, sample_sizes = sizes)
expect_equal(length(study$sample_sizes), length(unique(sizes)))
})
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.