Writing Unit Tests with JUnit and Mockito

On This Page What is JUnit?Why use JUnit for Unit Testing?June 02, 2026 · 16 min read · Testing Guide

Writing Unit Tests with JUnit and Mockito

Unit quiz ensures that the code part correctly and prevents issues before deployment.

JUnitprovides a structured framework for penning and running tests, while Mockito helps bemock dependence for effective isolation and check.

This guide coversapply JUnit and Mockito for unit testing, include best practices, key concepts, and implementation.

What is JUnit?

is a popular Java testing framework that helps developers write and run. It is part of the xUnit family of trial frameworks and is heavily apply for test-driven evolution (TDD).

Some key features of JUnit:

  • Offers annotations such as @ Test,, and @ AfterEach to organize.
  • Supports assertion statements (e.g., assertEquals, assertTrue) to confirm expected outputs.
  • Enables and simple consolidation with build tools like and Gradle.
  • Generates in-depth reports on examination runs.
  • Functions efficiently with pipelines.

JUnit warrantee Java code functionality works as await by allowing developers to test individual part quickly and effectively.

Must Read:

Why use JUnit for Unit Testing?

JUnit makes Java covering faster, more stable, and easier to maintain by observe problems early and encouraging good coding practices. It create testing leisurely to make, run, and maintain.

JUnit 4introduced key features like annotations (@ Test, @ Before, @ After) and a simple test-running model, making it a popular Java testing model.

JUnit 5enhanced it with a modular design (JUnit Platform, Jupiter, and Vintage), better extensibility, improved lifecycle notation (@ BeforeEach, @ AfterEach), potent assertions, and seamless CI/CD consolidation.

Read More:

Here & # 8217; s whyJUnitis the choice of developers:

  • Automation & amp; Efficiency: JUnit belittle effort and maximizes growth speed by replacing the motive for. It can easily be integrated with build tools such as Maven and Gradle for.
  • Reliable : It provides built-in asseveration methods (e.g., assertEquals, assertTrue) to verify expected results, making test validation easier.
  • Structured & amp; Reusable Tests: JUnit use annotations (@ Test, @ BeforeEach, @ AfterEach) to organize and fulfill tests systematically, check codification continue modular and maintainable.
  • Supports : JUnit encourages, where tests are written before codification, leading to better design, few glitch, and improved code quality.
  • Integration with CI/CD: It mix well with Jenkins, GitHub Actions, and other CI/CD tools to automate prove in line.
  • Detailed Reporting & amp; Debugging: JUnit offering detailed test resolution and failure logarithm, enabling developers to identify and resolve problems apace.
  • Open-Source & amp; Community Support: JUnit is a popular open-source framework with robust community support, so finding solutions and best practices is easy.

Must Read:

Features of JUnit

Various feature of JUnit render it a strong, flexible, and effective unit testing puppet. A few of its key features are:

1. Assertions: check expected output and help identify problems early. Some common assertions are:

  • assertEquals (expected, actual): Tests whether two value are adequate.
  • assertTrue (condition): Checks if a condition is true.
  • assertFalse (condition): Checks if a condition is false.
  • assertThrows (Exception.class, () - & gt; {}): Checks that an elision is thrown.

Also Read:

2. Test Annotations: JUnit employs annotation to specify and conserve test cases:

  • @ Test: Indicates that a method is a examination event.
  • @ BeforeEach: Executes before each test (for example, setup code).
  • @ AfterEach: Executes after each test (for representative, cleanup code).
  • @ BeforeAll: Executes once before all tests in a class.
  • @ AfterAll: Executes once after all the tests.
  • @ Disabled: Disables a test case.

3. Parameterized Tests: JUnit allows running the like examination with different inputs using @ ParameterizedTest:

  • @ ValueSource (ints = {1, 2, 3}): Provides multiple value for testing.
  • @ CsvSource ({& # 8220; 1, One & # 8221;, & # 8220; 2, Two & # 8221;}): Supplies multiple exam cases in CSV format.
  • @ MethodSource: Supplies test information from a static method.

4. Exception Handling: JUnit can screen if a method correctly throws an expected exclusion:

@ Test void testException () {assertThrows (ArithmeticException.class, () - & gt; {int result = 10 / 0;});}

5. Timeout Handling: JUnit allows put a time limit for examination execution:

@ Test @ Timeout (2) // Fails if execution takes more than 2 minute void testTimeout () {Thread.sleep (1000);}

6. : JUnit enable grouping multiple examination course into a suite using @ Suite and @ SelectClasses.

Also Read:

7. Mocking Support: for bemock dependencies, enabling detached testing of component.

8. CI/CD & amp; IDE Support: JUnit work seamlessly with Jenkins, GitHub Actions, and all major like IntelliJ and Eclipse.

How to write Unit Tests with JUnit?

JUnitsimplifies writing and running unit examination for Java applications. Follow these steps to create efficient unit tests:

Step 1: Set Up JUnit in Your Project

Using Maven (JUnit 5)

Add the next dependency to your pom.xml:

& lt; dependencies & gt; & lt; dependency & gt; & lt; groupId & gt; org.junit.jupiter & lt; /groupId & gt; & lt; artifactId & gt; junit-jupiter-api & lt; /artifactId & gt; & lt; variation & gt; 5.9.2 & lt; /version & gt; & lt; scope & gt; test & lt; /scope & gt; & lt; /dependency & gt; & lt; /dependencies & gt;

Using Gradle (JUnit 5)

Add this to your build.gradle:

dependance {testImplementation 'org.junit.jupiter: junit-jupiter:5.9.2'}

Step 2: Create a Java Class to Test

Example: A unproblematic Calculator class.

public class Calculator {public int add (int a, int b) {revert a + b;} public int subtract (int a, int b) {return a - b;}}

Step 3: Create a JUnit Test Class

JUnit exam grade should be placed in the src/test/java directory.

significance org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions. *; class CalculatorTest {@ Test void testAddition () {Calculator reckoner = new Calculator (); assertEquals (5, calculator.add (2, 3));} @ Test void testSubtraction () {Calculator calculator = new Calculator (); assertEquals (2, calculator.subtract (5, 3));}}

Step 4: Run the Tests

  • In IntelliJ/Eclipse: Right-click the test class and choice Run.
  • Using Maven: Run mvn tryout in the terminal.
  • Using Gradle: Run gradle test.

Step 5: Use Setup & amp; Cleanup Methods

JUnit furnish lifecycle methods for frame-up and cleanup.

importee org.junit.jupiter.api. *; import static org.junit.jupiter.api.Assertions. *; stratum CalculatorTest {private Calculator computer; @ BeforeEach null setUp () {calculator = new Calculator (); // Runs before each test} @ AfterEach void tearDown () {figurer = nada; // Cleanup after each test} @ Test nihility testAddition () {assertEquals (5, calculator.add (2, 3));}}

Step 6: Test Exception Handling

Ensure method throw expected exceptions.

@ Test void testDivideByZero () {assertThrows (ArithmeticException.class, () - & gt; {int consequence = 10 / 0;});}

Learn More:

Step 7: Run Parameterized Tests (Optional)

JUnit allows testing multiple values using @ ParameterizedTest.

import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; import static org.junit.jupiter.api.Assertions. *; class CalculatorTest {@ ParameterizedTest @ CsvSource ({`` 2,3,5 '', `` 4,5,9 '', `` 10,20,30 ''}) void testAddition (int a, int b, int anticipate) {Calculator calculator = new Calculator (); assertEquals (expected, calculator.add (a, b));}}

Step 8: Integrate with CI/CD (Optional)

JUnit act seamlessly with Jenkins, GitHub Actions, and GitLab CI for automated examination.

GitHub Actions Example

Create .github/workflows/test.yml:

name: Run JUnit Tests on: [push] job: test: runs-on: ubuntu-latest measure: - purpose: actions/checkout @ v3 - gens: Set up JDK use: actions/setup-java @ v3 with: java-version: '17' distribution: 'temurin' - gens: Run Tests run: mvn examination

What is Mockito?

Mockitois a popular Java mocking model used for unit examination. It helps test case-by-case portion by assume dependencies instead of relying on real implementations.

Mockito creates mock objects that mimic real dependency. These objects can return predefined answer and track method calls.

Why use Mockito for Unit Testing?

Mockito is useful in the next cases when it arrive to unit examination:

  • Isolates the portion under test by replacing dependencies with mock objects.
  • Avoids database, network, or file dependance, get tests faster and more reliable.
  • Allows behaviour confirmation (e.g., control if a method was called).
  • It supports stubbing and enables controlled responses for mocked methods.

Also Read:

SUSA automates exploratory testing with persona-driven behavior, catching bugs that scripted automation misses.

Features of Mockito

Mockitoprovides powerful mock capabilities forunit testing in Java. It assist isolate dependencies, control method response, and control interactions.

Below are its key features:

1.Mockito grant mocking objects to supercede real addiction in a, preventing trial from look on database, APIs, or external systems. This secure tests run in isolation, making them fast and more reliable.

For illustration:

UserRepository repoMock = mock (UserRepository.class);

2.Stubbing lets you delimit method responses for mock objects, guarantee predictable doings in tryout regardless of outside factor. This let precise control over test conditions and expected outcomes.

For example:

when (repoMock.findById (1)) .thenReturn (new User (1, `` Alice ''));

3.Mockito allows checking whether a method was called, how many times, and with which debate, ensuring correct interactions between components. This help detect unnecessary or missing method Call, meliorate test accuracy.

For instance:

verify (repoMock, multiplication (1)) .findById (1);

4.Mockito act with JUnit assertions to validate examination output, confirming if the scheme produces expected value. This ensures rightness by comparing actual versus expected results.

For example:

assertEquals (`` Alice '', user.getName ()); assertNotNull (user);

5.Mockito provides @ Mock, @ InjectMocks, and @ Spy annotations to simplify mock object setup, reduce boilerplate codification, and make tests more clear and easier to sustain.

For example:

@ Mock UserRepository repoMock; @ InjectMocks UserService service;

6.A spy allows real method calls but enables selective method overriding, making it utilitarian for testing specific behaviors without losing original functionality. This maintains real deportment while allowing targeted control over sure method.

For model:

List & lt; String & gt; spyList = spy (new ArrayList & lt; & gt; ()); spyList.add (`` Hello ''); verify (spyList) .add (`` Hello '');

7.Mockito allows pressure a method to throw an elision, which helps test how the scheme react to failure, ensuring robust erroneousness manipulation and improve system reliability.

For example:

when (repoMock.findById (1)) .thenThrow (new RuntimeException (`` Database erroneousness ''));

8.Mockito provides argument matchers like anyInt (), anyString (), and eq (value) to handle dynamic inputs in stubbing and verification, allowing flexible and dynamic test cases.

For example:

when (repoMock.findById (anyInt ())) .thenReturn (new User (1, `` Alice ''));

Learn More:

How to Write Unit Tests with Mockito?

Mockito makes unit screen easier by allowing developers to bemock dependencies, control method doings, and verify interactions.

Below is a step-by-step guide to writing unit examination using Mockito.

1. Add Mockito Dependency

First, add Mockito to your undertaking. If you are using Maven, add the follow in pom.xml:

& lt; dependency & gt; & lt; groupId & gt; org.mockito & lt; /groupId & gt; & lt; artifactId & gt; mockito-core & lt; /artifactId & gt; & lt; adaptation & gt; 5.2.0 & lt; /version & gt; & lt;! -- Use the latest version -- & gt; & lt; setting & gt; test & lt; /scope & gt; & lt; /dependency & gt;

For Gradle, add this to build.gradle:

testImplementation 'org.mockito: mockito-core:5.2.0 '

Read More:

2. Create a Sample Class to Test

Suppose a UserService class depends on a UserRepository to fetch exploiter data.

public class UserService {private final UserRepository userRepository; public UserService (UserRepository userRepository) {this.userRepository = userRepository;} public User getUserById (int id) {return userRepository.findById (id);}}

The UserService relies on UserRepository, which will be mocked in the unit test.

3. Write a Mockito Test Class

Create a exam class and mock dependencies.

import org.junit.jupiter.api.Test; import org.junit.jupiter.api.BeforeEach; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; signification static org.mockito.Mockito. *; import static org.junit.jupiter.api.Assertions. *; class UserServiceTest {@ Mock // Create a mock object private UserRepository userRepository; @ InjectMocks // Inject mocks into UserService private UserService userService; @ BeforeEach void apparatus () {MockitoAnnotations.openMocks (this);} @ Test void testGetUserById () {// Arrange: Define the doings of mock User mockUser = new User (1, `` Alice ''); when (userRepository.findById (1)) .thenReturn (mockUser); // Act: Call method under test User termination = userService.getUserById (1); // Assert: Verify the expected result assertNotNull (event); assertEquals (`` Alice '', result.getName ()); verify (userRepository, times (1)) .findById (1); // Verify method was called once}}

4. Explanation of the Test

  • Mock Creation: @ Mock creates a faux UserRepository object.
  • Dependency Injection: @ InjectMocks mechanically injects the mock into UserService.
  • Setup Method: MockitoAnnotations.openMocks (this); initializes mocks before each exam.
  • Stubbing behavior: when (userRepository.findById (1)) .thenReturn (mockUser); tells Mockito what to return.
  • Assertions: assertEquals (& # 8220; Alice & # 8221;, result.getName ()); ensure the right yield.
  • Verification: verify (userRepository, time (1)) .findById (1); control the method was phone once.

Read More:

5. Running the Test

Execute the test apply JUnit in your IDE or command line. If successful, it confirms that the UserService correctly retrieves user data using a mocked UserRepository.

How to use Mockito with JUnit?

Mockito integrates seamlessly with JUnit to make effective unit tests by mocking dependance, defining expected behavior, and verifying method calls.

Below is a step-by-step guide to using Mockito with JUnit.

1. Add Mockito and JUnit Dependencies

Ensure your project includes Mockito and JUnit 5 dependencies.

For Maven, add this to pom.xml:

& lt; dependency & gt; & lt; groupId & gt; org.mockito & lt; /groupId & gt; & lt; artifactId & gt; mockito-core & lt; /artifactId & gt; & lt; version & gt; 5.2.0 & lt; /version & gt; & lt; scope & gt; test & lt; /scope & gt; & lt; /dependency & gt; & lt; dependency & gt; & lt; groupId & gt; org.junit.jupiter & lt; /groupId & gt; & lt; artifactId & gt; junit-jupiter-api & lt; /artifactId & gt; & lt; version & gt; 5.9.0 & lt; /version & gt; & lt; background & gt; test & lt; /scope & gt; & lt; /dependency & gt;

For Gradle, add this to build.gradle:

testImplementation 'org.mockito: mockito-core:5.2.0' testImplementation 'org.junit.jupiter: junit-jupiter:5.9.0 '

2. Create a Sample Service to Test

Suppose there is a UserService family that depends on UserRepository:

public class UserService {private last UserRepository userRepository; public UserService (UserRepository userRepository) {this.userRepository = userRepository;} public User getUserById (int id) {return userRepository.findById (id);}}

The UserService calls UserRepository, which will be mock in the test.

3. Write a JUnit Test Using Mockito

Create a trial class and use Mockito with JUnit 5.

import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; significance org.mockito.InjectMocks; importation org.mockito.Mock; import org.mockito.MockitoAnnotations; import stable org.mockito.Mockito. *; import static org.junit.jupiter.api.Assertions. *; class UserServiceTest {@ Mock // Creates a mock of UserRepository individual UserRepository userRepository; @ InjectMocks // Injects the mock into UserService private UserService userService; @ BeforeEach void frame-up () {MockitoAnnotations.openMocks (this); // Initializes mock} @ Test void testGetUserById () {// Arrange: Define mock behavior User mockUser = new User (1, `` Alice ''); when (userRepository.findById (1)) .thenReturn (mockUser); // Act: Call the method under test User result = userService.getUserById (1); // Assert: Verify expected behavior assertNotNull (upshot); assertEquals (`` Alice '', result.getName ()); verify (userRepository, multiplication (1)) .findById (1); // Ensure method was called once}}

4. Explanation of the Test

  • Mock Creation: @ Mock create a simulated UserRepository object.
  • Dependency Injection: @ InjectMocks inject the mock into UserService.
  • Mock Initialization: MockitoAnnotations.openMocks (this); initializes mocks before each test.
  • Defining Behavior: when (userRepository.findById (1)) .thenReturn (mockUser); tell Mockito what to return.
  • Assertions: assertEquals (& # 8220; Alice & # 8221;, result.getName ()); checks the output.
  • Verification: verify (userRepository, time (1)) .findById (1); ensures the method was telephone exactly once.

5. Run the trialin your IDE or with mvn test (Maven) or gradle test (Gradle). It confirms that Mockito and JUnit work together for screen if it passes.

Also Read:

Test-Driven Development (TDD) with JUnit and Mockito

Test-Driven Development (TDD) is a software development approach where tests are write before the actual code.

It postdate aRed-Green-Refactor cycle:

  • Red: Write a failing test.
  • Green: Implement the minimum code to pass the tryout.
  • Refactor: Improve the codification while guarantee test still pass.

TDD can be effectively applied using JUnit and Mockito. Below is a step-by-step guide to implementing.

Step 1: A UserServicemotive to be built to fetch user datum from aUserRepository. The repository interacts with a database but will be bemock for unit testing.

Step 2: Create a JUnit test before implementing UserService, assure the test fails initially (Red Phase in TDD).

import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import static org.mockito.Mockito. *; import static org.junit.jupiter.api.Assertions. *; class UserServiceTest {@ Mock private UserRepository userRepository; // Mock the repository @ InjectMocks individual UserService userService; // Inject mock into service @ BeforeEach null setUp () {MockitoAnnotations.openMocks (this);} @ Test void testGetUserById () {when (userRepository.findById (1)) .thenReturn (new User (1, `` Alice '')); User exploiter = userService.getUserById (1); assertNotNull (user); assertEquals (`` Alice '', user.getName ()); verify (userRepository, times (1)) .findById (1);}}

Expected Outcome: The test neglect because UserService does not exist yet.

Step 3: Write minimum code to pass the exam (Green Phase)

public class UserService {individual final UserRepository userRepository; public UserService (UserRepository userRepository) {this.userRepository = userRepository;} public User getUserById (int id) {return userRepository.findById (id);}}

Expected Outcome: The test passes because UserService now calls userRepository.findById (id).

Step 4: Optimize the code while ensuring all tests surpass, including adding error treatment in UserService (Refactor Phase).

public class UserService {private final UserRepository userRepository; public UserService (UserRepository userRepository) {this.userRepository = userRepository;} public User getUserById (int id) {User user = userRepository.findById (id); if (user == null) {throw new UserNotFoundException (`` User not found with ID: `` + id);} return user;}}

Expected Outcome: The test still surpass, confirming that the change did not break functionality.

Step 5: Add tests for exception scenario and repeat the TDD cycle for improved coverage.

vacuum testGetUserById_UserNotFound () {when (userRepository.findById (2)) .thenReturn (void); Exception elision = assertThrows (UserNotFoundException.class, () - & gt; {userService.getUserById (2);}); assertEquals (`` User not found with ID: 2 '', exception.getMessage ());}

Outcome: This trial fails if no exception is thrown. After ensuring UserNotFoundException is handled, the trial pass.

Best Practices for Unit Testing with JUnit and Mockito

Effective unit testing enhances code reliability and maintainability.JUnit and Mockitofacilitate well-structured, effective, and maintainable tests.

Here are some best practice to achieve high-quality testing.

  • Use the Arrange-Act-Assert (AAA) Pattern: Organize tests into three distinct phases:
    • Arrange: Initialize examination data and dependencies.
    • Act: Invoke the method under test.
    • Assert: Verify the expected outcome.
  • Provide Meaningful Test Method Names: Test names must report the desired deportment. One proper format is & # 8220; methodName_condition_expectedOutcome & # 8221; to make tests self-describing.
  • Tests Must Be Small and Focused: Only one demeanour must be insure per trial. This enhances legibility, maintainability, and debugging. Having case-by-case tests for distinct demeanor provides clarity.
  • Mock Only External Dependencies: Mocks should be apply only for external dependence, such as databases, APIs, or file systems. Avoid mocking the class under test to ensure real logic is verified.
  • Verify Interactions with Dependencies: Mockito allows ensure whether methods were called with the right statement. This ensures that dependencies behave as expected. Always control critical interaction, particularly when working with external systems.
  • Test Edge Cases and Exceptions: Ensure tests include invalid inputs, void values, and exceptions. This avoids failure under unexpected weather and enhances coating solidity.
  • Use @ BeforeEach to Minimize Code Duplication: Set common objects using a setup method to reduce repeated codification for diverse tests. This preserve light test cases and minimizes duplication.
  • Refrain from Testing Implementation Details: Emphasize testing behavior, not internal effectuation. Tests must pass still if the implementation varies, but the behavior must be the same.
  • Make Tests Run Independently: Every tryout must be independent and not depend on the solution of another examination. State shared among tests can give irregular results.
  • Automate and Run Tests Regularly: Integrate tests into CI/CD pipelines so that they automatically fulfil with each code modification. Veritable test execution ensures bug get catch early, and constancy is maintained.

Why execute JUnit tests on Real Devices?

Executing JUnit tests on existent devicesguarantees consistent, real-world performance verification.

Although are utile in initial testing, they can not accurately simulate real user scenario like net variation, battery event, or device-specific behaviors. Existent devices deliver true tryout results, allow teams to detect and adjudicate issues before they involve users.

Why Use BrowserStack Automate for JUnit Testing?

offers on-demand access to 3,500+ real devices and browser, allowing developers to execute JUnit trial causa on a under without host an in-house device lab.

Key lineament include:

  • : Execute tests across multiple devices, OS version, and manufacturers.
  • Scalability: Automate cooccurring test scat to minimize test run time.
  • Cloud-Based Access: No twist purchases or hardware maintenance required—get the latest models on-demand.
  • Precise Debugging: Take screenshots, logs, and network observations to name problems quickly.
  • Smooth Integration: Integrates with major CI/CD solutions to carry out constant testing.

Useful Resources for JUnit

Talk to an Expert

Conclusion

JUnit and Mockitooffer a practical framework for creating trustworthy, maintainable, efficientunit tests.

Testing on existent devices further promotes test reliability by overcompensate for realistic scenario, which emulators and simulators can not achieve.

BrowserStack Automate provides cloud access to various real devices to simplify this summons, allowing easy cross-device testing,, and simplified debugging.

Tags
28,000+ Views

# Ask-and-Contributeabout this topic with our Discord community.

Related Guides

Automate This With SUSA

Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts needed.

Try SUSA Free

Test Your App Autonomously

Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.

Try SUSA Free