Top Interview Questions
JUnit is a popular unit testing framework for Java that helps developers write and run automated tests to ensure their code works as expected. It plays a crucial role in test-driven development (TDD) and continuous integration (CI) processes. JUnit allows developers to test individual units of code—such as methods or classes—independently, helping to identify bugs early in the development cycle.
Originally developed by Kent Beck and Erich Gamma, JUnit has become the de facto standard for Java testing. It is open-source, lightweight, and widely supported by IDEs such as Eclipse, IntelliJ IDEA, and NetBeans, as well as build tools like Maven and Gradle.
Unit testing is a software testing technique where individual components (units) of an application are tested in isolation. A unit typically refers to the smallest testable part of an application, such as a method or function.
Key goals of unit testing:
Verify correctness of code
Detect bugs early
Improve code quality
Facilitate code refactoring
Provide documentation through test cases
JUnit makes unit testing easy and systematic for Java applications.
JUnit has evolved over time to support modern Java features.
Based on inheritance (extends TestCase)
Test methods had to start with test
Limited annotations
Less flexible
Introduced annotations like @Test, @Before, @After
Removed the need to extend TestCase
More readable and flexible
JUnit 5 is a major redesign and consists of three sub-projects:
JUnit Platform – Launches testing frameworks
JUnit Jupiter – New programming model and annotations
JUnit Vintage – Supports JUnit 3 and 4 tests
JUnit 5 supports Java 8+ features, including lambda expressions and streams.
JUnit uses annotations to define test methods and lifecycle events, making tests clean and readable.
Assertions verify expected results against actual outcomes.
JUnit provides runners to execute tests automatically.
Allows running the same test with multiple input values.
Easily integrates with CI/CD tools and build frameworks.
JUnit can validate that expected exceptions are thrown.
Some of the most widely used JUnit annotations include:
@Test – Marks a method as a test case
@BeforeEach – Runs before each test
@AfterEach – Runs after each test
@BeforeAll – Runs once before all tests
@AfterAll – Runs once after all tests
@Disabled – Skips a test
@DisplayName – Custom name for test
@ParameterizedTest – Runs test with parameters
These annotations help manage the test lifecycle efficiently.
Assertions are used to validate test outcomes. If an assertion fails, the test fails.
Common assertion methods include:
assertEquals(expected, actual)
assertNotEquals()
assertTrue(condition)
assertFalse(condition)
assertNull(object)
assertNotNull(object)
assertThrows(exception, executable)
Assertions improve code confidence by verifying logic correctness.
A basic JUnit test follows three steps:
Arrange – Prepare test data
Act – Execute the method
Assert – Verify the result
Example structure:
Create a test class
Annotate test methods with @Test
Use assertions to validate results
JUnit tests are usually placed in a separate test directory, keeping them independent of production code.
JUnit provides lifecycle methods to manage setup and cleanup:
Setup methods initialize objects before tests run
Teardown methods release resources after tests finish
This ensures tests are isolated, repeatable, and consistent.
Parameterized tests allow running the same test logic with multiple input values. This reduces code duplication and improves coverage.
Examples include:
Testing multiple inputs for mathematical operations
Validating edge cases
Testing boundary values
JUnit supports parameter sources such as:
Values
CSV files
Method sources
JUnit provides mechanisms to test whether a method throws an expected exception.
This is useful for:
Input validation testing
Error-handling logic
Security checks
JUnit ensures exceptions are thrown only when expected.
JUnit itself does not provide mocking capabilities, but it integrates seamlessly with frameworks like:
Mockito
EasyMock
PowerMock
Mocking allows developers to simulate dependencies such as databases, APIs, or services, making unit tests faster and more reliable.
In TDD, developers:
Write tests before code
Write minimal code to pass tests
Refactor code
JUnit is widely used for TDD because it:
Encourages small, focused tests
Supports rapid feedback
Improves design quality
JUnit integrates well with CI tools like:
Jenkins
GitHub Actions
GitLab CI
Bamboo
CI pipelines automatically run JUnit tests whenever code is committed, ensuring:
Early bug detection
Code stability
Faster releases
JUnit generates test reports that help teams analyze test results easily.
Open-source and free
Easy to learn and use
Reduces bugs in production
Encourages clean code design
Saves time and cost in the long run
Strong community and documentation
Excellent IDE and tool support
Limited to Java ecosystem
Requires additional libraries for mocking
Not suitable for UI or performance testing
Poorly written tests can be hard to maintain
Despite these limitations, JUnit remains ideal for unit testing Java applications.
Write small, independent tests
Use meaningful test names
Avoid testing multiple things in one test
Mock external dependencies
Keep tests fast and repeatable
Maintain high test coverage
Run tests frequently
Following best practices ensures maintainable and effective test suites.
Testing business logic in enterprise applications
Validating REST APIs
Ensuring correctness of utility methods
Regression testing during code changes
Supporting agile and DevOps workflows
JUnit is widely used in banking, e-commerce, telecom, healthcare, and enterprise software development.
Answer:
JUnit is a unit testing framework for Java used to test individual units of code such as methods or classes. It helps developers ensure that the code works correctly by writing automated test cases.
Answer:
Unit testing is the process of testing the smallest testable parts of an application, such as methods or functions, to verify that they work as expected independently.
Answer:
JUnit is important because:
It helps find bugs early
Improves code quality
Supports automation testing
Makes code easier to maintain
Saves time during regression testing
Answer:
Annotations for defining test methods
Assertions to validate expected results
Test runners to execute tests
Test suites to group multiple tests
Supports Test-Driven Development (TDD)
Answer:
JUnit annotations are special keywords that define how a test method should behave.
Answer:
@Test – Marks a method as a test
@BeforeEach – Runs before each test
@AfterEach – Runs after each test
@BeforeAll – Runs once before all tests
@AfterAll – Runs once after all tests
@Disabled – Skips a test
@DisplayName – Custom test name
@Test annotation?Answer:
@Test is used to indicate that a method is a test case that JUnit should execute.
Answer:
Assertions are used to verify expected outcomes of a test. If an assertion fails, the test fails.
Answer:
assertEquals()
assertNotEquals()
assertTrue()
assertFalse()
assertNull()
assertNotNull()
assertThrows()
assertEquals()?Answer:
It checks whether the expected value matches the actual value.
Answer:
The test case fails, and JUnit reports the failure with details.
@BeforeEach?Answer:
It runs before every test method and is used for setup tasks like initializing objects.
@AfterEach?Answer:
It runs after every test method and is used for cleanup activities.
@BeforeAll?Answer:
It runs once before all test methods in the class. The method must be static.
@AfterAll?Answer:
It runs once after all tests have executed. The method must be static.
Answer:
A test case is a set of conditions used to verify whether a piece of code works correctly.
Answer:
A test suite is a collection of test cases that are executed together.
Answer:
TDD is a development approach where:
Write test cases first
Write code to pass the tests
Refactor the code
Answer:
| Feature | JUnit 4 | JUnit 5 |
|---|---|---|
| Annotations | Limited | More advanced |
| Architecture | Single | Modular |
| Java Version | Java 5+ | Java 8+ |
Answer:
JUnit Jupiter is the programming and extension model for writing tests in JUnit 5.
Answer:
No, JUnit cannot directly test private methods. They should be tested indirectly through public methods.
@Disabled annotation?Answer:
It is used to skip or ignore a test method.
Answer:
It verifies whether a method throws an expected exception using assertThrows().
Answer:
Parameterized tests allow running the same test multiple times with different input values.
Answer:
Mocking is creating fake objects to simulate real dependencies during testing.
Answer:
Mockito is commonly used with JUnit.
Answer:
Regression testing ensures that new changes do not break existing functionality.
Answer:
Yes, JUnit can be used for integration testing, but it is mainly designed for unit testing.
Answer:
Eclipse
IntelliJ IDEA
NetBeans
Answer:
JUnit tests are run automatically in CI/CD pipelines to ensure code quality before deployment.
@DisplayName?Answer:
It provides a custom name for test methods to improve readability.
Answer:
Faster testing
Reliable results
Reusable tests
Reduces manual effort
Answer:
Yes, JUnit tests can be executed using build tools like Maven or Gradle.
Answer:
Maven manages dependencies and helps run JUnit tests using plugins like Surefire.
Answer:
Yes, JUnit is free and open-source.
Answer:
Cannot test UI directly
Not suitable for performance testing
Requires additional tools for mocking
Answer:
Java developers, automation testers, QA engineers, and DevOps teams.
Answer:
Unit tests should be written during development, preferably before or alongside code.
Answer:
Code coverage measures how much of the code is tested by unit tests.
Answer:
Yes, JUnit is easy to learn and highly suitable for beginners in Java testing.
Answer:
A Test Runner is a component that executes test cases and displays results such as passed, failed, or ignored tests.
Examples:
JUnit Console Runner
IDE-based runners (Eclipse, IntelliJ)
Answer:
A test fixture is a fixed environment used to run tests. It includes:
Test data
Objects initialization
Database connections
Annotations like @BeforeEach and @AfterEach are used to manage fixtures.
assertThrows()?Answer:
assertThrows() checks whether a method throws a specific exception.
Example:
assertThrows(ArithmeticException.class, () -> divide(10, 0));
assertAll()?Answer:
assertAll() allows multiple assertions to be executed together. Even if one fails, others still run.
assertTrue() and assertEquals()?Answer:
| assertTrue() | assertEquals() |
|---|---|
| Checks condition | Compares values |
| Boolean result | Expected vs actual |
| Used for logic | Used for data |
@RepeatedTest?Answer:
It runs the same test multiple times.
Example:
@RepeatedTest(5)
void repeatTest() { }
@Timeout?Answer:
It fails a test if it exceeds a given time limit.
@Tag?Answer:
@Tag is used to group and filter tests.
Example:
@Tag("smoke")
@Nested?Answer:
@Nested is used to create inner test classes for better structure and readability.
@ParameterizedTest?Answer:
It runs the same test with different input values.
Example:
@ParameterizedTest
@ValueSource(ints = {1, 2, 3})
@CsvSource?Answer:
It provides multiple arguments using CSV format.
Example:
@CsvSource({"1,2,3", "2,3,5"})
@MethodSource?Answer:
It supplies test data from a method.
Answer:
A disabled test is skipped during execution using @Disabled.
@BeforeEach and @BeforeAll?Answer:
@BeforeEach: Runs before every test
@BeforeAll: Runs once before all tests (static)
Answer:
| Failure | Error |
|---|---|
| Assertion fails | Unexpected exception |
| Test logic issue | Runtime issue |
assumeTrue()?Answer:
It runs a test only if a condition is true; otherwise, the test is skipped.
Answer:
Test ordering controls the sequence of test execution using @TestMethodOrder.
@Order?Answer:
It specifies the order of test execution.
Answer:
Mocking simulates real objects to isolate the unit under test.
Answer:
Mockito helps create mock objects for:
Database calls
External services
APIs
Answer:
A stub provides fixed responses during testing.
Answer:
| Mock | Stub |
|---|---|
| Verifies behavior | Returns fixed data |
| Interaction-based | State-based |
@ExtendWith?Answer:
It integrates extensions like Mockito with JUnit 5.
Answer:
Injecting required objects into a class instead of creating them directly.
Answer:
Poor test design that makes tests hard to maintain.
Answer:
A test that passes or fails randomly without code changes.
Answer:
Each test runs independently without affecting others.
Answer:
Yes, JUnit 5 supports parallel execution.
Answer:
Running tests automatically whenever code changes.
Answer:
Maven Surefire plugin executes JUnit tests during the build.
Answer:
Used for integration testing in Maven.
@TempDir?Answer:
Creates temporary directories for tests.
@TestFactory?Answer:
Creates dynamic tests at runtime.
Answer:
Tests generated during execution instead of compile time.
Answer:
A command-line tool to run JUnit tests.
Answer:
Tools like JaCoCo measure how much code is tested.
Answer:
Testing based on internal code structure.
Answer:
Testing without knowing internal code.
Answer:
Write small test cases
Use meaningful names
Avoid test dependencies
Mock external systems
Answer:
JUnit remains the standard testing framework for Java with strong community support.
Answer:
Effective unit tests should:
Test only one unit of behavior
Be independent and isolated
Be fast and repeatable
Avoid external dependencies using mocks
Follow AAA pattern (Arrange, Act, Assert)
Answer:
Common challenges include:
Testing legacy code
Mocking static or final methods
Handling external dependencies
Writing maintainable test cases
Dealing with flaky tests
Answer:
JUnit 5 consists of:
JUnit Platform – Launches testing frameworks
JUnit Jupiter – New programming model and annotations
JUnit Vintage – Supports JUnit 3 & 4 tests
Answer:
| Unit Testing | Integration Testing |
|---|---|
| Tests individual units | Tests combined components |
| Uses mocks | Uses real dependencies |
| Faster | Slower |
| Isolated | End-to-end flow |
Answer:
Use in-memory databases (H2)
Mock repository layers
Use @Transactional with rollback
Separate unit and integration tests
Answer:
By using:
Mockito for mocking services
WireMock for REST APIs
TestContainers for real environments
@ExtendWith(MockitoExtension.class).Answer:
It integrates Mockito with JUnit 5 and initializes mock objects automatically.
Answer:
TestContainers allows running real dependencies like databases in Docker containers during tests.
Answer:
Using assertThrows():
assertThrows(CustomException.class, () -> service.process());
Answer:
Parameterized testing allows running a test with multiple inputs.
Used for:
Validation logic
Boundary testing
Business rules
@BeforeEach and @BeforeAll in real use?Answer:
@BeforeEach → Reset state before each test
@BeforeAll → Expensive setup like DB connections
Answer:
Each test should run independently to avoid side effects and flaky results.
Answer:
A flaky test behaves inconsistently.
Fix by:
Removing timing dependencies
Using mocks
Resetting shared states
Avoiding parallel conflicts
Answer:
JUnit 5 supports parallel execution using configuration properties.
@TestInstance?Answer:
Controls test instance lifecycle:
PER_METHOD (default)
PER_CLASS (useful for shared state)
Answer:
Tests created at runtime using @TestFactory.
assertAll() and multiple assertions?Answer:
assertAll() executes all assertions even if one fails, improving diagnostics.
Answer:
Private methods are tested indirectly via public methods. Reflection is avoided.
Answer:
Assumptions (assumeTrue) skip tests when conditions are not met.
Answer:
Using @Tag and build-tool configurations.
Answer:
| Surefire | Failsafe |
|---|---|
| Unit tests | Integration tests |
| test phase | verify phase |
Answer:
Using tools like JaCoCo, integrated with CI pipelines.
Answer:
Mutation testing checks the quality of tests by introducing small changes in code.
Answer:
Use descriptive method names
Avoid duplication
Follow naming conventions
Use helper methods
Keep tests simple
Answer:
| Mock | Spy |
|---|---|
| Fake object | Real object |
| No real logic | Partial real logic |
| Fully controlled | Partial control |
@MockBean?Answer:
Used in Spring Boot tests to mock beans in the application context.
Answer:
Using:
MockMvc
WebTestClient
RestAssured
Answer:
JUnit ensures:
Automated regression testing
Build validation
Early bug detection
Answer:
Refactor slowly
Add tests before changes
Use seams and mocks
Answer:
Write tests first, then code, then refactor.
Answer:
BDD focuses on behavior using readable scenarios (JUnit + Cucumber).
Answer:
Overusing mocks
Testing implementation details
Large test methods
Test dependency
Answer:
By mocking clocks or using fixed timestamps.
@TempDir used for?Answer:
Creates temporary directories for file system tests.
Answer:
Use logs
Debug mode
Check assertions
Reproduce locally
Answer:
JUnit is simpler and standard; TestNG provides advanced configurations.
Answer:
Ensures services agree on request-response formats.
Answer:
Unit tests for services
Integration tests with TestContainers
Contract tests
Answer:
Tests should be fast, isolated, and readable.
Answer:
Real project scenarios
Mockito integration
CI/CD usage
Performance & reliability
Debugging flaky tests
Answer:
Unit test:
Business logic
Calculations
Decision-making code
Do not unit test:
Framework code
Getters/setters
Third-party libraries
Answer:
By:
Verifying state changes
Verifying interactions using Mockito (verify())
Answer:
Using Mockito:
verify(service).process();
ArgumentCaptor and when do you use it?Answer:
ArgumentCaptor captures arguments passed to a mocked method for validation.
@Mock and @InjectMocks?Answer:
| @Mock | @InjectMocks |
|---|---|
| Creates mock | Injects mocks |
| Standalone object | Tested class |
@Spy and when to use it?Answer:
A spy wraps a real object and allows partial mocking.
Answer:
Using Mockito (inline mock maker) or PowerMockito.
Answer:
PowerMockito is used to mock:
Static methods
Constructors
Final classes
Answer:
Trigger methods directly
Mock time
Avoid real scheduling in unit tests
Answer:
Use CompletableFuture
Awaitility library
Timeouts in assertions
Answer:
Using @TempDir and mock multipart files.
@DirtiesContext?Answer:
Resets Spring context after test execution.
Answer:
Builders
Test factories
Separate test resources
Answer:
Arrange: Setup data
Act: Execute method
Assert: Verify result
Answer:
Improving test structure without changing behavior.
Answer:
MockMvc
RestAssured
WebTestClient
@WebMvcTest?Answer:
Loads only web layer components for controller testing.
@SpringBootTest?Answer:
Loads full application context.
@MockBean and @Mock?Answer:
@MockBean replaces Spring bean, @Mock is standalone.
Answer:
Ensures services communicate correctly without breaking changes.
Answer:
Using profiles and assumptions.
Answer:
Mock authentication
Use Spring Security Test support
@ActiveProfiles?Answer:
Activates specific Spring profiles during tests.
Answer:
A model defining ratio of:
Unit tests (majority)
Integration tests
UI tests
Answer:
Parallel execution
Mock dependencies
Avoid full context loading
Answer:
Introduces faults to verify test effectiveness.
@DisabledOnOs?Answer:
Disables tests for specific operating systems.
Answer:
Mock mail sender and verify interactions.
Answer:
A place where behavior can be altered for testing.
Answer:
Isolate resources
Retry logic
Use containers
Answer:
Verify cache hits/misses using mocks.
Answer:
Use embedded brokers or TestContainers.
@Nested used for in large test classes?Answer:
Improves structure and readability.
@TestMethodOrder?Answer:
Controls execution order of test methods.
Answer:
Use @TestPropertySource.
@DynamicPropertySource?Answer:
Provides dynamic properties at runtime.
Answer:
Mock failures and verify retries.
Answer:
Stubbing returns data; mocking verifies behavior.
Answer:
Descriptive names
@DisplayName
Clear structure
Answer:
Overusing mocks
Not understanding test isolation
Writing brittle tests
Answer:
Add characterization tests
Refactor gradually
Answer:
Mock flag states.
Answer:
Verify boundaries and page sizes.
Answer:
Use parallel tests and synchronization checks.
Answer:
Testing implementation instead of behavior.
Answer:
By discussing:
Real problems
Testing strategies
Tool integration
Answer:
Fast, reliable, readable, and maintainable.
Answer:
Analyze logs
Reproduce locally
Fix root cause
Answer:
Override properties in tests.
Answer:
Code reviews
Mutation testing
Refactoring tests