How do you select which tests run with TestLauncher — what's the difference between withJvmTestClasses and withJvmTestMethods?
answer
- withJvmTestClasses = whole class
- withJvmTestMethods = specific methods
- calls are additive, not replacing
- withTestsFor + forTaskPath disambiguates
- unmatched name = run fails
basics
~10 swithJvmTestClasses(className...) runs every test in the named class; withJvmTestMethods(className, methodName...) narrows it to specific methods. Both are accumulative — multiple calls add more selections.
solid answer
~40 s`TestLauncher` selection is declarative and additive. `withJvmTestClasses("com.acme.FooTest")` runs all test methods in that class. `withJvmTestMethods("com.acme.FooTest", "a", "b")` runs only methods `a` and `b` of `FooTest`. You can call them repeatedly to build up a set; selections accumulate rather than replace. Both take JVM class names (fully qualified), and Gradle matches them against the test classes produced by the project's `Test` tasks. If you have a descriptor from a previous run (a `TestOperationDescriptor` captured via a progress listener), `withTests(...)` / `withTestsFor(...)` re-run exactly those. A common pitfall: passing a class name that no `Test` task contains causes a failure — Gradle reports it can't find matching tests rather than silently passing.
code
kotlin · 4 linesconnection.newTestLauncher()
.withJvmTestClasses("com.acme.PricingTest")
.withJvmTestMethods("com.acme.OrderTest", "placesOrder", "rejectsEmpty")
.run() // runs all of PricingTest + two methods of OrderTestgo deeper
Know the two main methods and that one runs a whole class, the other specific methods.
Explain additive semantics, fully-qualified names, and the no-match-fails behavior.
Use withTestsFor/forTaskPath to disambiguate multi-source-set cases and withTests for descriptor-based re-runs.
Design the IDE-to-build selection contract so re-run-failed and multi-module targeting are deterministic across source sets.
## The selection API `TestLauncher` exposes several ways to say 'these tests': - **`withJvmTestClasses(String... classNames)`** — fully-qualified class names; runs all tests in each. - **`withJvmTestMethods(String className, String... methods)`** — one class, specific method names. (There's also a Collection overload.) - **`withTests(TestOperationDescriptor...)` / `withTests(Iterable<...>)`** — runs tests identified by descriptors you captured from a previous build's test events. - **`withTestsFor(Action<TestSpecs>)`** — a structured DSL (`TestSpecs`) for richer selection, e.g. `forTaskPath(":app:test").includeClass(...).includeMethod(...)`, useful when the same class exists in multiple tasks/source sets and you must disambiguate by task path. ## Additive semantics These calls **accumulate**. Calling `withJvmTestClasses("A")` then `withJvmTestMethods("B", "m")` selects all of `A` plus method `m` of `B`. There's no implicit 'replace'. ## How matching works Gradle takes your selections and finds the `Test` tasks whose compiled output contains the named classes. It runs those tasks but filters execution to the selected tests (similar in spirit to the `--tests` CLI filter, but driven programmatically). If a name matches **nothing**, the run fails — this protects against typos silently 'passing'. ## withTestsFor / TestSpecs for disambiguation When the same class name lives in `test` and `integrationTest` source sets, plain class selection runs it in **both**. `withTestsFor` lets you pin a task path: ```kotlin connection.newTestLauncher() .withTestsFor { specs -> specs.forTaskPath(":app:test") .includeMethod("com.acme.FooTest", "shouldWork") } .run() ``` ## Practical guidance for IDE integration - For a 'run class' action: `withJvmTestClasses`. - For 'run method': `withJvmTestMethods`. - For 're-run failed': capture descriptors via the test progress listener and feed them to `withTests(...)`. - For multi-source-set ambiguity: `withTestsFor`/`forTaskPath`.
- The same test class exists in both the test and integrationTest source sets. What happens with withJvmTestClasses, and how do you target just one?It runs the class in both matching Test tasks. Use withTestsFor { it.forTaskPath(":app:integrationTest").includeClass(...) } to pin a single task path.
- What happens if you pass a class name that no Test task contains?The run fails with a 'no matching tests' error rather than reporting success — a guard against typos.
- How would you implement 're-run only the failed tests'?Capture the failing tests' TestOperationDescriptors from the previous run's progress events, then pass them to withTests(...) on a new TestLauncher.
saying these in an interview costs you the question
- Thinking a later withJvm... call replaces an earlier selection — they accumulate.
- Assuming a non-matching class name is silently skipped — it fails the run.
- Forgetting that class-name selection can run the same class in multiple source sets.