What is the difference between invoking `mvn test` (a phase) and `mvn surefire:test` (a goal directly)? When would you use each?
answer
- phase = run chain up to it
- goal = just that one goal
- direct goal skips compile -> stale classes
- unbound goals (dependency:tree) only run directly
- CI uses phases
basics
~20 smvn test runs the whole lifecycle up to test (validate, compile, test-compile, then tests). mvn surefire:test runs only that one goal, skipping compilation, so it can fail or use stale classes if you haven't built first.
solid answer
~40 sA phase invocation (`mvn test`) triggers the full chain: Maven executes every phase in order up to `test`, so resources are copied, main and test sources are compiled, then `surefire:test` runs against freshly compiled classes. A direct goal invocation (`mvn surefire:test`) runs only that single goal with none of the preceding phases — no recompile, no resource copy. That is faster for re-running tests when nothing changed, but dangerous if sources changed because it tests stale `target/classes`. Direct goals are also how you call goals that aren't bound to any phase (e.g., `mvn dependency:tree`, `mvn help:effective-pom`, `mvn versions:set`). Rule of thumb: use a phase for a correct, repeatable build; use a direct goal for ad-hoc tooling or fast iteration when you accept the staleness trade-off.
code
bash · 3 linesmvn test # compiles main + test, then runs tests (correct)
mvn surefire:test # ONLY runs tests against existing target/classes (fast, can be stale)
mvn dependency:tree # unbound utility goal; phase invocation can't reach itgo deeper
Know mvn test runs more than just tests (it compiles first).
Explain that a direct goal skips the preceding phases and can hit stale classes.
Decide between phase vs direct goal based on correctness vs speed and recognize unbound utility goals.
Set team conventions (CI uses phases; direct goals only for tooling) and educate on the stale-classes failure mode.
## Two ways to invoke Maven The Maven command line accepts both **phases** and **plugin goals**: ```bash mvn test # a phase mvn surefire:test # a goal (plugin:goal) mvn clean package # mixing: clean lifecycle phase + default lifecycle phase ``` ## Phase invocation = run the chain `mvn test` tells Maven: execute the `default` lifecycle from the start **up to and including** `test`. Concretely it runs (for jar packaging): ``` validate -> ... -> process-resources (resources:resources) -> compile (compiler:compile) -> process-test-resources (resources:testResources) -> test-compile (compiler:testCompile) -> test (surefire:test) ``` So your classes and test classes are guaranteed fresh before tests run. This is the **correct, reproducible** path. ## Direct goal invocation = just that goal `mvn surefire:test` runs **only** `surefire:test`. Nothing recompiles. If you edited `src/main/java` but didn't rebuild, Surefire tests the **stale** `target/classes`, producing misleading green/red results. It is faster (no compile) but you own the staleness risk. ## Goals with no phase binding Many utility goals are **not bound** to any phase and can only be run directly: - `mvn dependency:tree` — print the resolved dependency graph. - `mvn help:effective-pom` — show the merged POM. - `mvn versions:set -DnewVersion=2.0.0` — rewrite versions. - `mvn exec:java -Dexec.mainClass=...` — run a main class. These never appear in a lifecycle binding, so you must invoke them by `plugin:goal`. ## Choosing - **CI / release / anything that must be correct:** use phases (`mvn verify`, `mvn install`). - **Fast local test re-run when you KNOW nothing changed:** `mvn surefire:test` saves a compile. - **Tooling / inspection / one-off mutation:** direct goal is the only option. ## Gotcha `mvn surefire:test` skipping compilation is the #1 'my fix didn't take effect' trap. When in doubt, run the phase.
- Why might `mvn surefire:test` show passing tests for code you just broke?It does not recompile; it runs against the previously compiled target/classes, so your new (broken) source was never built.
- How do you run a goal like dependency:tree that has no phase binding?Invoke it directly as plugin:goal, e.g. `mvn dependency:tree`; no phase will trigger it because it isn't bound to the lifecycle.
saying these in an interview costs you the question
- Claiming `mvn surefire:test` recompiles sources first
- Saying direct goals always run preceding phases
- Believing every goal can be reached via some phase