skip to content

TestLauncher for IDE Test Runs

Running or debugging individual tests through the Tooling API's TestLauncher rather than a whole task graph. Interviewers ask because it explains how an IDE's run arrow reaches a single test method.

on this pageshow

questions

6

What is the Tooling API's TestLauncher, and why would an IDE use it instead of running a regular Gradle test task?

level: juniorimportance: must knowfreq 45%

answer

  1. connection.newTestLauncher()
  2. withJvmTestClasses / withJvmTestMethods
  3. runs selected tests, not whole task
  4. powers IDE gutter run-arrow
  5. resolves matching Test tasks

basics

~20 s

TestLauncher is a Tooling API entry point (connection.newTestLauncher()) that runs specific tests by class or method, instead of invoking a whole test task. IDEs use it to run or debug a single test the user selected.

solid answer

~40 s

The Gradle Tooling API lets an external process (an IDE like IntelliJ or Eclipse) drive a build in another JVM. `TestLauncher`, obtained from `connection.newTestLauncher()`, is a specialized launcher for executing tests. Instead of running a full `test` task and all its tests, the IDE declares which tests it wants — `withJvmTestClasses("com.acme.FooTest")` or `withJvmTestMethods("com.acme.FooTest", "shouldWork")` — and Gradle figures out the matching test tasks and runs only those tests. This is how the green 'run single test' arrow works. It honors normal build configuration (classpath, JVM args, test framework) but narrows execution to the selected tests, giving fast, targeted feedback and a foundation for debugging.

code

kotlin · 9 lines
kotlin
GradleConnector.newConnector()
    .forProjectDirectory(projectDir)
    .connect()
    .use { connection ->
        connection.newTestLauncher()
            .withJvmTestClasses("com.acme.OrderServiceTest")
            .setStandardOutput(System.out)
            .run()
    }

go deeper

for a junior

Know that newTestLauncher() runs specific tests and powers the IDE's single-test run button.

for a middle

Explain withJvmTestClasses/withJvmTestMethods and that Gradle resolves the matching Test tasks automatically.

for a senior

Discuss event/progress listeners for live test trees and async run via ResultHandler.

for a principal

Frame it as the contract between IDE and build for targeted execution, and how it underpins consistent test running across IDEs.

## The Tooling API in one paragraph The **Gradle Tooling API** is a client library that lets a separate program embed Gradle. The IDE runs in its own JVM and uses the Tooling API to start a Gradle *daemon* in another JVM, send it work, and receive results and events back. You start from a `GradleConnector`, get a `ProjectConnection`, and from that connection create *launchers* and *model builders*. ## Launchers vs. TestLauncher - `connection.newBuild()` returns a `BuildLauncher` — you give it task names (`forTasks("build")`) and it runs the task graph. - `connection.newTestLauncher()` returns a **`TestLauncher`** — a launcher specialized for tests. Rather than naming tasks, you name *tests*, and Gradle resolves which test tasks must run to execute them. ## Why IDEs prefer TestLauncher When a developer clicks the gutter arrow next to a single `@Test` method, the IDE does **not** want to run the entire `test` task. It wants exactly that one method. `TestLauncher` expresses that intent declaratively: - `withJvmTestClasses("com.acme.FooTest")` — run all tests in a class. - `withJvmTestMethods("com.acme.FooTest", "shouldWork")` — run a specific method. - `withTests(TestOperationDescriptor...)` / `withTestsFor(...)` — re-run tests identified from a previous run's events. Gradle then finds the `Test` tasks whose source sets contain those classes and runs only the selected tests inside them, applying the normal classpath, test framework (JUnit/TestNG/Spock), and JVM configuration. ## What you get back Like any launcher you can attach a `ResultHandler` for async runs, an `OutputStream` for stdout/stderr, and **progress/test event listeners** (`addProgressListener` with `OperationType.TEST`) so the IDE's test tree updates live. ```kotlin val connector = GradleConnector.newConnector() .forProjectDirectory(projectDir) connector.connect().use { connection -> connection.newTestLauncher() .withJvmTestMethods("com.acme.FooTest", "shouldWork") .setStandardOutput(System.out) .run() // blocking; throws on test/build failure } ``` ## Key takeaway TestLauncher = 'run these specific tests' as a first-class Tooling API operation, which is what powers IDE single-test run and debug.

  • How does Gradle know which test task to run when you only name a class?
    It matches the named classes/methods against the source sets feeding each Test task and runs the tests in whichever task(s) contain them; if none match, the run fails with a 'no matching tests' error.
  • Does run() block or return immediately?
    run() is blocking and throws on failure. There's also run(ResultHandler) for asynchronous execution that delivers success/failure via the handler.

BuildLauncher says 'run this build target'; TestLauncher says 'run exactly these tests' and lets Gradle work out which tasks must fire to do it — like ordering a single dish instead of the whole set menu.

saying these in an interview costs you the question

  • Saying TestLauncher runs the whole test task — it runs only the selected tests.
  • Confusing TestLauncher with BuildLauncher.forTasks("test").

context

open as a page

How do you select which tests run with TestLauncher — what's the difference between withJvmTestClasses and withJvmTestMethods?

level: middleimportance: must knowfreq 40%

basics

~10 s

withJvmTestClasses(className...) runs every test in the named class; withJvmTestMethods(className, methodName...) narrows it to specific methods. Both are accumulative — multiple calls add more selections.

open as a page

How does an IDE debug a single test through the Tooling API? Explain debugTestsOn(port) and what happens under the hood.

level: middleimportance: should knowfreq 35%

basics

~10 s

TestLauncher.debugTestsOn(port) starts the test JVM with a JDWP debug agent that connects back to the IDE's debugger listening on that port. The IDE's breakpoints then hit in the test process.

open as a page

How would you implement 're-run failed tests' from a previous Tooling API run? Explain withTests and TestOperationDescriptor.

level: seniorimportance: should knowfreq 25%

basics

~10 s

During the first run, attach a progress listener for TEST events and collect the TestOperationDescriptors of failed tests. On the next run, pass those descriptors to TestLauncher.withTests(...) to re-execute exactly those tests.

open as a page

Contrast running tests via TestLauncher with running them via BuildLauncher.forTasks("test") plus the --tests filter. When does each make sense?

level: seniorimportance: should knowfreq 22%

basics

~20 s

TestLauncher selects tests declaratively and lets Gradle find the right task, with structured test events and per-test debug. BuildLauncher.forTasks("test") runs a named task and you narrow it with the --tests command-line filter. TestLauncher is purpose-built for IDE test execution.

open as a page

What error cases and edge conditions should an IDE integration handle when using TestLauncher (no matching tests, version compatibility, failure reporting)?

level: seniorimportance: nice to knowfreq 18%

basics

~20 s

Handle 'no matching tests' (selection matched nothing fails the run), test failures surfaced as a build failure with details from TEST events, and Tooling-API-vs-Gradle version compatibility. Always capture events for accurate reporting and propagate exceptions to the UI.

open as a page