Skip to main content
skill CX Codex

unit-test-service-layer — Claude Code skill: Mockito service tests

A skill that gives the agent a Mockito pattern for service-layer unit tests: mock repositories, verify calls, cover exception paths.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add giuseppe-trisciuoglio/developer-kit --skill unit-test-service-layer -a claude-code
Open on GitHub

What unit-test-service-layer does

The skill walks through testing @Service classes: enable Mockito annotations with @ExtendWith(MockitoExtension.class), declare dependencies as @Mock and the service under test as @InjectMocks. Then Arrange-Act-Assert — set up data and stub returns with when().thenReturn(), call the method, assert the result with AssertJ and check interactions with verify(). Each step has a validation checkpoint: run the test, confirm the green bar.

Exception paths get their own section. The mock is configured with when().thenThrow(), and the test asserts the exception type and message. At the end the workflow runs the full suite (mvn test or gradle test) and a coverage report via mvn test jacoco:report. A references/examples.md file inside the skill covers more ground: multiple dependencies, argument captors, async services, InOrder verification.

The constraints matter more than the examples. Value objects and DTOs are never mocked — you build real instances with test data. Argument matchers like any() and eq() can't be mixed with actual values in the same stub, or the stub won't match. Private methods are tested through public behaviour only. And if a service needs too many mocks to test, that's a signal to refactor rather than pile more collaborators into the test.

What it helps with

  • write a service unit test without booting a Spring context or a database
  • mock a repository and check the service called it with the right argument
  • assert that a method throws the expected exception on an empty result
  • stub an external client response so the test never hits the network
  • split a test into Arrange-Act-Assert and remember to verify interactions

Example prompts for the agent

  • Write Mockito unit tests for UserService: mock UserRepository, cover the found-user path and the UserNotFoundException case.
  • Add a test that verifies emailService.sendWelcomeEmail is called when a new user registers.
  • Run mvn test and show me which service methods still have no coverage.

How to install unit-test-service-layer

1Skills CLI (Vercel)

npx skills add giuseppe-trisciuoglio/developer-kit --skill unit-test-service-layer -a claude-code

2Manually: put the files in place

~/.claude/skills/unit-test-service-layer/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/unit-test-service-layer/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about unit-test-service-layer

How do I install unit-test-service-layer in Claude?

Run npx skills add giuseppe-trisciuoglio/developer-kit --skill unit-test-service-layer -a claude-code. The skill lands in ~/.claude/skills/unit-test-service-layer/SKILL.md.

What does unit-test-service-layer do?

It hands the agent Mockito patterns for service-layer unit tests: mocked repositories and clients, verified invocations, exception scenarios. Tests run without a Spring container or database.

How is this different from integration tests?

It targets isolated business-logic tests. Dependencies are replaced with mocks, so no database or external API is involved in the run.

Source text

SKILL.md · MIT
---
name: unit-test-service-layer
description: Provides patterns for unit testing service layer with Mockito. Creates isolated tests that mock repository calls, verify method invocations, test exception scenarios, and stub external API responses. Use when testing service behaviors and business logic without database or external services.
allowed-tools: Read, Write, Bash, Glob, Grep
---

# Unit Testing Service Layer with Mockito

## Overview

Provides patterns for unit testing `@Service` classes using Mockito. Mocks repository calls, verifies method invocations, tests exception scenarios, and stubs external API responses. Enables fast, isolated tests without Spring container or database.

## When to Use

- Testing business logic in `@Service` classes
- Mocking repository and external client dependencies
- Verifying service interactions with mocked collaborators
- Testing error handling and edge cases in services
- Writing fast, isolated unit tests (no database, no API calls)

## Instructions

Follow this workflow to test service layer with Mockito, including validation checkpoints:

### 1. Setup Test Class

Use `@ExtendWith(MockitoExtension.class)` to enable Mockito annotations.

### 2. Declare Mocks with `@Mock` and `@InjectMocks`

Use `@Mock` for dependencies (repositories, clients) and `@InjectMocks` for the service under test.

### 3. Arrange-Act-Assert with Validation

**Arrange**: Create test data and configure mock return values using `when().thenReturn()`.

**Act**: Execute the service method being tested.

**Assert**:
- Verify returned values with AssertJ assertions
- Verify mock interactions with `verify()`
- **Validation checkpoint**: Run test and confirm green bar

### 4. Test Exception Scenarios

Configure mocks to throw exceptions with `when().thenThrow()`.

**Validation checkpoint**: Verify exception type and message

### 5. Verify Complete Coverage

- Run full test suite: `mvn test` or `gradle test`
- Check coverage report: `mvn test jacoco:report`
- **Validation checkpoint**: Confirm all service methods have corresponding tests

## Examples

### Basic Service Test Pattern

```java
@ExtendWith(MockitoExtension.class)
class UserServiceTest {

  @Mock
  private UserRepository userRepository;

  @InjectMocks
  private UserService userService;

  @Test
  void shouldReturnUserWhenFound() {
    // Arrange
    User expected = new User(1L, "Alice");
    when(userRepository.findById(1L)).thenReturn(Optional.of(expected));

    // Act
    User result = userService.getUser(1L);

    // Assert
    assertThat(result.getName()).isEqualTo("Alice");
    verify(userRepository).findById(1L);
  }

  @Test
  void shouldThrowWhenUserNotFound() {
    // Arrange
    when(userRepository.findById(999L)).thenReturn(Optional.empty());

    // Act & Assert
    assertThatThrownBy(() -> userService.getUser(999L))
      .isInstanceOf(UserNotFoundException.class);
  }
}
```

### Verify Method Invocations

```java
@Test
void shouldSendEmailOnUserCreation() {
  User newUser = new User(1L, "Alice", "[email protected]");
  when(userRepository.save(any(User.class))).thenReturn(newUser);

  enrichmentService.registerNewUser("Alice", "[email protected]");

  verify(userRepository).save(any(User.class));
  verify(emailService).sendWelcomeEmail("[email protected]");
}
```

For additional patterns (multiple dependencies, argument captors, async services, InOrder verification), see `references/examples.md`.

## Best Practices

- **Use `@ExtendWith(MockitoExtension.class)`** for JUnit 5 integration
- **Mock only direct dependencies** of the service under test
- **Verify interactions** to ensure correct collaboration
- **Test one behavior per test method** - keep tests focused
- **Use descriptive variable names**: `expectedUser`, `actualUser`, `captor`
- **Create real instances** for value objects and DTOs (don't mock them)

## Constraints and Warnings

- Do not mock value objects or DTOs; create real instances with test data.
- Avoid mocking too many dependencies; consider refactoring if a service has too many collaborators.
- Tests must be independent; do not rely on execution order.
- Be cautious with `@Spy`; partial mocking is harder to understand and maintain.
- Do not test private methods directly; test them through public method behavior.
- Argument matchers (`any()`, `eq()`) cannot be mixed with actual values in the same stub.
- Avoid over-verifying; verify only interactions important to the test scenario.

## References

- [Mockito Documentation](https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html)
- [JUnit 5 User Guide](https://junit.org/junit5/docs/current/user-guide/)
- [AssertJ Assertions](https://assertj.github.io/assertj-core-features-highlight.html)

© giuseppe-trisciuoglio · MIT · giuseppe-trisciuoglio/developer-kit

Similar skills

All skills for Testing and QA →

From the same set96

spring-boot-actuator Guides setup of Spring Boot Actuator endpoints, Kubernetes health probes, isolated management ports, and Micrometer metric exports. CX Codex +1 3,800installs spring-ai-mcp-server-patterns A skill with Spring Boot and Spring AI patterns for MCP servers: @Tool handlers, prompt templates, and stdio, HTTP or SSE transports. CX Codex +1 3,800installs nestjs-code-review A skill that reviews NestJS apps: controllers, services, modules, DI, guards and database patterns. Useful before merging a pull request. CX Codex +1 3,800installs spring-boot-resilience4j Generates Resilience4j fault tolerance patterns for Spring Boot 3.x projects. Use it to configure circuit breakers and retry logic. CX Codex +1 3,800installs nestjs-best-practices A skill that hands your agent a rulebook for NestJS: module boundaries, provider scopes, exception filters, DTO validation and Drizzle ORM. CX Codex +1 3,800installs spring-boot-cache Configures caching in Spring Boot services using Caffeine, Redis, or Ehcache providers. Helps set up TTL policies, apply cache annotations, and trace cache misses. CX Codex +1 3,800installs zod-validation-utilities Guides Zod v4 validation for TypeScript APIs, forms, and configuration. Use it when external input needs parsing, coercion, and clear validation errors. CX Codex +1 3,800installs spring-boot-event-driven-patterns A Spring Boot 3.x skill for domain events, @TransactionalEventListener, Kafka messaging and the transactional outbox pattern. Useful when sync calls between services need to become events. CX Codex +1 3,800installs

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor