Unit Testing Concepts & Its Implementation in Java with PowerMock (and Mockito)
Unit Testing Concepts and Principles, Unit Testing in Java using PowerMock and Mockito
Unit testing validates the function of a unit, ensuring that the inputs (one to a few) result in the lone desired output. This testing type provides the foundation for more complex integrated software.
Unit Testing Principles
- Simply stick to the one test class per production class rule of thumb
- ensure that all your happy path and edge cases are included in your tests
- your test code and structure should be as loosely coupled with your main code as it can be. test for observable behaviour.
if I enter values x and y, will the result be z? ✔️
if I enter x and y, will the method call class A first, then call class B and then return the result of class A plus the result of class B? ❌
Solitary and Sociable Unit Tests
- Solitary: mocks or stubs should be used to come up with perfect isolation and to avoid side-effects and a complicated test setup.
- Sociable: only collaborators that are slow or have bigger side effects (e.g. classes that access databases or make network calls) should be stubbed or mocked.
- Both are accepted.
- Test Double: where you replace a production object (e.g. a class, module or function) for testing purposes.
- Dummy objects: never actually used, used to fill parameter lists.
- Fake objects: working implementations, suitable for testing environment (InMemoryTestDatabase).
- Stubs: are used when we don’t want to use objects that would give a response with real data. they hold predefined data to give responses during tests. mainly used for performing state verification.
- Mocks: are the objects that store method calls, gives full control over the behavior of the mocked objects. generally used for behavior verification.
- Spies: stubs. partially mock objects. the real object remains unchanged, and we just spy some specific methods of it.
Mockito Annotations — “@Mock”, “@Spy” and “@InjectMocks”
- The @Mock annotation is used to create and inject mocked instances (without having to call Mockito.mock manually). We do not create real objects, rather ask Mockito to create a mock for the class.
- @Spy, like @Mock, is designed to set up test doubles. With @Spy, you can use both real methods of a class or stub its methods.
- @Spy and @Mock are always meant for dependencies, and not for your system under test.
- @InjectMocks marks a field on which injection should be performed. If you have a test that defines a @Mock or @Spy of the right type, Mockito will try to inject mocks only either by constructor injection, setter injection, or property injection — in this order.
Using PowerMock in Spring Boot
Here is my project’s dependencies for PowerMock (using 2.0.9 version).
After creating your test class, you should annotate it like below:
Mocking Static Classes
Firstly, you should add “@PrepareForTest” annotation and add your static class.
What does “@PrepareForTest” do?
(From official docs) This annotation tells PowerMock to prepare certain classes for testing. This includes final classes, classes with final, private, static or native methods that should be mocked and also classes that should be return a mock object upon instantiation.
Here, I mocked “OrientationUtils.class” to ensure its method is called the same amount of times as expected.
You have to declare your verification first and then call the method. Be careful with the order.
If you are using construction injection, you should provide your mock classes to your spy class. “SubscriptionJobConfig, ArchiveAccountTtlInfoService, ArchiveBatchJobService, JobExecutionRouter” classes are added to “@PrepareForTest” annotation as well as being declared with “@Mock” annotation. The class I am writing tests for is “SubscriptionJobScheduler” (with “@InjectMocks”) as you can see here:
I initialized my mock services using “PowerMockito.whenNew” and provided them to my spy service:
Different from “thenReturn”, you can return different responses depending on parameter values with “thenAnswer”:
Mock Private Methods
You can mock private methods with “Whitebox.invokeMethod(method_name_in_str, parameters)”.
You can use “assertThrows” if you would like to test exception messages, too.
(From official docs) This annotation tells PowerMock to defer the loading of classes with the names supplied to “value()” to the system classloader.
This is useful in situations when you have e.g. a test/assertion utility framework (such as something similar to Hamcrest) whose classes must be loaded by the same classloader as EasyMock, JUnit and PowerMock etc.
If you get a linkage error using PowerMock, you should add “@PowerMockIgnore(“javax.management.*”)”
For an encrypt/decrypt utility class, I had to include other packages as:
There are times you need to run your tests in order, especially when you want to perform integration tests, like testing a database service, insert-update-delete the same record in order. For this, you can use “@FixMethodOrder” and choose “MethodSorters.NAME_ASCENDING” and name your methods accordingly.
- Integration testing is often done in concert with unit testing.
- They test the integration of your application with all the parts that live outside of your application.
- treat integration testing more narrowly and test one integration point at a time by replacing separate services and databases with test doubles.