DEV Community

Mohammed Ghallab
Mohammed Ghallab

Posted on

Mastering Unit Testing in Spring Boot: How I Achieved 70%+ Coverage for Open Source

 Testing is not about finding bugs; it's about gaining the confidence to ship code.
Recently, while contributing to an Open Source project for GSSoC 2026, I took on the challenge of writing unit tests for a complex DecisionService. My goal was 70%+ coverage, but the journey was filled with NullPointerExceptions and mocking hurdles. Here is how I solved them.

  1. The Challenge The DecisionService I was testing relied on multiple repositories and complex DTO mapping. When I first ran my tests, I kept hitting a wall: java.lang.NullPointerException: Cannot invoke "OffsetDateTime.toInstant()" because ... is null

This happened because the service was converting entity timestamps to Instants for the API response, but in a Mockito environment, these fields aren't automatically populated like they are in a real database.

  1. The Technical Solution To fix this, I had to ensure that every Mock object was fully initialized with the fields required by the Mapper. Here’s a snippet of the successful test setup:
@Test
@DisplayName("Should create decision successfully")
void createDecision_Success() {
    // 1. Prepare the Request
    CreateDecisionRequest request = new CreateDecisionRequest(
        "Feature", "Body", "repo-1", DecisionStatus.PROPOSED, List.of("java")
    );

    // 2. Build the Mock Entity with required fields (Crucial Step!)
    Decision savedDecision = Decision.builder()
            .id("dec-1")
            .author(mockUser)
            .repo(mockRepo)
            .createdAt(OffsetDateTime.now()) // The fix for NPE!
            .status(DecisionStatus.PROPOSED)
            .build();

    // 3. Mock the behavior
    when(decisionRepository.save(any(Decision.class))).thenReturn(savedDecision);

    // 4. Act & Assert
    DecisionResponse response = decisionService.createDecision(request, currentUserId);
    assertThat(response.title()).isEqualTo("Feature");
}
Enter fullscreen mode Exit fullscreen mode
  1. Key Takeaways
  • Mocks are not Magic: If your service maps an entity to a DTO, your Mock entity must have all the fields the Mapper touches.
  • Context Matters: In Spring Boot tests, pay attention to OffsetDateTime and relational objects like Repo or User.
  • Clean over Complex: Using thenReturn() is often more readable and predictable than thenAnswer() for simple Unit Tests.

Call to Action

Writing these tests increased the project's reliability and helped me understand the inner workings of Spring Boot even better.

Are you working on GSSoC 2026? Let's connect!
Check out my full contribution and other projects on my GitHub: MohammedGhallab.

java #springboot #testing #opensource

Top comments (0)