Skip to main content
rule

mockito — Cursor rule: what it does, how to install

This rule guides Java unit tests written with Mockito and JUnit 5, from mock setup to argument checks. Use it when an agent creates or edits tests.

Install into Cursor · Manually: put the files in place All methods and platforms ↓
.cursor/rules/mockito.mdc
Open on GitHub

What mockito does

The .cursor/rules/mockito.mdc file applies to **/*.java. It recommends integrating Mockito through @ExtendWith(MockitoExtension.class), using annotations to initialize mocks, and keeping each test focused on one behavior. Assert observable results rather than internal calls.

The guidance covers strict stubbing, ArgumentCaptor, choosing mocks over spies, and parameterized tests with @CsvSource. Remove unused stubs; reserve lenient() for specific cases. Mockito 5 supports mocking final classes, static methods, and constructors, though the rule advises restraint. The setup uses JUnit 5 and Mockito; it does not use the older JUnit 4 runner.

What it helps with

  • configure Mockito for JUnit 5 tests
  • separate distinct behaviors into focused tests
  • inspect the exact object passed to a mock
  • remove unused stubs that trigger exceptions
  • replace repetitive cases with a parameterized test

Example prompts for the agent

  • Write a Java unit test for this service using Mockito and JUnit 5, following this rule.
  • Review these tests and remove unused stubs; split unrelated checks into separate tests.
  • Add a parameterized test with @CsvSource for these input values.

How to install mockito

Manually: put the files in place

.cursor/rules/mockito.mdc

Frontmatter: description, globs, alwaysApply

Step by step, with commands for each platform: Cursor rules: .mdc files, four modes and what replaced .cursorrules

Questions about mockito

How do I install mockito in Cursor?

Create .cursor/rules/mockito.mdc and place the rule in that file.

What does the mockito rule do?

It guides Java unit testing with Mockito and JUnit 5, including mock setup, outcome checks, and stub handling.

What does mockito require?

The rule is for Java files and tests using JUnit 5 and Mockito. It uses MockitoExtension for integration.

Source text

mockito.mdc · CC0-1.0
---
description: This guide provides definitive best practices for writing robust, maintainable, and readable unit tests using Mockito with JUnit 5, focusing on modern patterns and common pitfalls.
globs: **/*.java
---
# Mockito Best Practices

Mockito is the indispensable mocking framework for Java unit testing. Adhere to these guidelines to ensure your tests are clear, reliable, and resistant to refactoring.

## 1. Standardize Test Setup with JUnit 5 & Annotations

Always use JUnit 5's `@ExtendWith` for Mockito integration and leverage annotations for mock initialization. This keeps your setup concise and automatic.

❌ **BAD: Manual setup or old JUnit 4 runner**
```java
// JUnit 4: @RunWith(MockitoJUnitRunner.class) - Obsolete
// Manual mock creation
UserRepository repo = mock(UserRepository.class);
UserService service = new UserService(repo);
```

✅ **GOOD: JUnit 5 `@ExtendWith` and annotations**
```java
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.InjectMocks;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
class UserServiceTest {
    @Mock
    UserRepository userRepository; // Collaborator

    @InjectMocks
    UserService userService; // System Under Test (SUT)

    // ... tests
}
```

## 2. One Test, One Behavior

Each test method must verify a single, distinct behavior. This makes tests easier to debug and provides clear documentation.

❌ **BAD: Multiple unrelated assertions in one test**
```java
@Test
void processOrder_createsUser_addsPoints_sendsEmail() {
    // ... setup
    orderService.placeOrder(orderRequest);
    verify(userRepository).save(any(User.class));
    verify(loyaltyService).addPoints(anyString(), anyInt());
    verify(notificationService).sendEmail(anyString(), anyString());
}
```

✅ **GOOD: Focused tests**
```java
@Test
void shouldSaveUserWhenOrderIsPlaced() {
    orderService.placeOrder(orderRequest);
    verify(userRepository).save(any(User.class));
}

@Test
void shouldAddLoyaltyPointsForEligibleUsers() {
    when(loyaltyPolicy.isEligible(any())).thenReturn(true);
    orderService.placeOrder(orderRequest);
    verify(loyaltyService).addPoints(anyString(), anyInt());
}
```

## 3. Verify Outcomes, Not Implementation Details

Only verify interactions that are part of the contract being tested. Avoid verifying internal method calls or private state.

❌ **BAD: Verifying internal helper method calls**
```java
// Assuming OrderService.placeOrder() internally calls calculateTax()
@Test
void shouldCalculateTaxWhenPlacingOrder() {
    orderService.placeOrder(orderRequest);
    verify(taxCalculator).calculateTax(any()); // Tax calculation is an internal detail
}
```

✅ **GOOD: Verifying the observable outcome**
```java
@Test
void shouldReturnOrderWithCorrectTotalIncludingTax() {
    when(taxCalculator.calculateTax(any())).thenReturn(BigDecimal.valueOf(10));
    Order result = orderService.placeOrder(orderRequest);
    assertEquals(BigDecimal.valueOf(110), result.getTotalAmount()); // Verify the final amount
}
```

## 4. Handle `UnnecessaryStubbingException` Correctly

Mockito's strict stubbing (default with `MockitoExtension`) catches unused stubs. This prevents dead code in tests. Resolve it by removing unused stubs. Use `lenient()` only when absolutely necessary (e.g., in parameterized tests where some stubs might not be hit in all cases).

❌ **BAD: Silencing all strictness with `@MockitoSettings(strictness = Strictness.LENIENT)`**
```java
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT) // Hides potential issues
class MyServiceTest {
    // ...
    @Test
    void someTest() {
        when(mockDependency.someMethod()).thenReturn("value"); // This stub is never used
        // ... test logic that doesn't call someMethod()
    }
}
```

✅ **GOOD: Remove unused stubs or use `lenient()` for specific stubs**
```java
@ExtendWith(MockitoExtension.class) // Strictness is default
class MyServiceTest {
    // ...
    @Test
    void someTest() {
        // No unused stubs here
        // If a stub is conditionally used, make it lenient:
        Mockito.lenient().when(mockDependency.optionalMethod()).thenReturn("optional");
        // ...
    }
}
```

## 5. Use `ArgumentCaptor` for Complex Argument Verification

When you need to inspect the exact values of objects passed to a mock, `ArgumentCaptor` is your tool.

❌ **BAD: Generic `any()` when specific content matters**
```java
verify(invoiceRepository).save(any(Invoice.class)); // Only checks type
```

✅ **GOOD: Capture and assert on the actual object's state**
```java
import org.mockito.ArgumentCaptor;
// ...
@Test
void shouldSaveInvoiceWithCorrectDetails() {
    // ... call SUT method
    ArgumentCaptor<Invoice> captor = ArgumentCaptor.forClass(Invoice.class);
    verify(invoiceRepository).save(captor.capture());
    Invoice savedInvoice = captor.getValue();
    assertEquals("ORD-123", savedInvoice.getOrderId());
    assertEquals(BigDecimal.valueOf(150.00), savedInvoice.getAmount());
}
```

## 6. Prefer Mocks over Spies

Use mocks for external, unmanaged dependencies where you control all behavior. Use spies only when you need partial real behavior of an object.

❌ **BAD: Spying on simple dependencies that should be fully mocked**
```java
@Spy
UserService userService = new UserService(userRepository); // Unnecessary complexity
```

✅ **GOOD: Mocking dependencies, using `@InjectMocks` for SUT**
```java
@Mock
UserRepository userRepository;

@InjectMocks
UserService userService; // SUT is a real instance, dependencies are mocked
```

## 7. Use Parameterized Tests for Similar Scenarios

Avoid duplicate test methods for different inputs. Parameterized tests keep your test suite DRY and maintainable.

❌ **BAD: Repetitive tests for different inputs**
```java
@Test void shouldReturnBronzeFor0Points() { /* ... */ }
@Test void shouldReturnSilverFor1000Points() { /* ... */ }
```

✅ **GOOD: Single parameterized test**
```java
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
// ...
class LoyaltyServiceTest {
    @InjectMocks
    LoyaltyService loyaltyService;

    @ParameterizedTest
    @CsvSource({
        "0, BRONZE",
        "1000, SILVER",
        "5000, GOLD"
    })
    void shouldReturnCorrectTierForPoints(int points, String expectedTier) {
        String actualTier = loyaltyService.calculateTier(points);
        assertEquals(expectedTier, actualTier);
    }
}
```

## 8. Mock Final Classes, Static Methods, and Constructors (with Caution)

Mockito 5 (and newer) supports mocking these without extra dependencies. Use this feature judiciously for testing legacy code or third-party APIs that were not designed for testability. Avoid it for your own code; design for testability instead.

```java
// Example (use sparingly for legacy/third-party code)
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.when;
import org.mockito.MockedStatic;

@Test
void shouldMockStaticMethod() {
    try (MockedStatic<MyStaticUtil> mockedStatic = mockStatic(MyStaticUtil.class)) {
        when(MyStaticUtil.getConstantValue()).thenReturn("MOCKED_VALUE");
        assertEquals("MOCKED_VALUE", MyStaticUtil.getConstantValue());
    }
}
```

© sanjeed5 · CC0-1.0 · sanjeed5/awesome-cursor-rules-mdc

Similar IDE rules

IDE rules catalog →

From the same set240

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