Skip to content

test: add Visualization Unit Tests#49

Open
bianjh-cloud wants to merge 17 commits into
mainfrom
47-unit-tests-for-split_featureplot
Open

test: add Visualization Unit Tests#49
bianjh-cloud wants to merge 17 commits into
mainfrom
47-unit-tests-for-split_featureplot

Conversation

@bianjh-cloud
Copy link
Copy Markdown
Collaborator

@bianjh-cloud bianjh-cloud commented Apr 17, 2026

Changes

make_volcano_plot.R
Refactored volcano logic to use snake_case (avg_log_2_fc), aligned significance labels, and ensured consistent internal data-frame column naming.

Regenerated docs to match the updated argument/field naming in the R function.

Added comprehensive volcano tests covering object creation, transformations, significance logic, edge cases, and missing-column validation.

split_featurePlot.R
Added/updated split feature plot tests for layout behavior, return types, parameter options, and invalid-input handling.

make_bubble_plot.R
Added unit tests for bubble plot creation, structure checks, identity handling, scaling behavior, and expected error cases.

Issues

issue 47 - see checklist

PR Checklist

(Strikethrough any points that are not applicable.)

  • This comment contains a description of changes with justifications, with any relevant issues linked.
  • Write unit tests for any new features, bug fixes, or other code changes.
  • [ ] Update the docs if there are any API changes (roxygen2 comments, vignettes, readme, etc.).
  • [ ] Update NEWS.md with a short description of any user-facing changes and reference the PR number. Follow the style described in https://style.tidyverse.org/news.html
  • Run devtools::check() locally and fix all notes, warnings, and errors.
  • R-CMD-check succeeds on the most recent user commit.

bianjh-cloud and others added 4 commits March 23, 2026 10:05
- Add test-make_bubble_plot.R and test-make_volcano_plot.R
- Update test-split_featurePlot.R
- Remove source() calls from test-make_volcano_plot.R
- Rename avg_log2FC to avg_log_2_fc in make_volcano_plot.R and tests
- Hardcode fixed math expectations (log10 transforms)
- Regenerate man/make_volcano_plot.Rd

Generated using AI
@bianjh-cloud bianjh-cloud linked an issue Apr 17, 2026 that may be closed by this pull request
@github-actions github-actions Bot added the SCOT RepoName label Apr 17, 2026
@kelly-sovacool kelly-sovacool changed the title Visualization Unit Tests test: add Visualization Unit Tests Apr 29, 2026
Copy link
Copy Markdown
Member

@kelly-sovacool kelly-sovacool left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Significant work is needed to improve these tests. Some patterns I noticed:

  • Make sure you're testing the behavior of SCOT functions, not functions from base R or other packages, and not merely the function definitions.
  • Make sure each test actually runs the SCOT functions mentioned in the test_that description, or tests the results of a previously-run SCOT function.
  • Try to make the tests for functions that return ggplot objects do more than just check that the result is a ggplot. You can test that the various function arguments modify the plots as expected by extracting the plot data, layers, and other plot attributes.

Comment thread tests/testthat/helper-selectData.R Outdated
Comment thread tests/testthat/helper-selectData.R Outdated
Comment thread tests/testthat/helper-selectData.R Outdated
Comment thread tests/testthat/test-cluster_metrics.R Outdated
Comment thread R/seurat_clustering.R
resolution = 0.8,
algorithm = 3,
resolution = resolution,
algorithm = algorithm,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch! using parameters is important

ncl_low <- nlevels(SeuratObject::Idents(low_res))
ncl_high <- nlevels(SeuratObject::Idents(high_res))

expect_true(ncl_high >= ncl_low)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since you set seeds above (good job!), you can use the actual values rather than this conditional

Comment thread tests/testthat/test-seurat_clustering.R Outdated
Comment thread tests/testthat/test-seurat_clustering.R Outdated
Comment on lines +10 to +14
brca.data = selectData("wu_et_al_BRCA")
input_cells <- colnames(brca.data)

set.seed(42)
brca.clustered = seurat_clustering(so_in = brca.data, npcs_in = 30)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

follow the tidyverse style guide

Suggested change
brca.data = selectData("wu_et_al_BRCA")
input_cells <- colnames(brca.data)
set.seed(42)
brca.clustered = seurat_clustering(so_in = brca.data, npcs_in = 30)
brca_data <- selectData("wu_et_al_BRCA")
input_cells <- colnames(brca.data)
set.seed(42)
brca_clustered <- seurat_clustering(so_in = brca.data, npcs_in = 30)

Comment thread tests/testthat/test-split_featurePlot.R Outdated
Comment on lines +86 to +265
test_that("split_featurePlot returns NULL silently with return_list = FALSE", {
so <- brca_data
res <- split_featurePlot(
so = so,
features = features[1],
split_ident = "orig.ident",
plot_image = FALSE,
return_list = FALSE,
reduction = "umap"
)
expect_null(res)
})

test_that("split_featurePlot runs when provided with only ncol", {
so <- brca_data
single_feature <- rownames(so@assays$SCT@scale.data)[1]

res <- split_featurePlot(
so = so,
features = single_feature,
split_ident = "orig.ident",
ncol = 2,
nrow = NA,
plot_image = FALSE,
return_list = TRUE,
reduction = "umap"
)

expect_true(is.list(res))
expect_true(inherits(res[[single_feature]], "ggplot"))
})

test_that("split_featurePlot works with scalar numeric cutoff values", {
so <- brca_data
single_feature <- rownames(so@assays$SCT@scale.data)[1]

res <- split_featurePlot(
so = so,
features = single_feature,
split_ident = "orig.ident",
min.cutoff = 0,
max.cutoff = 5,
plot_image = FALSE,
return_list = TRUE,
reduction = "umap"
)

expect_true(is.list(res))
expect_true(inherits(res[[single_feature]], "ggplot"))
})

test_that("split_featurePlot runs with label = TRUE", {
so <- brca_data
single_feature <- rownames(so@assays$SCT@scale.data)[1]

res <- split_featurePlot(
so = so,
features = single_feature,
split_ident = "orig.ident",
label = TRUE,
plot_image = FALSE,
return_list = TRUE,
reduction = "umap"
)

expect_true(is.list(res))
expect_true(inherits(res[[single_feature]], "ggplot"))
})

test_that("split_featurePlot works with order = TRUE", {
so <- brca_data
single_feature <- rownames(so@assays$SCT@scale.data)[1]

res <- split_featurePlot(
so = so,
features = single_feature,
split_ident = "orig.ident",
order = TRUE,
plot_image = FALSE,
return_list = TRUE,
reduction = "umap"
)

expect_true(is.list(res))
expect_true(inherits(res[[single_feature]], "ggplot"))
})

test_that("split_featurePlot works with slot = 'data'", {
so <- brca_data
single_feature <- rownames(so@assays$SCT@data)[1]

res <- split_featurePlot(
so = so,
features = single_feature,
split_ident = "orig.ident",
slot = "data",
plot_image = FALSE,
return_list = TRUE,
reduction = "umap"
)

expect_true(is.list(res))
expect_true(inherits(res[[single_feature]], "ggplot"))
})

test_that("split_featurePlot works with single split group", {
so <- brca_data
single_feature <- rownames(so@assays$SCT@scale.data)[1]

# Create metadata with single group value
so$single_group <- "group_1"

res <- split_featurePlot(
so = so,
features = single_feature,
split_ident = "single_group",
plot_image = FALSE,
return_list = TRUE,
reduction = "umap"
)

expect_true(is.list(res))
expect_true(inherits(res[[single_feature]], "ggplot"))
})


test_that("split_featurePlot works with numeric split_ident values", {
so <- brca_data
single_feature <- rownames(so@assays$SCT@scale.data)[1]

# Create numeric metadata
so$numeric_group <- sample(1:3, ncol(so), replace = TRUE)

res <- split_featurePlot(
so = so,
features = single_feature,
split_ident = "numeric_group",
plot_image = FALSE,
return_list = TRUE,
reduction = "umap"
)

expect_true(is.list(res))
expect_true(inherits(res[[single_feature]], "ggplot"))
})

test_that("split_featurePlot handles empty feature list", {
so <- brca_data

res <- split_featurePlot(
so = so,
features = character(0),
split_ident = "orig.ident",
plot_image = FALSE,
return_list = TRUE,
reduction = "umap"
)

expect_true(is.list(res))
expect_equal(length(res), 0)
})

test_that("split_featurePlot with asymmetric cutoff pair", {
so <- brca_data
single_feature <- rownames(so@assays$SCT@scale.data)[1]

res <- split_featurePlot(
so = so,
features = single_feature,
split_ident = "orig.ident",
min.cutoff = "q10",
max.cutoff = 3.5,
plot_image = FALSE,
return_list = TRUE,
reduction = "umap"
)

expect_true(is.list(res))
expect_true(inherits(res[[single_feature]], "ggplot"))
})
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps you could add expectations that do more than only check that the function was able to successfully return lists of ggplots, and actually test that the different function arguments you provide have an effect on the ggplot objects themselves, e.g. testing the layers, labels, plot data, etc;

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added some additional expectations for checking layers and plot data

Comment thread R/seurat_clustering.R
@@ -15,6 +15,25 @@
#' @return The updated Seurat single cell object with recalculated PCA,
#' neighbors, UMAP and clusters
seurat_clustering <- function(so_in, npcs_in, resolution = 0.8, algorithm = 3) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should consider renaming this function to a verb. see https://style.tidyverse.org/functions.html @wong-nw

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

SCOT RepoName

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unit Tests for Visualization and Clustering Functions

2 participants