Resource library

QA Interview

Top 30 JUnit Interview Questions and Answers (2026)

Prepare with the top JUnit interview questions, practical JUnit Jupiter answers, runnable Java examples, lifecycle concepts, extensions, and CI advice.

25 min read | 3,570 words

TL;DR

The strongest answers to the top JUnit interview questions connect JUnit Jupiter APIs to deterministic test design. Be ready to write a small test, explain lifecycle and isolation, choose parameterized tests or extensions appropriately, and describe how the suite runs reliably in CI.

Key Takeaways

  • Explain Jupiter through test lifecycle, isolation, assertions, parameterization, extensions, and execution rather than reciting annotations.
  • Use per-method test instances and fresh fixtures by default to reduce order dependence and parallel execution risk.
  • Prefer assertAll for related checks, assertThrows for exception contracts, and parameterized tests for meaningful input partitions.
  • Treat tags, timeouts, repeated tests, and display names as execution metadata, not substitutes for a sound test design.
  • Use extensions for focused cross-cutting behavior and keep invocation state in ExtensionContext.Store.
  • Separate fast unit feedback from slower integration suites in Maven or Gradle and publish machine-readable results in CI.

The top JUnit interview questions test much more than whether you remember @Test. Interviewers want to see whether you can design isolated Java tests, choose the right Jupiter feature, diagnose unreliable execution, and keep a suite useful as the codebase grows. A strong answer names the API, explains the tradeoff, and gives a compact example.

This guide covers 30 questions from foundational annotations through extensions, parallel execution, and CI. The examples use stable JUnit Jupiter APIs and avoid depending on an internal implementation. If your target project uses a maintained JUnit 5 line or JUnit 6, confirm the Java baseline and dependency versions in that repository, while keeping the design principles below unchanged.

TL;DR

Interview area What a strong candidate demonstrates Typical evidence
Lifecycle Knows callback order and fixture scope Fresh state in @BeforeEach
Assertions Checks behavior with useful failure messages assertAll, assertThrows
Data coverage Models partitions without duplicated methods @ParameterizedTest
Isolation Avoids ordering and shared mutable state Per-method instances
Extensibility Adds narrow reusable behavior Jupiter extension callbacks
Delivery Runs the right tests predictably in CI Tags, build tasks, XML reports

Prepare one concise definition, one runnable example, and one failure mode for each area. That combination sounds credible because it shows both API knowledge and engineering judgment.

1. What the top JUnit interview questions actually evaluate

JUnit questions usually evaluate four layers. First is syntax: annotations, assertions, and parameter sources. Second is execution: discovery, lifecycle, nested containers, tags, and build-tool integration. Third is design: test independence, readable fixtures, deterministic time, useful failure output, and the boundary between a unit test and an integration test. Fourth is diagnosis: why a test passes alone but fails in a suite, why no tests were discovered, or why parallel execution exposed a race.

Answer at the layer the question targets, then add one implication. For example, do not answer @BeforeEach only with its timing. Say that it runs before every test method and is appropriate for fresh mutable fixtures, while expensive shared resources need deliberate class-level management and cleanup. That second sentence shows that you understand why the callback exists.

Interviewers may still say JUnit 5 even when a project has adopted JUnit 6. Jupiter is the programming and extension model used in both contexts. Avoid arguing about naming. Clarify the project version only when a behavior depends on it, then answer with the public API. For broader preparation, pair this guide with Java automation scenario interview questions and practice explaining tradeoffs aloud.

2. JUnit Jupiter architecture and core annotations

The JUnit Platform launches testing frameworks on the JVM. Jupiter supplies the modern programming and extension model. A test class normally uses @Test, lifecycle callbacks such as @BeforeEach, assertions from org.junit.jupiter.api.Assertions, and an engine available at runtime. The Vintage engine is a separate compatibility path for older JUnit 3 and 4 tests when a migration requires it.

The most useful annotations are behavioral, not decorative. @Disabled records an intentional skip, but it should include a reason and should not become a defect graveyard. @Tag supports selection. @DisplayName improves human-readable output. @Nested groups related scenarios with their own setup. @TestInstance changes instance lifecycle and therefore changes the safety of mutable fields.

A basic Jupiter test is small and executable:

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

class CartTest {
    private Cart cart;

    @BeforeEach
    void createCart() {
        cart = new Cart();
    }

    @Test
    void addsItemPriceToTotal() {
        cart.add("Keyboard", 49);
        assertEquals(49, cart.total());
    }

    static final class Cart {
        private int total;
        void add(String name, int price) { total += price; }
        int total() { return total; }
    }
}

The production substitute is included only to make the example runnable. In a real project, test the public behavior of the production class rather than reproducing its implementation inside the test.

3. Lifecycle, fixture isolation, and nested test design

With the default per-method lifecycle, Jupiter creates a new test class instance for every test method. @BeforeAll runs once, then each test follows @BeforeEach, test method, and @AfterEach, with @AfterAll at the end. Superclass callbacks participate in a defined order, but a suite that relies on subtle callback ordering is usually hard to maintain.

Per-method instances are a helpful isolation boundary, not a complete guarantee. Static fields, singletons, files, databases, ports, clocks, and remote services can still be shared. Make mutable fixtures local to a test or recreate them in @BeforeEach. Use @AfterEach to release what that test owns, and preserve the original failure if cleanup also fails.

@TestInstance(TestInstance.Lifecycle.PER_CLASS) allows non-static @BeforeAll and one test instance for the class. It is useful when instance-level setup is necessary, but mutable fields are then shared between methods. That makes execution order and parallel safety more important. Do not select it merely to avoid typing static.

@Nested classes express context, such as an empty cart versus a populated cart. Outer setup can establish broad context and inner setup can refine it. Keep nesting shallow and scenario-focused. If setup becomes a hidden state machine, use helper factories or parameterized input instead. The JUnit 5 extensions guide for Java testers goes deeper into reusable lifecycle behavior.

4. Assertions, exceptions, timeouts, and assumptions

Assertions should describe externally observable behavior. assertEquals compares expected and actual values using the type's equality semantics. assertSame checks object identity. Arrays and iterables have dedicated assertions. Put expected first for conventional output, and use a lazy message supplier when constructing the message is expensive.

assertAll groups related assertions so a single run reports every failure in the group. It is valuable when all checks describe one result, such as an API response model. It is not permission to put unrelated scenarios in one method. assertThrows returns the exception, which lets the test verify a message or domain field. assertDoesNotThrow can communicate intent, although an unexpected exception already fails a normal test.

import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;

class PasswordPolicyTest {
    @Test
    void rejectsShortPasswordWithActionableReason() {
        PasswordException error = assertThrows(
                PasswordException.class,
                () -> PasswordPolicy.validate("abc"));

        assertAll(
                () -> assertEquals("TOO_SHORT", error.code()),
                () -> assertTrue(error.getMessage().contains("8")));
    }

    static final class PasswordException extends RuntimeException {
        private final String code;

        PasswordException(String code, String message) {
            super(message);
            this.code = code;
        }

        String code() {
            return code;
        }
    }

    static final class PasswordPolicy {
        static void validate(String value) {
            if (value.length() < 8) throw new PasswordException("TOO_SHORT", "Minimum is 8");
        }
    }
}

Use assertTimeout when the code may finish and the calling thread can wait. Preemptive timeout execution uses another thread, which can break thread-local transactions or security context. Assumptions abort a test when a valid environmental precondition is absent. They should not hide a required environment failure.

5. Parameterized, repeated, dynamic, and template tests

A parameterized test runs the same behavior contract with multiple arguments. Choose a source that keeps the case readable: @ValueSource for one simple value, @CsvSource for compact literals, @EnumSource for enum subsets, and @MethodSource for objects or derived cases. Give each invocation a useful name when the default display is ambiguous.

import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

class ShippingTest {
    @ParameterizedTest(name = "subtotal {0} -> fee {1}")
    @CsvSource({"0, 5", "49, 5", "50, 0", "120, 0"})
    void calculatesShipping(int subtotal, int expectedFee) {
        assertEquals(expectedFee, subtotal >= 50 ? 0 : 5);
    }
}

Good rows represent equivalence partitions and boundaries, not arbitrary samples. If a CSV row needs many flags or cryptic null markers, return named domain arguments from a method source. A parameterized test is a poor fit when cases require different workflows or assertions.

@RepeatedTest reruns a test a fixed number of times, often to observe repetition metadata or exercise a property with controlled variation. It does not prove the absence of flakiness. @TestFactory creates dynamic tests at runtime. Dynamic tests have different lifecycle behavior because callbacks wrap the factory, not each generated test body. A @TestTemplate is an extension-driven abstraction used by features such as parameterized tests. In interviews, explain when plain parameterization is clearer than building custom infrastructure.

6. Extensions, mocking boundaries, and test doubles

Jupiter extensions replace the runner and rule patterns used by JUnit 4. An extension can participate in lifecycle callbacks, resolve parameters, evaluate conditions, observe results, intercept invocations, or handle exceptions. Register a type declaratively with @ExtendWith, or a configured instance with @RegisterExtension.

Keep each extension focused. A timing extension may implement before and after test execution callbacks and store its start value in ExtensionContext.Store. A parameter resolver should claim a narrow type, preferably qualified by an annotation, so it does not conflict with another resolver. An exception handler that captures evidence should rethrow the original exception, adding capture failures as suppressed errors when appropriate.

JUnit itself is not a mocking library. Mockito, WireMock, MockWebServer, Testcontainers, and fakes solve different collaboration problems. Choose a real small value object when construction is cheap. Use a fake for meaningful in-memory behavior, a mock to verify a narrow interaction, and a stub server at an HTTP boundary. Do not mock the class under test. Do not verify every internal call, because that couples the test to implementation.

An interviewer may ask about @Mock or @InjectMocks as if they were JUnit features. State politely that they belong to Mockito and are commonly integrated through MockitoExtension. That distinction signals precise tool knowledge without derailing the answer.

7. Discovery, tags, parallel execution, and CI

The build tool discovers tests through the JUnit Platform provider and naming or include rules configured in the project. A test can compile yet remain undiscovered because the engine is missing, the provider is old, a class is excluded, or JUnit 4 and Jupiter annotations were mixed. Diagnose from the dependency tree, test task configuration, and discovery output before changing the test.

Tags express stable categories such as unit, integration, or contract. Keep business ownership and priority out of a sprawling tag vocabulary. Maven Surefire commonly runs unit tests during test, while Failsafe can run integration tests during integration-test and verify. Gradle can define separate suites or tasks. The exact build configuration belongs in version control.

Parallel execution is opt-in through JUnit configuration. Enabling it does not make tests thread-safe. Audit static state, shared mock servers, fixed ports, database rows, system properties, and non-thread-safe test doubles. Use unique resources and resource locks only where genuine sharing cannot be removed. Test order annotations can make a documented sequence possible, but ordered tests are not a repair for hidden coupling.

In CI, publish JUnit XML results and bounded diagnostic artifacts. Retry only after classifying the failure and exposing the original attempt. A green result produced by unconditional retries hides risk. For broader delivery design, see Allure reporting in CI.

8. How to answer top JUnit interview questions at senior level

Use a three-part pattern: define the feature, explain the design decision, then name a failure mode. For @BeforeAll, say when it executes, why you would use it, and how shared mutable state can harm isolation. For parameterized tests, explain the source, the input partitions, and when separate scenario methods are clearer. This keeps answers short while proving depth.

When given a coding task, begin with the behavior and boundary cases. Use Arrange, Act, Assert as a thinking aid, but avoid comments that merely restate each line. Give the test a behavior-focused name, keep the fixture minimal, and make the assertion failure useful. Run it if the environment allows, then mention one additional case you would add.

For a flaky-suite scenario, do not jump directly to retries. Ask whether the failure is order-dependent, timing-dependent, data-dependent, or environment-dependent. Reproduce with seeds, repeated execution, changed order, and isolated resources. Compare timestamps and correlation IDs. The scenario-based SDET interview guide is useful for practicing that diagnostic structure.

If you do not remember a minor annotation attribute, say what you would verify in the project documentation. Interview credibility comes from accurate reasoning, not pretending to recall every option.

Interview Questions and Answers

Q1: What is JUnit Jupiter?

JUnit Jupiter is the programming and extension model for modern JUnit tests. It provides annotations, assertions, parameterized tests, and extension APIs, while the JUnit Platform handles discovery and launching. I keep that distinction clear because discovery failures often involve the platform or engine rather than the test code.

Q2: What is the difference between JUnit 4 and Jupiter?

JUnit 4 relies on annotations such as @Before, runners, and rules. Jupiter uses @BeforeEach, a composable extension model, nested tests, richer parameterized tests, and platform-based execution. A migration should update imports and lifecycle behavior deliberately, not only rename annotations.

Q3: What is the JUnit test lifecycle?

With the default per-method lifecycle, Jupiter constructs a fresh test instance for each method. Class-level setup runs once, then each test gets before-each setup, execution, and after-each cleanup, followed by class-level cleanup. Exact inheritance and extension ordering should be verified when multiple layers participate.

Q4: When would you use @BeforeEach versus @BeforeAll?

I use @BeforeEach for fresh mutable fixtures needed by every test. I reserve @BeforeAll for class-wide initialization that is safe to share or for immutable configuration. Shared resources still need deterministic cleanup and must be safe if tests execute concurrently.

Q5: What does @TestInstance(PER_CLASS) change?

It tells Jupiter to reuse one test class instance for all methods in that class. This permits non-static @BeforeAll methods, but instance fields also become shared state. I use it only when that lifecycle is intentional and I have addressed ordering and parallelism.

Q6: How do assertEquals and assertSame differ?

assertEquals checks logical equality according to the type's equality implementation. assertSame checks whether both references point to the exact same object. Value behavior usually needs equality, while identity assertions are appropriate only when identity is part of the contract.

Q7: What is assertAll for?

assertAll executes a group of related assertions and reports all failures together. It is useful for several properties of one result, such as a mapped customer record. I do not use it to combine unrelated scenarios that deserve separate setup and failure reporting.

Q8: How do you test exceptions?

I use assertThrows around the smallest action expected to fail. It returns the exception, so I can verify a stable domain code, type, cause, or useful part of the message. I avoid accepting an overly broad exception because that can let the wrong failure pass.

Q9: What is a parameterized test?

It is one behavior contract executed for multiple argument sets. I select cases from boundaries and equivalence partitions, use a readable source, and name invocations when necessary. If each case needs a different workflow, separate test methods are clearer.

Q10: Which parameter sources do you use?

I use value or CSV sources for small literal cases, enum sources for enum coverage, and method sources for domain objects or generated arguments. Method sources are the best choice when row meaning would be obscured by positional strings. External files need explicit parsing and validation rather than hidden magic.

Q11: What is the difference between assumptions and assertions?

An assertion verifies expected product behavior and fails when it is false. An assumption checks a precondition and aborts the test when that precondition is not met. I use assumptions for legitimate optional environments, not to turn required infrastructure failures into skips.

Q12: How do timeouts work in JUnit?

JUnit offers timeout assertions and declarative timeout support. A same-thread timeout preserves thread-local context but cannot interrupt early in the same way as preemptive execution. I use preemptive timeouts carefully because moving code to another thread can invalidate transaction or security context.

Q13: What are nested tests?

@Nested classes group tests by context and can refine setup within an outer scenario. They improve readability for state-based behavior such as an empty cart and a populated cart. Deep nesting or hidden mutation is a warning that factories or explicit fixtures may be clearer.

Q14: What are dynamic tests?

A @TestFactory returns dynamic nodes created at runtime. They help when test cases are discovered programmatically, but lifecycle callbacks wrap the factory differently from ordinary individual methods. For a fixed data table, parameterized tests usually produce clearer reports and setup semantics.

Q15: What does @RepeatedTest prove?

It runs a test a configured number of times and exposes repetition information. It can help reproduce intermittent behavior or validate repetition-aware code, but a few successful repetitions do not prove stability. I prefer deterministic control of seeds, clocks, and concurrency over repetition as the primary oracle.

Q16: How do tags help?

@Tag attaches selection metadata that build tools and IDEs can include or exclude. I use a small stable vocabulary, such as unit, integration, and contract, tied to execution needs. Too many tags become inconsistent and make it difficult to know which CI job covers a test.

Q17: How do you disable a test?

@Disabled can skip a class or method, preferably with a concrete reason. In a working suite, I also link the reason to ownership and review disabled tests regularly. Conditional execution is better when the test is valid only on a documented platform or capability.

Q18: What is a JUnit extension?

An extension adds reusable behavior at defined Jupiter lifecycle and execution points. Examples include parameter resolution, conditional execution, timing, and failure evidence. I register narrow extensions with @ExtendWith or configured instances with @RegisterExtension rather than building one all-purpose framework extension.

Q19: What is ExtensionContext.Store used for?

It stores extension-owned state at a selected test context scope. A timing extension can save a start value before execution and retrieve it afterward without unsafe instance fields. Namespace keys and scope must be chosen carefully, especially under parallel execution.

Q20: How do you integrate Mockito with Jupiter?

I add Mockito's Jupiter integration and register MockitoExtension, then use Mockito annotations or explicit mock creation. Mockito APIs are not JUnit APIs, even though they work together. I mock external collaborations selectively and avoid verifying internal calls that are not part of observable behavior.

Q21: Why might Jupiter report no tests found?

Common causes are a missing Jupiter engine, an outdated build provider, include patterns that exclude the class, mixed JUnit 4 and Jupiter imports, or a task that selects the wrong tags. I inspect the resolved dependencies and discovery configuration before editing test annotations.

Q22: How do you run tests in parallel safely?

I first remove shared mutable state and give each test unique data, files, ports, and server instances. Then I enable parallel execution gradually and inspect concurrency-sensitive failures. Resource locks are a targeted fallback, not a substitute for isolation.

Q23: Should JUnit tests depend on execution order?

Normally no. Each test should establish its own preconditions and be able to run alone. Method ordering can support a rare documented workflow, but it increases failure cascading and blocks parallelism, so I prefer explicit setup or a single end-to-end scenario where sequence is the behavior.

Q24: How do you test asynchronous code?

I wait on the application's completion primitive or use a purpose-built polling library with a bounded deadline. I avoid Thread.sleep because it is both slow and timing-sensitive. Failure output should state the awaited condition and capture enough state to diagnose why it never became true.

Q25: How do you test private methods?

I test private behavior through the public contract. If a private algorithm is complex enough to need direct tests, that is often evidence it should become a separate collaborator with a public package-level or domain API. Reflection-based tests create tight coupling and make safe refactoring harder.

Q26: How do you separate unit and integration tests?

I define the boundary by dependency and execution cost, then configure distinct build tasks or Maven phases. Unit tests stay isolated and fast, while integration tests may use databases, containers, or real protocols. CI runs both with clear reports so a slow test cannot silently enter the fast feedback lane.

Q27: How do you diagnose a test that passes alone but fails in the suite?

I suspect leaked state, order dependence, exhausted resources, fixed identifiers, or timing. I randomize or reverse order, run the smallest failing group, inspect static and external state, and compare logs with correlation IDs. The fix is to restore isolation, not preserve the accidental order.

Q28: Are retries a good solution for flaky JUnit tests?

Retries can collect evidence or temporarily protect a release, but they are not the root fix. They increase runtime and may convert a genuine defect into a green build. Any retry policy should expose initial failures, be bounded, and have ownership and an expiry plan.

Q29: What makes a good JUnit test?

It verifies one coherent behavior, controls relevant inputs, has deterministic setup, and fails with useful evidence. It does not depend on another test or assert implementation detail without reason. It is also cheap enough to run at the feedback stage where the team needs it.

Q30: How would you improve a slow JUnit suite?

I measure by class and test, separate unit from integration work, remove unnecessary waits, and reduce repeated expensive setup with safe scoped resources. Then I address isolation before enabling parallelism. I preserve coverage of business risks rather than deleting slow tests based only on duration.

Common Mistakes

  • Mixing org.junit.Test with Jupiter lifecycle annotations and then debugging the wrong engine.
  • Sharing mutable static fixtures because setup appears expensive.
  • Using Thread.sleep instead of waiting for a meaningful condition with a deadline.
  • Catching an exception manually and forgetting to fail when no exception occurs.
  • Using one parameterized method for cases that have completely different actions and assertions.
  • Treating repeated success as proof that a flaky test is fixed.
  • Enabling parallel execution before removing fixed ports, shared records, and global state.
  • Disabling failures without a reason, owner, and review path.
  • Mocking value objects or the class under test.
  • Retrying every failure and publishing only the final green attempt.

Conclusion

The top JUnit interview questions are easiest when you connect APIs to engineering outcomes. Know the Jupiter lifecycle, assertions, parameterized tests, extensions, discovery, and execution controls, but always explain how they protect isolation, readability, and diagnostic value.

Practice the 30 answers with a two-minute coding example and one flaky-test diagnosis. That preparation shows an interviewer you can do more than write annotations, you can maintain a trustworthy Java test suite.

Interview Questions and Answers

What is the relationship between the JUnit Platform and Jupiter?

The JUnit Platform discovers and launches testing frameworks on the JVM. Jupiter is the modern JUnit programming and extension model, with its own test engine. Keeping them separate helps diagnose whether a problem is in test code, engine availability, or launcher configuration.

How does the default Jupiter test instance lifecycle improve isolation?

The default creates a fresh test class instance for each test method. That prevents ordinary instance fields from leaking values between methods. Static fields and external resources are still shared, so the lifecycle helps but does not remove the need for disciplined fixtures.

When would you choose `@BeforeAll` over `@BeforeEach`?

I choose `@BeforeAll` for immutable configuration or a deliberately shared resource whose lifecycle is the class. Mutable scenario state belongs in `@BeforeEach` or the test itself. I also define cleanup and verify that the resource is safe under the configured parallel mode.

How do you write a precise exception test?

I wrap only the action expected to fail in `assertThrows` and request the narrowest meaningful exception type. Then I assert a stable domain code, cause, or useful message fragment. This prevents unrelated setup failures from satisfying the test.

When is `assertAll` appropriate?

It is appropriate for several properties of one observed result, because it reports all related failures in one run. It is not a good way to combine independent scenarios. Independent behaviors deserve separate setup, names, and results.

How do you select cases for a parameterized test?

I derive rows from equivalence partitions, boundaries, special values, and documented business rules. I avoid arbitrary samples and make each invocation understandable in the report. If rows need different workflows, I split them into scenario-specific tests.

What problem does the Jupiter extension model solve?

It composes reusable behavior at supported lifecycle and execution points without requiring base-class inheritance or a single runner. I use small extensions for concerns such as parameter resolution, timing, conditions, or evidence capture. Extension state must be scoped safely for parallel execution.

How would you debug a no-tests-found result?

I inspect the resolved engine and platform dependencies, build provider, include patterns, selected tags, and annotation imports. I also confirm the IDE and command line use the same task. This finds configuration errors faster than randomly renaming methods.

How do you make Jupiter tests safe for parallel execution?

I remove shared mutable state, generate unique data and files, avoid fixed ports, and isolate external resources. Then I enable concurrency gradually and investigate races. Resource locks are reserved for unavoidable shared resources.

How do you approach flaky JUnit tests?

I classify the flake by order, timing, data, concurrency, or environment and reproduce it with controlled seeds and focused runs. I collect evidence from the first failure and fix isolation or synchronization. A bounded retry may be temporary containment, but it is never the final diagnosis.

How do you separate JUnit unit and integration suites?

I define clear dependency and cost criteria, then use separate Maven phases or Gradle tasks with stable tags or source sets. Each suite publishes its own results. The fast lane remains deterministic, while integration coverage still runs as a required delivery stage.

What signals senior-level JUnit knowledge?

A senior answer connects APIs to isolation, failure semantics, diagnosability, and delivery speed. It distinguishes JUnit from mocking tools, explains extension scope, and anticipates parallel and CI behavior. It also recognizes when a simple test is clearer than custom framework code.

Frequently Asked Questions

What JUnit topics should I prepare for an SDET interview?

Prepare Jupiter architecture, lifecycle callbacks, assertions, exception testing, parameterized tests, tags, extensions, mocking boundaries, parallel execution, and CI integration. Also practice diagnosing undiscovered, flaky, and order-dependent tests.

Is JUnit 5 still relevant in 2026?

Yes. Many production Java suites use maintained JUnit 5 releases, while newer projects may use JUnit 6. Jupiter concepts and most public testing patterns remain central, but candidates should confirm the Java baseline and dependency line used by the target project.

How many JUnit interview questions should I practice?

Thirty well-chosen questions cover a strong foundation if you can explain each answer and write representative code. Depth matters more than memorizing a larger list, especially for lifecycle, isolation, parameterization, and extensions.

What is the difference between JUnit and Mockito?

JUnit discovers and executes tests and provides lifecycle and assertion APIs. Mockito creates and verifies test doubles. They are often integrated, but their responsibilities and annotations are separate.

Should JUnit tests use real databases?

Fast unit tests generally replace the database boundary with a suitable fake or mock. Integration tests should exercise real database behavior through an isolated schema, container, or controlled environment when SQL, mapping, transactions, or constraints are part of the risk.

How should I answer a JUnit coding question?

State the behavior, select boundaries, create the smallest clear fixture, perform one action, and assert the public outcome. Run the test if possible, then mention one failure case or design tradeoff you would cover next.

Related Guides