0% found this document useful (0 votes)
11 views13 pages

Java Unit Testing Guide: JUnit & Mockito

The document provides a comprehensive guide on Java unit testing using JUnit and Mockito, covering the fundamentals of unit testing, the JUnit framework, and effective test case writing. It explains concepts such as Test-Driven Development (TDD), the lifecycle of JUnit tests, and the differences between JUnit 4 and JUnit 5. Additionally, it introduces Mockito for mocking and spying in tests, detailing how to create mocks, stub methods, and the use of annotations like @Mock and @Spy.

Uploaded by

heyrahilkhan
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
11 views13 pages

Java Unit Testing Guide: JUnit & Mockito

The document provides a comprehensive guide on Java unit testing using JUnit and Mockito, covering the fundamentals of unit testing, the JUnit framework, and effective test case writing. It explains concepts such as Test-Driven Development (TDD), the lifecycle of JUnit tests, and the differences between JUnit 4 and JUnit 5. Additionally, it introduces Mockito for mocking and spying in tests, detailing how to create mocks, stub methods, and the use of annotations like @Mock and @Spy.

Uploaded by

heyrahilkhan
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Java Unit Testing (JUnit & Mockito) Interview

Guide
Fundamentals of Unit Testing
• What is unit testing and why is it important?
Unit testing is the practice of verifying individual units of code (such as methods or classes) in
isolation to ensure they behave correctly. It “validates individual units of software… checking if the
function works correctly and meets the requirements” 1 . By catching bugs early in the
development cycle, unit tests improve code quality and reliability. They run quickly (often on every
build) and provide immediate feedback, which is essential for continuous integration (CI) and agile
development 2 1 . Because unit tests focus on isolated logic, they make it easier to identify the
root cause of failures without involving external components.
• How does unit testing differ from other testing levels (e.g. integration or functional testing)?
Unlike integration or system tests, which verify multiple components working together, unit tests
target a single “unit” of code in isolation. This means unit tests do not rely on databases, network, or
other external systems. They are typically faster and more fine-grained. For example, while
integration tests require specialized tools and environments, unit tests can be written as soon as the
code exists and run on every build without special infrastructure 2 . This makes unit testing one of
the most fundamental testing types to ensure each piece of code works before it is combined with
others.
• What is TDD (Test-Driven Development)?
Test-Driven Development is a practice where developers write unit tests before the production code.
In TDD’s “Red-Green-Refactor” cycle, you first write a failing test (Red), then implement the minimal
code to pass the test (Green), and finally refactor the code with confidence. TDD ensures code is
designed for testability and that requirements are clearly captured in tests from the start. It relies
heavily on unit testing frameworks (like JUnit) and mock libraries (like Mockito) to quickly verify
behavior at each step.
• Why use unit tests in CI/CD?
In modern CI/CD pipelines, unit tests are run automatically on every code change. This practice
catches regressions immediately, preventing broken code from progressing. Because unit tests
execute quickly, they fit into fast feedback loops: as soon as code is committed, the build runs all
tests to ensure new changes didn’t break existing functionality 2 . This dramatically improves code
quality and stability throughout development.

JUnit Framework Overview: Annotations & Lifecycle


• What is JUnit and what role does it play in unit testing?
JUnit is a popular open-source testing framework for Java. It provides annotations to mark test
methods, assertion methods to check conditions, and a test runner to execute tests. Using JUnit,
developers can write repeatable tests in code. For example, the @Test annotation marks methods
that should be run as tests. JUnit frameworks (4 or 5) supply lifecycle annotations (e.g.,

1
@BeforeEach / @AfterEach , @BeforeAll / @AfterAll ) and assertion methods
( assertEquals , assertTrue , etc.) to automate test execution and validation.
• What does the @Test annotation do?
The @Test annotation (from JUnit4 or JUnit5) identifies a method as a test case to be run by the
test runner. During a test run, any method annotated with @Test is automatically executed. For
example, in JUnit5 you might write:

@Test
void testSum() {
assertEquals(4, [Link](2, 2));
}

This method will be executed as a test; if the assertion fails (e.g. [Link](2,2) returns
something other than 4), the test fails.
• What are @Before / @After (JUnit4) and @BeforeEach / @AfterEach (JUnit5)?
In JUnit4, methods annotated with @Before run before each test method, and @After methods
run after each test method 3 . They are useful for common setup and teardown code (e.g.,
initializing or clearing test data). In JUnit5 these annotations were renamed to @BeforeEach and
@AfterEach , but the behavior is the same 4 . For example:

@BeforeEach
void setup() {
list = new ArrayList<>();
}

@AfterEach
void teardown() {
[Link]();
}

Here, setup() runs before each test (ensuring a fresh list) and teardown() runs after each test.
• What are @BeforeClass / @AfterClass (JUnit4) and @BeforeAll / @AfterAll (JUnit5)?
@BeforeClass and @AfterClass in JUnit4 (or @BeforeAll and @AfterAll in JUnit5)
annotate methods that run once per test class. Typically these methods are used for expensive or
one-time setup/cleanup (like initializing a database connection). Importantly, in JUnit4
@BeforeClass / @AfterClass methods must be static 5 . For example,

@BeforeAll
static void initDatabase() {
dbConnection = new DatabaseConnection();
}
@AfterAll
static void closeDatabase() {

2
[Link]();
}

This code (JUnit5 syntax) creates a database connection before any tests run and closes it after all
tests complete 5 . In JUnit4, the equivalent would use @BeforeClass and @AfterClass with
static methods. JUnit5 simply renamed these annotations for clarity: @BeforeAll replaces
@BeforeClass , and @AfterAll replaces @AfterClass 4 .
• What is the test execution lifecycle in JUnit?
For each test class, JUnit follows this simplified lifecycle:
1. Before All Tests: Run methods annotated @BeforeClass (JUnit4) or @BeforeAll (JUnit5)
once.
2. Before Each Test: For each test method, run methods annotated @Before (JUnit4) or
@BeforeEach (JUnit5).
3. Test Method: Run the @Test method.
4. After Each Test: After the test method, run @After (JUnit4) or @AfterEach (JUnit5)
methods.
5. After All Tests: After all tests in the class, run @AfterClass (JUnit4) or @AfterAll
(JUnit5) once.
This ensures common setup/cleanup is executed appropriately. For example, with each new
test, the @Before code reinitializes state to avoid tests interfering with each other 3 5 .

Writing Effective Test Cases (JUnit 4 vs JUnit 5)


• What are the key differences between JUnit 4 and JUnit 5?
JUnit5 (JUnit Jupiter) is a redesign of JUnit4 with several changes:
• Annotations Renamed: As mentioned, @Before/@After → @BeforeEach/@AfterEach , and
@BeforeClass/@AfterClass → @BeforeAll/@AfterAll 4 .
• Assertions: JUnit5 uses [Link] (with assertThrows ,
assertDoesNotThrow , etc.), whereas JUnit4 uses [Link] .
• Parameterized Tests: JUnit5 has built-in support via @ParameterizedTest , @ValueSource ,
@CsvSource etc., whereas JUnit4 required the @RunWith([Link]) approach
6 .
• Extensibility: JUnit5 is modular (Jupiter, Vintage engines) and supports Java 8+ features like lambdas
in assertions. JUnit4 is monolithic.
• Tagging/Filtering: JUnit5 introduces @Tag to group tests; JUnit4 used custom @Category .
In practice, migrating tests to JUnit5 mainly involves updating annotation names and imports. For
example, a simple test looks similar:

// JUnit 5 example (uses [Link])


import static [Link];
import [Link];

class CalculatorTest {
@Test
void testAdd() {
Calculator calc = new Calculator();

3
assertEquals(4, [Link](2, 2));
}
}

// JUnit 4 example (uses [Link])


import static [Link];
import [Link];

public class CalculatorTest {


@Test
public void testAdd() {
Calculator calc = new Calculator();
assertEquals(4, [Link](2, 2));
}
}

The logic is identical; only the imports and annotations ( [Link] vs


[Link] ) differ.
- How do you test exceptions in JUnit?
In JUnit5, use assertThrows() to assert that a block of code throws a specific exception. For example:

@Test
void testException() {
Exception ex = assertThrows([Link], () -> {
[Link]("abc"); // should throw NumberFormatException
});
// Optionally assert on the exception message
assertTrue([Link]().contains("For input string")) ;
}

The assertThrows() method returns the thrown exception, allowing further assertions on it 7 . In
JUnit4, you would use the expected attribute on @Test :

@Test(expected = [Link])
public void testExceptionThrown() {
[Link]("abc");
}

Or use the ExpectedException rule for more control (e.g., to check exception message) 8 9 .
- What assertions are commonly used?
JUnit provides many assertion methods: assertEquals(expected, actual) ,
assertTrue(condition) , assertNull(obj) , etc. JUnit5 also adds assertNotNull , assertAll
(aggregate multiple checks), assertThrows , and assertDoesNotThrow 10 . Using meaningful
assertions helps verify correctness. For example, assertEquals(5, result) checks that a method
returned 5, and will fail the test if not.

4
- Can you write an example JUnit test method?
Sure. For instance:

@Test
void testMultiply() {
Calculator calc = new Calculator();
int product = [Link](3, 4);
assertEquals(12, product);
}

This test creates a Calculator , calls multiply , and asserts that the result is 12. The test will pass if
true, or fail otherwise. This example demonstrates the Arrange-Act-Assert pattern: setup objects, perform
action, then assert outcome.

Introduction to Mockito: Mocking, Stubbing, and Spying


• What is Mockito and why use it?
Mockito is a Java library for creating mock objects and spies in unit tests. Mocking means creating a
simulated object that mimics the behavior of a real dependency. This allows you to isolate the class
under test by replacing its collaborators with mocks. For example, if a service calls a database, you
can mock the database interface so the service is tested without a real database. Using Mockito, you
can stub method calls (define return values or exceptions) and verify interactions on mocks. This
helps ensure your unit tests focus only on the logic of the class under test without relying on
external systems.
• What is a mock, a stub, and a spy?
• Mock: A mock is an object created by Mockito that implements a class or interface and tracks
interactions (method calls). By default, mocked methods return default values (null, 0, false). Mocks
are used to verify that the class under test calls its dependencies correctly. They do not execute real
code. For example, [Link]([Link]) creates a mock List.
• Stub: Stubbing is the act of defining behavior on a mock. For example,
when([Link]()).thenReturn(5) tells the mock to return 5 when size() is called.
This sets up known behavior for the test. Stubs can specify return values or thrown exceptions when
methods are called.
• Spy: A spy wraps a real object instance and allows you to monitor interactions while still calling real
methods by default. In Mockito, spy(realObject) creates a spy. For example, a List spy will
add items to the list normally, but you can still verify calls on it. Unlike mocks, spies execute the real
implementation unless a method is stubbed. As Baeldung explains, “the spy will wrap an existing
instance… The only difference is that it will also be instrumented to track all the interactions with
it” 11 . In short, use a spy when you want partial mocking of a real object.
• How do you create a Mockito mock?
You can create mocks in two ways:
• Programmatically with [Link]() , e.g. List mockedList =
[Link]([Link]); .
• Using annotations: @Mock on a field and initializing mocks (e.g. with
[Link](this) or using a runner/extension) 12 13 . For example:

5
@Mock
private List<String> mockedList;

@BeforeEach
void init() {
[Link](this);
}
@Test
void testMockedList() {
when([Link]()).thenReturn(10);
assertEquals(10, [Link]());
}

The @Mock annotation tells Mockito to create and inject a mock instance automatically, simplifying
test setup 14 .
• How do you stub methods on a mock?
Use [Link](...).thenReturn(...) or thenThrow(...) . For example:

MyService serviceMock = [Link]([Link]);


when([Link]()).thenReturn("hello");

This stubs getData() to return "hello" . In JUnit tests, you would then call
assertEquals("hello", [Link]()) . For methods that return void, you use
doThrow().when() :

[Link](new RuntimeException()).when(serviceMock).process();

Then calling [Link]() will throw the exception. (Using when().thenThrow()


directly isn’t allowed for void methods 15 .) As Baeldung notes, for non-void methods you can do
when([Link](anyString())).thenThrow([Link]) 16 ,
and for void methods use doThrow 15 .
• Can you give an example of spying with Mockito?
Yes. A simple spy example:

List<String> realList = new ArrayList<>();


List<String> spyList = [Link](realList);
[Link]("one");
[Link]("two");
// Real methods executed, so size() is 2
assertEquals(2, [Link]());
// But we can verify interactions
[Link](spyList).add("one");
// We can also stub: force size() to return 100

6
[Link](100).when(spyList).size();
assertEquals(100, [Link]());

Here, spyList behaves like a normal list initially, but Mockito tracks calls on it. The example from
Baeldung shows that spying “will allow us to call all the normal methods of the object while still
tracking every interaction, just as we would with a mock” 17 . After stubbing size() , the spy
returns 100.
• What is the difference between a mock and a spy?
When Mockito creates a mock, it generates a bare-bones instance of the class (no real logic)
instrumented to record interactions 11 . Calls on a mock do not execute the real methods. In
contrast, a spy wraps an actual instance: it calls real methods by default and also records interactions
11 . For example, adding an element to a mocked List leaves its size at 0, whereas adding to a

spied List actually increases its size by 1. Baeldung demonstrates this: a mocked list has no side
effects, but a spy’s add() “will actually call the real implementation… and add the element to the
underlying list” 18 . In summary, use mocks when you want full isolation, and spies when you need
the real behavior with the ability to stub or verify.

Mockito Annotations: @Mock , @Spy , @InjectMocks


• What does @Mock do?
The @Mock annotation tells Mockito to create a mock instance of the annotated field. It eliminates
the need to call [Link]() manually. When using @Mock , you typically initialize
annotations with [Link](this) in a setup method or by using
@ExtendWith([Link]) in JUnit5. The field will then hold a mock object ready
for stubbing and verification 14 . For example:

@Mock
private UserRepository userRepository;

@BeforeEach
void init() {
[Link](this);
}
@Test
void testFindUser() {
when([Link](1)).thenReturn(new User(1,"Alice"));
// ...
}

• What does @Spy do?


The @Spy annotation creates a spy of the annotated field. That means Mockito will wrap the real
instance (or create one if assigned) and spy on it. For example:

@Spy
private List<String> spiedList = new ArrayList<>();

7
@Test
void testSpy() {
[Link]("one");
verify(spiedList).add("one");
assertEquals(1, [Link]()); // real method was called
}

The spy calls real methods ( add ) but you can still stub or verify methods if needed. This matches
the code example in Baeldung 19 .
• What does @InjectMocks do?
The @InjectMocks annotation tells Mockito to create an instance of the annotated class and inject
the mocks (and spies) into it. All fields of the class that match a mock’s type or name are set to the
mock. This is a form of dependency injection for tests. For example:

@Mock
private Map<String,String> wordMap;

@InjectMocks
private MyDictionary dic = new MyDictionary();

@Test
void testInjectMocks() {
when([Link]("key")).thenReturn("value");
assertEquals("value", [Link]("key"));
}

Here, wordMap is a mock, and dic is an instance of MyDictionary . Mockito will inject the
wordMap mock into [Link] . Baeldung notes that @InjectMocks “injects mock fields
into the tested object automatically” 20 . This eliminates manual setter calls and keeps tests cleaner.
• Can you use multiple annotations together?
Yes. Commonly you use @Mock for dependencies and @InjectMocks for the class under test. You
can also mix @Spy and @InjectMocks to inject mocks into a spied object, although full injection
into spies is limited. The order of initialization is: mocks and spies are created first, then injected into
the @InjectMocks object. Using the Mockito JUnit runner or
[Link](this) will activate these annotations.

Mocking Dependencies and Verifying Interactions


• Why do we mock dependencies?
In unit tests, we mock external dependencies to isolate the unit under test. For example, if class A
depends on class B (a database or service), mocking B ensures tests for A don’t actually access the
database. This isolation avoids side effects, speeds up tests, and makes failures easier to diagnose.
Mocks also let us simulate edge conditions (e.g. forcing errors) that might be hard to trigger
otherwise. As Indeed notes, using mocks “improves the reliability and robustness of tests” by
controlling dependencies 21 .

8
• How do you verify that a method was called on a mock?
Mockito provides a verify() method. After exercising the code under test, you call
verify(mock).someMethod(args) to ensure someMethod was called on the mock with the
given arguments. For example:

verify(userRepository, times(1)).findById(1);

checks that findById(1) was invoked exactly once. You can combine this with argument
matchers ( any() , eq() , etc.) or verifyNoMoreInteractions() to ensure no other calls
occurred. As one resource explains, you can also use times() to specify call count and include
arguments with matchers 22 . For example, verify(mock, times(2)).update(anyString())
asserts two calls.
• How do you verify method call order?
Mockito can verify order using InOrder . For example:

InOrder inOrder = [Link](mock1, mock2);


[Link](mock1).firstMethod();
[Link](mock2).secondMethod();

This asserts that firstMethod() on mock1 happened before secondMethod() on mock2 .


This is used when the sequence of interactions matters. (This goes beyond basic testing but is often
asked in interviews.)
• How can you capture arguments passed to a mock’s method?
Mockito provides ArgumentCaptor for this. You declare @Captor ArgumentCaptor<Type>
captor; (with [Link](this) ), or create one via
[Link]() . Then:

[Link]("one");
verify(mock).add([Link]());
assertEquals("one", [Link]());

This captures the actual argument passed. Using @Captor makes the test code cleaner. (Refer to
Baeldung for a detailed example.) This technique is useful to assert on parameters, not just call
counts.
• How do you test void methods or methods throwing exceptions?
For void methods on mocks, use doNothing() or doThrow() . For example, to make a mock’s
delete() method throw an exception:

doThrow(new RuntimeException()).when(mockedRepo).delete(anyInt());
assertThrows([Link], () -> [Link](123));

Baeldung notes that you must use doThrow(...).when() for void methods (since
when([Link]()) isn’t allowed) 15 . For example, in a test you might write:

9
doThrow([Link]).when(dictMock).add(anyString(),
anyString());
assertThrows([Link], () -> [Link]("x", "y"));

This configures the void method add() to throw. For methods that return values, simply
when(...).thenThrow([Link]) is used 16 .
• Give an example of using both JUnit and Mockito together in a test.
A typical integration of JUnit and Mockito might look like this:

@ExtendWith([Link]) // JUnit 5 integration


class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService; // class under test

@Test
void testGetUserById() {
// Arrange: stub behavior
when([Link](1)).thenReturn(new User(1,"Alice"));
// Act: call method under test
User result = [Link](1);
// Assert: verify result and interaction
assertNotNull(result);
assertEquals("Alice", [Link]());
verify(userRepository, times(1)).findById(1);
}
}

In this example, Mockito’s @Mock creates a fake UserRepository , and @InjectMocks injects it
into UserService . We stub the repository, call the service, and use JUnit assertions to check the
result and verify() to check the interaction. This pattern (Arrange-Act-Assert) is a best practice in
tests 23 : first set up mocks ( Arrange ), then call the method ( Act ), then Assert the outcome
and verify calls.

Handling Exceptions and Void Methods in Tests


• How do you test that a method throws a specific exception (using Mockito and JUnit)?
In JUnit5, use assertThrows() . Combine this with Mockito stubbing if needed. For example, if you
want to test that your service throws UserNotFoundException when a repository returns null:

when([Link](2)).thenReturn(null);
Exception ex = assertThrows([Link], () -> {
[Link](2);

10
});
assertEquals("User not found with ID: 2", [Link]());

This pattern is shown in the TDD example above 24 : the mock is set up to return null, and the test
asserts that getUserById(2) throws the exception with the expected message. In Mockito alone
(outside JUnit), you can stub a mock method to throw by using
when([Link]()).thenThrow([Link]) 16 (for non-void) or
doThrow().when(mock).method() 15 (for void). Then JUnit’s assertThrows verifies it.
• Can you test a void method that should throw an exception?
Yes. Since JUnit’s assertThrows works with any executable code, you simply put the void method
call in the lambda. In Mockito, stub the void to throw using doThrow . Example:

doThrow([Link]).when(myMock).doSomething();
assertThrows([Link], () -> [Link]());

As Baeldung notes, you cannot use when() with void methods, so doThrow() is required 15 .
• How do you ensure a block of code does not throw an exception?
In JUnit5, use assertDoesNotThrow() around the code block. For example:

assertDoesNotThrow(() -> {
int result = [Link](10, 2);
});

This test passes if no exception is thrown. JUnit4 has no built-in, but you can simply run code
normally or use a try/catch to fail on exceptions. The BrowserStack guide even shows a custom
assertNoExceptionIsThrown() method for JUnit4 25 .

Best Practices for Maintainable and Readable Test Code


• How should you structure your tests (Arrange-Act-Assert)?
Follow the AAA pattern: Arrange (set up test data and mocks), Act (execute the method under test),
Assert (verify results). This makes tests clear and consistent. For example, the earlier
testGetUserById arranges the stub and service, acts by calling the service, and asserts the
outcome and interaction.
• How do you name test methods?
Give tests descriptive names reflecting behavior. A common convention is
methodName_condition_expectedResult , e.g.,
getUserById_nonexistentUser_throwsException() . This self-documenting style makes it
clear what is being tested. BrowserStack advises using meaningful names so tests are self-describing
26 .

• Should tests be small and focused?


Yes – each test should verify one specific behavior. This makes failures obvious and tests easier to
maintain. If a test covers too much, it may pass even when part of the logic is broken. BrowserStack
emphasizes “only one behavior must be checked per test” to enhance readability and clarity 27 .
• What are common Mockito best practices?

11
• Mock only external dependencies: Don’t mock the class under test itself; only mock collaborators
(DB, web services, etc.) 28 .
• Verify critical interactions: Use verify() to check that important methods on mocks are called
(with correct arguments) 29 .
• Avoid over-verifying: Only verify essential calls to avoid brittle tests (e.g., verify external service calls
but not trivial getters).
• Use annotations and setup methods: Initialize mocks in @BeforeEach to avoid duplication 30 .
For example, calling [Link](this) or using
@ExtendWith([Link]) ensures all @Mock fields are ready.
• Don’t test implementation details: Focus tests on observable behavior. Don’t lock tests to private
logic; if internal design changes but externally the behavior is the same, tests should still pass 31 .
• Keep tests independent: Each test should be able to run on its own, without relying on other tests’
side effects or order 32 .
• Include edge cases and exceptions: Write tests for null inputs, invalid data, and exception paths to
ensure robustness 33 .
• Review test code readability: Structure code clearly, use helper methods if needed, and avoid
lengthy setup in tests.

Scenario-Based Examples
• Scenario: Testing a Service with a Mocked Repository
Setup: A [Link](int id) method calls [Link](id)
and throws UserNotFoundException if null .
Test: Stub [Link](2) to return null . Then use assertThrows to verify
the exception:

when([Link](2)).thenReturn(null);
Exception exception = assertThrows([Link], () -> {
[Link](2);
});
assertEquals("User not found with ID: 2", [Link]());

This test fails if no exception is thrown, ensuring the service handles the “not found” case correctly
24 .

• Scenario: Verifying Interactions Order


Suppose a method should first save data then send a notification. You can use InOrder to verify
call order:

[Link](data);
InOrder order = inOrder(databaseMock, notificationMock);
[Link](databaseMock).save(data);
[Link](notificationMock).notify(any());

This ensures save() happens before notify() .

12
• Scenario: Testing Void Methods
If sendEmail() is void but should not throw an exception:

assertDoesNotThrow(() -> [Link]("user@[Link]",


"Hello"));

If it should throw on invalid input: stub accordingly and use assertThrows .

Each of these examples demonstrates applying JUnit and Mockito together to handle real-world cases:
mocking dependencies, stubbing behavior, verifying outcomes, and ensuring exception paths are tested.

Sources: Concepts and examples are based on official Mockito/JUnit documentation and expert tutorials
3 5 14 11 15 7 23 24 , which provide detailed explanations and code demonstrations for these

topics.

1 2 Unit Testing - Software Testing - GeeksforGeeks


[Link]

3 4 5 @Before vs @BeforeClass vs @BeforeEach vs @BeforeAll | Baeldung


[Link]

6 JUnit 5 vs JUnit 4 - GeeksforGeeks


[Link]

7 8 9 10 25 Assert an Exception Is Thrown in JUnit 4 and 5 | Baeldung


[Link]

11 17 18 Mockito - Using Spies | Baeldung


[Link]

12 13 14 19 20 Getting Started with Mockito @Mock, @Spy, @Captor and @InjectMocks | Baeldung
[Link]

15 16 Mocking Exception Throwing using Mockito | Baeldung


[Link]

21 22 26 Mockito Interview Questions (With Sample Answers) | [Link] India


[Link]

23 24 26 27 28 29 30 31 32 33 Writing Unit Tests with JUnit and Mockito | BrowserStack


[Link]

13

You might also like