Mockito Basics - anastasiamexa/Healthy-Coder-App GitHub Wiki
Basic concepts
Mockito is a popular Java testing framework that allows you to create and configure mock objects for testing purposes. Mock objects are simulated objects that mimic the behavior of real objects in controlled ways, making it easier to isolate and test specific components of your code. Here's a basic summary of the basics of Mockito:
Mocking
- Purpose: Mockito allows you to create mock objects, which are objects with simulated behavior. This is useful for isolating the code under test by replacing dependencies with mocks.
- Example: Creating a mock object for an interface.
// Interface to be mocked
public interface MyInterface {
String someMethod();
}
// Creating a mock object
MyInterface myMock = mock(MyInterface.class);
Stubbing
- Purpose: You can define the behavior of mock objects using stubbing. Stubbing means specifying what a method should return when it's called with specific arguments.
- Example: Stubbing a method to return a specific value.
// Stubbing a method to return a specific value
when(myMock.someMethod()).thenReturn("MockedValue");
// Testing code that uses the mock
assertEquals("MockedValue", myMock.someMethod());
Verifying Interactions
- Purpose: Mockito allows you to verify that specific interactions with mock objects have occurred, such as method invocations and the number of times a method was called.
- Example: Verifying that a method was called with specific arguments.
// Testing code that interacts with the mock
myMock.someMethod("ArgumentValue");
// Verifying that the method was called with specific arguments
verify(myMock).someMethod("ArgumentValue");
Argument Matchers
- Purpose: Mockito provides matchers for specifying flexible argument matching in stubbing and verification. Matchers allow you to match arguments based on various conditions.
- Example: Using argument matchers in stubbing.
// Using argument matchers in stubbing
when(myMock.someMethod(anyString())).thenReturn("MockedValue");
// Testing code that uses the mock
assertEquals("MockedValue", myMock.someMethod("AnyString"));
Exception Handling
- Purpose: Mockito allows you to specify that a mock method should throw an exception when called, which is useful for testing error conditions.
- Example: Stubbing a method to throw an exception.
// Stubbing a method to throw an exception
when(myMock.someMethod()).thenThrow(new RuntimeException("Mocked Exception"));
// Testing code that uses the mock
assertThrows(RuntimeException.class, () -> myMock.someMethod());
Spying
- Purpose: Mockito provides the ability to create spy objects, which are partial mocks. A spy allows you to retain the real behavior of the object while selectively stubbing or verifying certain methods.
- Example: Creating a spy object on a real instance.
// Class to be spied on
public class MyObject {
public String realMethod() {
return "RealValue";
}
}
// Creating a spy object
MyObject mySpy = spy(new MyObject());
// Stubbing and testing code that uses the spy
when(mySpy.realMethod()).thenReturn("MockedValue");
assertEquals("MockedValue", mySpy.realMethod());
Annotations
- Purpose: Mockito supports annotations to simplify the process of creating and managing mocks. Annotations include
@Mock
,@InjectMocks
, and@Spy
. - Example: Using
@Mock
and@InjectMocks
annotations.
// Class to be tested
public class MyClass {
private MyDependency dependency;
public MyClass(MyDependency dependency) {
this.dependency = dependency;
}
public String processData() {
// Some logic using the dependency
return dependency.getData();
}
}
// Interface to be mocked
public interface MyDependency {
String getData();
}
// Using annotations to create mocks and inject them
@Mock
private MyDependency myMock;
@InjectMocks
private MyClass myClassUnderTest;
// Setting up the test
@BeforeEach
void setUp() {
MockitoAnnotations.initMocks(this);
}
// Testing code that uses the injected mocks
@Test
void testProcessData() {
// Stubbing the dependency method
when(myMock.getData()).thenReturn("MockedData");
// Testing the logic in MyClass
assertEquals("MockedData", myClassUnderTest.processData());
}
Resetting Mocks
- Purpose: Mockito allows you to reset the state of mock objects, which can be useful in certain scenarios where you want to reuse a mock with a clean state.
- Example: Resetting the state of a mock.
// Resetting the state of a mock
reset(myMock);
// Testing code that uses the reset mock
myMock.someMethod(); // The method will behave as per the default behavior or new stubbing
These are just some of the basics of Mockito. The framework provides many other features and capabilities, making it a powerful tool for writing effective and flexible unit tests in Java. It is commonly used in conjunction with testing frameworks like JUnit to create comprehensive and reliable test suites.
Mocks vs Spies
In Mockito, both mocks and spies are used to create objects with simulated behavior, but they serve different purposes and have distinct use cases.
Mocks
1. Purpose:
- Isolation: Mocks are primarily used for isolating the code under test by replacing dependencies with simulated objects.
2. Behavior:
- Default Behavior: By default, mocks have a default behavior for all methods, such as returning
null
for objects and0
for numbers. - Stubbing: You can specify the behavior of individual methods using stubbing (e.g., using
when
andthenReturn
).
3. Verification:
- Method Calls: Mocks are commonly used to verify that specific methods have been called during the execution of the test.
- Invocation Count: You can verify the number of times a method was called or ensure that it was not called.
4. Creation:
- Empty Object: Mocks are created as "empty" objects without a real implementation.
- Interface or Class: You can create mocks for both interfaces and concrete classes.
Spies
1. Purpose:
- Partial Mocking: Spies are used when you want to retain the real behavior of the object but selectively stub or verify certain methods.
2. Behavior:
- Real Behavior: Spies delegate the calls to the real methods of the object by default, unless specified otherwise.
- Partial Stubbing: You can selectively stub methods while retaining the real behavior for others.
3. Verification:
- Method Calls: Spies can be used to verify that specific methods of the real object have been called.
- Invocation Count: Similar to mocks, you can verify the number of times a method was called or ensure that it was not called.
4. Creation:
- Real Object: Spies are created based on an existing instance of a real object, and the real object's behavior is retained.
Mock Example
public interface MyDependency {
String getData();
}
// Creating a mock for an interface
MyDependency myMock = mock(MyDependency.class);
// Stubbing a method in the mock
when(myMock.getData()).thenReturn("MockedData");
// Testing code that uses the mock
assertEquals("MockedData", myMock.getData());
// Verifying method calls
verify(myMock, times(1)).getData();
Spy Example
public class MyObject {
public String realMethod() {
return "RealValue";
}
}
// Creating a spy based on a real instance
MyObject mySpy = spy(new MyObject());
// Stubbing a method in the spy (retaining real behavior for other methods)
when(mySpy.realMethod()).thenReturn("MockedValue");
// Testing code that uses the spy
assertEquals("MockedValue", mySpy.realMethod());
// Verifying method calls (using real behavior for unstubbed methods)
verify(mySpy, times(1)).realMethod();
In summary, mocks are generally used for isolating the code under test by replacing dependencies, while spies are used when you want to retain the real behavior of an object but selectively stub or verify certain methods. The choice between mocks and spies depends on the specific testing requirements and the desired level of isolation or integration with real behavior.