CodeGym /Courses /Module 5. Spring /Lecture 262: Unit testing for microservices: tools and ap...

Lecture 262: Unit testing for microservices: tools and approaches

Module 5. Spring
Level 21 , Lesson 1
Available

If you compare building microservices to constructing a skyscraper, unit tests are the checks on every single bricklaying. Imagine one brick is defective: the skyscraper can collapse. It's the same with microservices — even a small bug in a service can cause big problems during integration or production.

Unit tests help you:

  • Make sure the core business logic actually works. For example, a banking service shouldn't just hand a customer a couple million for no reason.
  • Isolate bugs. If a test fails, you immediately see which method or module is at fault.
  • Make refactoring safer. Changing the implementation? Make sure the old tests still pass.
  • Keep the developer sane. There's nothing worse than chasing a bug that pops up after deploy.

Main tools for unit testing

You don't need to reinvent the wheel to write unit tests in the Java ecosystem. It's all been figured out:

  1. JUnit 5 — the de-facto standard for testing in Java. Powerful, flexible, and pretty easy to pick up.
  2. Mockito — a library for creating mocks (fake objects) that let you test modules in isolation.
  3. AssertJ — for more readable and advanced assertions in tests (optional, but handy).

JUnit 5: testing basics

JUnit lets you write unit tests that check specific methods or classes. The most useful JUnit annotations:

  • @Test — marks a method as a test.
  • @BeforeEach — runs before each test.
  • @AfterEach — runs after each test.
  • @DisplayName — gives a readable name to the test.

Example of a simple test with JUnit:


import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;

class CalculatorTest {

    @Test
    void testAddition() {
        Calculator calculator = new Calculator();
        int result = calculator.add(1, 2);
        assertEquals(3, result, "1 + 2 must equal 3");
    }
}

Mockito: creating mocks

Mockito is your best friend for testing dependencies. Mocks let you isolate the code under test by replacing real dependencies with fakes. Use them to test just your code without calling external services, databases, etc.

Example using Mockito:


import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import static org.mockito.Mockito.*;

class OrderServiceTest {

    @Test
    void testCreateOrder() {
        // Create a mock for the repository
        OrderRepository repository = mock(OrderRepository.class);

        // Create OrderService with the fake repository
        OrderService service = new OrderService(repository);

        // Define mock behavior: return a fake value
        when(repository.save(any(Order.class))).thenReturn(new Order(1L, "Test Order"));

        // Call the method and check the result
        Order order = service.createOrder("Test Order");
        assertEquals(1L, order.getId(), "Order ID should be 1");
        assertEquals("Test Order", order.getName(), "Order name should be 'Test Order'");

        // Verify that save was actually called
        verify(repository).save(any(Order.class));
    }
}

Approaches to writing unit tests

When testing services you'll likely face various dependencies: repositories, other services, external APIs. To test logic in isolation, you need to:

  1. Create mocks for dependencies.
  2. Define their behavior using when (for example, when(repository.findById(1L)).thenReturn(mockEntity)).
  3. Verify that the required methods were called with correct parameters (using verify).

Example with multiple dependencies:


import static org.mockito.Mockito.*;

class PaymentServiceTest {
    @Test
    void testProcessPayment() {
        PaymentGateway gateway = mock(PaymentGateway.class);
        NotificationService notification = mock(NotificationService.class);

        PaymentService service = new PaymentService(gateway, notification);

        when(gateway.process(any(PaymentRequest.class))).thenReturn(true);

        service.processPayment(new PaymentRequest(100));

        verify(gateway).process(any(PaymentRequest.class));
        verify(notification).sendNotification(any());
    }
}

Testing business logic

Unit tests should cover not only happy paths but also edge cases. For example:

  • Validation for invalid input. The service should throw an exception or return an error.
  • Checks for "empty" data: empty lists, null values, etc.
  • Checks for maximum and minimum input values.

Example:


@Test
void testValidateInput_NullValue() {
    IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
        someService.validateInput(null);
    });
    assertEquals("Input cannot be null", exception.getMessage());
}

What to test and what not to test?

Remember that unit tests should not:

  1. Test third-party libraries (are you really going to test that StringUtils.capitalize() works? Hope not).
  2. Test interactions with the database or network (that’s what integration tests and Testcontainers are for).

Unit tests should:

  1. Test the logic of your application: methods, functions, classes.
  2. Check edge cases: invalid data, boundary values.
  3. Verify that dependency calls happen exactly as expected (using Mockito).

Common mistakes when writing unit tests

  1. Tests depend on external environment. For example, a test that hits a real database.
  2. No assertions. If a test just runs but doesn't check anything, it's not a test.
  3. Confusion with mocks. Overly complex mock setup can confuse you and your teammates.
  4. Tests become more complex than the code itself. Remember tests should be simple and readable.

Practical use

Unit tests won't just prove your code works — they'll also impress your future employer. During interviews you might be asked: "How do you write tests?" That's your chance to show off your JUnit, Mockito, and testing strategy knowledge.

Also, good unit tests make changing code much safer. If someone on your team accidentally "breaks" business logic, the tests will shout about it immediately.

Documentation links:

So grab JUnit, Mockito, and start writing tests for your microservice app. After all, tested code is good code!

Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION