A Java codebase mixes Mockito's classic when/verify calls and its BDD given/then calls inside the same test classes. What practical problems does that create, and how would you settle a convention for the team?
answer
- no technical breakage — same engine
- lost given/when/then rhythm
- BDDMockito.then vs AssertJ BDDAssertions.then
- one static import + build-failing rule
- migrate opportunistically, not big-bang
basics
~20 sNothing breaks technically, but readers lose the given/when/then rhythm, reviews re-argue style per file, and Mockito's static then(...) collides with AssertJ's then(...). Pick one style, enforce it with an import rule in the linter or an architecture test, and migrate opportunistically rather than in a mass rewrite.
solid answer
~50 sTechnically it is harmless — both APIs are the same engine and `BDDMockito` extends `Mockito`, so they interoperate freely. The costs are human. Readability: the value of BDD naming is the rhythm given / act / then. A file where half the setup uses `when(...)` loses it, and readers must decide line by line whether `when` means setup or the action. Ambiguity: `org.mockito.BDDMockito.then` collides with AssertJ's `org.assertj.core.api.BDDAssertions.then`. Static-importing both compiles — resolution is by argument type — but it reads badly and misleads newcomers and IDE auto-import. Drift by example: mixed files teach the next person both styles. My convention: one style per repository, one static import (`BDDMockito.*` already provides `mock`, `verify` and matchers), and an assertion spelling that avoids the `then` collision, typically `assertThat`. Enforce it with a build-failing import rule, migrate files as they are touched, and keep the rule small enough that reviewers never debate it again.
code
java · 10 linesimport static org.mockito.BDDMockito.*; // then(mock).should()
import static org.assertj.core.api.BDDAssertions.then; // then(value).isEqualTo()
// compiles, but one name carries two unrelated meanings in the same file
then(repository).should().save(order);
then(order.status()).isEqualTo(SHIPPED);
// preferred: one Mockito style, assertThat for assertions
then(repository).should().save(order);
assertThat(order.status()).isEqualTo(SHIPPED);go deeper
Say plainly that both styles work and behave identically, but a project should pick one for readability.
Name the concrete costs — lost given/when/then rhythm, review churn, the AssertJ then collision — and the one-static-import remedy.
Describe enforcement via a linter or architecture-test import rule and an opportunistic migration plan rather than a mass rewrite.
Keep it proportionate: automate the trivial decision, then redirect attention to what determines test value — mocking boundaries and behaviour-focused verification.
## Is mixing actually broken? No. `BDDMockito` extends `Mockito`, both funnel into the same stubbing and verification engine, and a test can use `when(...)` on one line and `then(mock).should()` on the next. Strictness, matchers and failure messages are identical. An answer claiming a technical defect is wrong; the argument is about communication and maintenance. ## What it costs **The rhythm disappears.** BDD naming exists so a test reads as given / act / then, with the word 'when' reserved for the action under test. Mixed files defeat that: the reader sees `when(...)` used for setup two lines above the real action, and has to slow down to classify each line. **Review friction.** With no rule, every pull request can re-open the question. Style debates about stubbing verbs are pure overhead, and they recur forever because each new file is a fresh decision. **The then collision.** AssertJ ships `BDDAssertions.then(...)` for BDD-style assertions — a static method named `then`, exactly like `BDDMockito.then(...)`. Importing both statically compiles, because overload resolution picks by argument type, but the file then has two unrelated meanings for one identifier. Readers, and IDE auto-import, get it wrong regularly. A team wanting both should qualify one of them. **Propagation by example.** People write tests by copying the nearest file, so a repository with both styles keeps producing both indefinitely. ## How to settle it Pick deliberately, based on the team's habits: - If tests already carry `// given / when / then` comments, BDD naming makes the code match the comments — the clearest win. - Kotlin codebases have an extra reason: `when` is a language keyword, so classic Mockito must be written with backticks. `given` avoids that. - If most people know only the classic API and tests are short, staying classic is perfectly defensible — consistency beats the naming benefit. Then make the decision cheap to follow: one static import in the team's test template, an IDE live template, and a linter rule. A forbidden-import or regexp check in Checkstyle, an import rule in an architecture test, or a custom detekt/ktlint rule in Kotlin will fail the build on the disallowed style, which ends the discussion permanently. Migration should be opportunistic: new tests follow the rule, existing files convert when edited for other reasons. A repository-wide mechanical rewrite touches every test file, creates a diff reviewers cannot read meaningfully, and risks a careless replacement inside stubbing chains — the payoff does not justify it. ## What a strong answer adds Proportion. This is a style decision with no correctness implications, so the mature position is: pick one, automate the check, migrate lazily, and spend remaining attention on what actually affects the tests' value — what gets mocked, and whether verifications assert behaviour rather than implementation. Treating style as a major engineering concern misallocates effort; dismissing it as irrelevant misses the small but recurring cost in reviews and onboarding.
- How would you enforce the chosen style so it does not resurface in every review?With a build-failing rule rather than a guideline: a Checkstyle illegal-import or regexp check, an architecture test asserting that test sources do not reference the disallowed static import, or a custom detekt rule in Kotlin. Pair it with an IDE live template and a single import line in the test template so the compliant path is also the easiest one.
- Would you run a repository-wide automated rewrite to unify the style?Generally no. It touches every test file, produces a diff nobody can review carefully, and a careless replacement inside stubbing chains can change behaviour silently. Opportunistic migration, where files convert as they are edited anyway, reaches the same end state with far less risk and no review-burden spike.
saying these in an interview costs you the question
- Claiming that mixing the two APIs causes real defects or interferes with strictness
- Not knowing that AssertJ also exposes a static then(...) that collides with BDDMockito's
- Proposing a big-bang rewrite of every test file to unify style
- Treating the choice as a matter of correctness rather than convention
- Assuming you must import both Mockito.* and BDDMockito.* to get verify and matchers