Hi,
I’m reopening a discussion related to #916, but from a slightly different angle.
I understand the rationale for keeping testthat::test_dir() flat:
- deterministic ordering,
- simple fixture semantics,
- explicitness over discovery magic.
That model makes a lot of sense for R packages, where tests are often organized around exported APIs and tests/testthat/ effectively represents a single suite.
However, I wonder whether the broader use of testthat in application-oriented workflows might justify revisiting this.
In the Shiny ecosystem, testthat increasingly underpins multiple layers of testing:
- pure unit tests for extracted logic,
shiny::testServer() for module/server logic,
shinytest2 for integration and snapshot testing.
As applications grow, these tend to group naturally by concern. For example:
tests/testthat/
unit/
test-utils.R
test-validation.R
modules/
test-auth.R
test-upload.R
integration/
test-login-flow.R
_snaps/
This structure maps well to how larger Shiny apps evolve:
- reusable helpers and business logic,
- module-level reactive/server tests,
- end-to-end user-flow tests.
The current recommendation seems to be flattening all test files into the root:
tests/testthat/
test-utils.R
test-validation.R
test-auth.R
test-upload.R
test-login-flow.R
which works, but becomes harder to navigate as the number of tests grows.
To be clear, I’m not suggesting changing defaults.
But would there be interest in supporting an opt-in mode like:
test_dir("tests/testthat", recursive = TRUE)
with constrained semantics, for example:
- default remains
FALSE,
- execution order defined lexically over relative paths,
- fixture files (
helper-*, setup-*, teardown-*) remain scoped exactly as they are today (i.e. directory-local, matching current test_file() behavior).
This is already possible to implement manually with recursive file discovery + test_file(), so this is less about adding new capability and more about standardizing a pattern that seems increasingly relevant for larger app-oriented projects.
I’m curious whether maintainers still see recursive discovery as fundamentally outside the scope of testthat, or whether the growing use of testthat as a general testing runner (not just for packages) changes that perspective.
Hi,
I’m reopening a discussion related to #916, but from a slightly different angle.
I understand the rationale for keeping
testthat::test_dir()flat:That model makes a lot of sense for R packages, where tests are often organized around exported APIs and
tests/testthat/effectively represents a single suite.However, I wonder whether the broader use of
testthatin application-oriented workflows might justify revisiting this.In the Shiny ecosystem,
testthatincreasingly underpins multiple layers of testing:shiny::testServer()for module/server logic,shinytest2for integration and snapshot testing.As applications grow, these tend to group naturally by concern. For example:
This structure maps well to how larger Shiny apps evolve:
The current recommendation seems to be flattening all test files into the root:
which works, but becomes harder to navigate as the number of tests grows.
To be clear, I’m not suggesting changing defaults.
But would there be interest in supporting an opt-in mode like:
with constrained semantics, for example:
FALSE,helper-*,setup-*,teardown-*) remain scoped exactly as they are today (i.e. directory-local, matching currenttest_file()behavior).This is already possible to implement manually with recursive file discovery +
test_file(), so this is less about adding new capability and more about standardizing a pattern that seems increasingly relevant for larger app-oriented projects.I’m curious whether maintainers still see recursive discovery as fundamentally outside the scope of
testthat, or whether the growing use oftestthatas a general testing runner (not just for packages) changes that perspective.