Nothing
# test-irt_design.R
# TDD tests for irt_design() — Objective 2
# These tests define the expected behavior BEFORE implementation exists.
# --- 1PL (Rasch) Construction ------------------------------------------------
test_that("irt_design creates valid 1PL design with explicit difficulty", {
b <- seq(-2, 2, length.out = 10)
design <- irt_design(model = "1PL", n_items = 10, item_params = list(b = b))
expect_s3_class(design, "irt_design")
expect_equal(design$model, "1PL")
expect_equal(design$n_items, 10L)
expect_equal(design$item_params$b, b)
# 1PL has no discrimination vector — all items share a = 1
expect_equal(design$item_params$a, rep(1, 10))
expect_equal(design$n_factors, 1L)
})
test_that("irt_design 1PL defaults to standard normal theta", {
design <- irt_design(model = "1PL", n_items = 5, item_params = list(b = rnorm(5)))
expect_equal(design$theta_dist, "normal")
})
# --- 2PL Construction --------------------------------------------------------
test_that("irt_design creates valid 2PL design", {
a <- rlnorm(20, meanlog = 0, sdlog = 0.25)
b <- seq(-2, 2, length.out = 20)
design <- irt_design(
model = "2PL",
n_items = 20,
item_params = list(a = a, b = b)
)
expect_s3_class(design, "irt_design")
expect_equal(design$model, "2PL")
expect_equal(design$n_items, 20L)
expect_equal(design$item_params$a, a)
expect_equal(design$item_params$b, b)
})
test_that("irt_design 2PL requires both a and b parameters", {
expect_error(
irt_design(model = "2PL", n_items = 10, item_params = list(b = rnorm(10))),
"a"
)
expect_error(
irt_design(model = "2PL", n_items = 10, item_params = list(a = rlnorm(10))),
"b"
)
})
# --- GRM Construction --------------------------------------------------------
test_that("irt_design creates valid GRM design", {
n_items <- 10
n_categories <- 5 # 5 categories → 4 thresholds per item
a <- rlnorm(n_items, meanlog = 0, sdlog = 0.25)
# b is a matrix: n_items x (n_categories - 1)
b <- matrix(
sort(rnorm(n_items * (n_categories - 1))),
nrow = n_items, ncol = n_categories - 1
)
design <- irt_design(
model = "GRM",
n_items = n_items,
item_params = list(a = a, b = b)
)
expect_s3_class(design, "irt_design")
expect_equal(design$model, "GRM")
expect_equal(design$n_items, n_items)
expect_equal(design$item_params$a, a)
expect_true(is.matrix(design$item_params$b))
expect_equal(nrow(design$item_params$b), n_items)
expect_equal(ncol(design$item_params$b), n_categories - 1)
})
test_that("irt_design GRM requires matrix b with correct dimensions", {
a <- rlnorm(5, 0, 0.25)
# Wrong: b as vector instead of matrix
expect_error(
irt_design(model = "GRM", n_items = 5, item_params = list(a = a, b = rnorm(5))),
"matrix"
)
})
# --- Theta Distribution Options ---------------------------------------------
test_that("irt_design accepts character theta_dist options", {
b <- rnorm(10)
design_normal <- irt_design(
model = "1PL", n_items = 10,
item_params = list(b = b), theta_dist = "normal"
)
expect_equal(design_normal$theta_dist, "normal")
design_uniform <- irt_design(
model = "1PL", n_items = 10,
item_params = list(b = b), theta_dist = "uniform"
)
expect_equal(design_uniform$theta_dist, "uniform")
})
test_that("irt_design accepts custom theta_dist function", {
custom_fn <- function(n) rnorm(n, mean = 1, sd = 0.5)
design <- irt_design(
model = "1PL", n_items = 10,
item_params = list(b = rnorm(10)),
theta_dist = custom_fn
)
expect_true(is.function(design$theta_dist))
})
test_that("irt_design rejects invalid theta_dist strings", {
expect_error(
irt_design(
model = "1PL", n_items = 5,
item_params = list(b = rnorm(5)),
theta_dist = "banana"
),
"theta_dist"
)
})
# --- n_factors ---------------------------------------------------------------
test_that("irt_design defaults to 1 factor", {
design <- irt_design(model = "1PL", n_items = 5, item_params = list(b = rnorm(5)))
expect_equal(design$n_factors, 1L)
})
test_that("irt_design accepts n_factors argument", {
# For multidimensional, a would be a matrix (n_items x n_factors)
a <- matrix(rlnorm(20), nrow = 10, ncol = 2)
b <- rnorm(10)
design <- irt_design(
model = "2PL", n_items = 10,
item_params = list(a = a, b = b),
n_factors = 2
)
expect_equal(design$n_factors, 2L)
})
# --- Parameter Validation (Errors) ------------------------------------------
test_that("irt_design rejects unsupported model types", {
expect_error(
irt_design(model = "4PL", n_items = 10, item_params = list(b = rnorm(10))),
"model"
)
expect_error(
irt_design(model = "GPCM", n_items = 10, item_params = list(b = rnorm(10))),
"model"
)
})
test_that("irt_design rejects non-positive n_items", {
expect_error(
irt_design(model = "1PL", n_items = 0, item_params = list(b = numeric(0))),
"n_items"
)
expect_error(
irt_design(model = "1PL", n_items = -5, item_params = list(b = rnorm(5))),
"n_items"
)
})
test_that("irt_design rejects mismatched n_items and parameter lengths", {
expect_error(
irt_design(model = "1PL", n_items = 10, item_params = list(b = rnorm(5))),
"n_items|length|mismatch"
)
expect_error(
irt_design(model = "2PL", n_items = 10,
item_params = list(a = rlnorm(10), b = rnorm(5))),
"n_items|length|mismatch"
)
})
test_that("irt_design rejects non-positive discrimination values", {
expect_error(
irt_design(model = "2PL", n_items = 5,
item_params = list(a = c(-1, 1, 1, 1, 1), b = rnorm(5))),
"discrimination|positive|a "
)
})
test_that("irt_design rejects non-numeric item parameters", {
expect_error(
irt_design(model = "1PL", n_items = 3,
item_params = list(b = c("a", "b", "c"))),
"numeric"
)
})
test_that("irt_design rejects item_params that is not a list", {
expect_error(
irt_design(model = "1PL", n_items = 5, item_params = rnorm(5)),
"list"
)
})
test_that("irt_design rejects NA values in item parameters", {
expect_error(
irt_design(model = "1PL", n_items = 5,
item_params = list(b = c(1, 2, NA, 4, 5))),
"NA|missing"
)
})
# --- Edge Cases --------------------------------------------------------------
test_that("irt_design handles single-item design", {
design <- irt_design(model = "1PL", n_items = 1, item_params = list(b = 0))
expect_s3_class(design, "irt_design")
expect_equal(design$n_items, 1L)
})
test_that("irt_design handles large item count", {
design <- irt_design(model = "1PL", n_items = 100,
item_params = list(b = rnorm(100)))
expect_s3_class(design, "irt_design")
expect_equal(design$n_items, 100L)
})
# --- S3 Class Structure ------------------------------------------------------
test_that("irt_design returns an object with correct class", {
design <- irt_design(model = "1PL", n_items = 5, item_params = list(b = rnorm(5)))
expect_s3_class(design, "irt_design")
expect_true(is.list(design))
})
test_that("irt_design object contains all expected elements", {
design <- irt_design(model = "2PL", n_items = 10,
item_params = list(a = rlnorm(10), b = rnorm(10)))
expected_names <- c("model", "n_items", "item_params", "theta_dist", "n_factors")
expect_true(all(expected_names %in% names(design)))
})
# --- Print Method ------------------------------------------------------------
test_that("print.irt_design produces informative output", {
design <- irt_design(model = "2PL", n_items = 20,
item_params = list(a = rlnorm(20), b = rnorm(20)))
output <- capture.output(print(design))
output_text <- paste(output, collapse = "\n")
# Should mention the model type
expect_match(output_text, "2PL", fixed = TRUE)
# Should mention the number of items
expect_match(output_text, "20")
# Should mention theta distribution
expect_match(output_text, "normal|theta", ignore.case = TRUE)
# Should return the object invisibly
expect_invisible(print(design))
})
test_that("print.irt_design works for GRM", {
a <- rlnorm(5, 0, 0.25)
b <- matrix(sort(rnorm(20)), nrow = 5, ncol = 4)
design <- irt_design(model = "GRM", n_items = 5, item_params = list(a = a, b = b))
output <- capture.output(print(design))
output_text <- paste(output, collapse = "\n")
expect_match(output_text, "GRM", fixed = TRUE)
# Should indicate polytomous / categories info
expect_match(output_text, "5 items|categor", ignore.case = TRUE)
})
# --- Immutability Design Intent ----------------------------------------------
test_that("irt_design object is a plain list (not reference class)", {
design <- irt_design(model = "1PL", n_items = 5, item_params = list(b = rnorm(5)))
# S3 objects are plain lists; confirm no R6/R5 reference semantics
expect_false(is.environment(design))
expect_true(is.list(design))
})
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.