Claude
Skills
Sign in
Back

java-test-generator

Included with Lifetime
$97 forever

Generate comprehensive JUnit 5 test cases for Java code with proper mocking and coverage. Use when writing tests, creating unit tests, generating test cases, adding JUnit tests, setting up Mockito mocks, writing parameterized tests, or achieving test coverage. Works with .java files, generates test classes following naming conventions, includes edge cases, boundary conditions, and uses Arrange-Act-Assert pattern.

Backend & APIs

What this skill does


# Java Test Generator

## Table of Contents

- [Purpose](#purpose)
- [When to Use](#when-to-use)
- [Quick Start](#quick-start)
- [Instructions](#instructions)
- [Examples](#examples)
- [Requirements](#requirements)
- [Testing Best Practices](#testing-best-practices)
- [Output Format](#output-format)
- [Error Handling](#error-handling)

## Purpose

Generates comprehensive, well-structured JUnit 5 test cases for Java code with proper mocking using Mockito, edge case coverage, parameterized tests, and adherence to testing best practices.

## When to Use

Use this skill when you need to:
- Generate JUnit 5 test cases for Java classes
- Create unit tests with Mockito mocking
- Write parameterized tests for multiple input scenarios
- Add test coverage for new or existing code
- Test service layers with dependency mocking
- Generate tests following Arrange-Act-Assert pattern
- Create tests for edge cases and boundary conditions
- Test exception handling scenarios
- Verify mock interactions with Mockito
- Generate tests for Spring Boot components
- Achieve high test coverage (>80%)
- Bootstrap test suites for new features

## Quick Start
Generate tests for any Java class instantly:

```bash
# Generate tests for a service class
Generate tests for UserService.java

# Generate tests for multiple classes
Generate tests for all classes in src/main/java/com/example/service/
```

## Instructions

### Step 1: Analyze Source Code
Read the target Java class and understand:
- Class purpose and responsibilities
- Public methods that need testing
- Dependencies (fields, constructor parameters)
- Return types and exception handling
- Business logic and edge cases
- Validation logic

Use Grep to find related classes if context is needed:
```bash
grep "class UserService" src/main/java/**/*.java
```

### Step 2: Identify Test Scenarios
For each public method, identify:

**Happy Path Tests:**
- Valid inputs producing expected outputs
- Typical use cases

**Edge Cases:**
- Boundary values (min, max, zero, empty)
- Null inputs (if not using @NonNull)
- Empty collections
- Special characters in strings

**Error Cases:**
- Invalid inputs
- Constraint violations
- Exception scenarios

**State-Based Tests:**
- Different object states
- Conditional branch coverage

**Integration Points:**
- Dependency interactions
- Method call verification

### Step 3: Generate Test Class Structure
Create test class following conventions:

**Naming:** [ClassName]Test.java (e.g., UserServiceTest.java)
**Location:** Mirror source structure in src/test/java/

**Structure Template:**
```java
@ExtendWith(MockitoExtension.class)
class ClassNameTest {
    // Mocks for dependencies
    @Mock
    private DependencyClass mockDependency;

    // System under test
    @InjectMocks
    private ClassUnderTest classUnderTest;

    // Test data builders
    private TestDataBuilder testDataBuilder;

    @BeforeEach
    void setUp() {
        // Common test setup
    }

    @Nested
    @DisplayName("methodName() tests")
    class MethodNameTests {
        // Group related tests
    }
}
```

### Step 4: Write Individual Test Methods
Follow the Arrange-Act-Assert (AAA) pattern:

```java
@Test
@DisplayName("should return user when valid ID provided")
void shouldReturnUser_WhenValidIdProvided() {
    // Arrange
    String userId = "123";
    User expectedUser = new User(userId, "John Doe");
    when(mockRepository.findById(userId)).thenReturn(Optional.of(expectedUser));

    // Act
    Optional<User> result = userService.getUser(userId);

    // Assert
    assertThat(result).isPresent();
    assertThat(result.get()).isEqualTo(expectedUser);
    verify(mockRepository).findById(userId);
}
```

**Test Method Naming Conventions:**
- `shouldDoSomething_WhenCondition()` format
- Or `should_DoSomething_When_Condition()` for readability
- Descriptive names that explain the scenario

### Step 5: Add Parameterized Tests for Multiple Inputs
Use `@ParameterizedTest` for testing multiple similar scenarios:

```java
@ParameterizedTest
@ValueSource(strings = {"", "  ", "\t", "\n"})
@DisplayName("should throw exception for blank names")
void shouldThrowException_ForBlankNames(String invalidName) {
    assertThrows(IllegalArgumentException.class,
        () -> userService.createUser(invalidName));
}

@ParameterizedTest
@CsvSource({
    "[email protected], true",
    "invalid-email, false",
    "@example.com, false",
    "john@, false"
})
@DisplayName("should validate email correctly")
void shouldValidateEmail_Correctly(String email, boolean expected) {
    boolean result = validator.isValidEmail(email);
    assertThat(result).isEqualTo(expected);
}
```

### Step 6: Add Exception Testing
Test exception scenarios explicitly:

```java
@Test
@DisplayName("should throw UserNotFoundException when user not found")
void shouldThrowUserNotFoundException_WhenUserNotFound() {
    // Arrange
    String userId = "999";
    when(mockRepository.findById(userId)).thenReturn(Optional.empty());

    // Act & Assert
    assertThrows(UserNotFoundException.class,
        () -> userService.getUser(userId));
    verify(mockRepository).findById(userId);
}
```

### Step 7: Add Verification for Mock Interactions
Verify dependencies are called correctly:

```java
@Test
@DisplayName("should save user to repository")
void shouldSaveUser_ToRepository() {
    // Arrange
    User newUser = new User("John Doe", "[email protected]");

    // Act
    userService.createUser(newUser);

    // Assert
    verify(mockRepository).save(newUser);
    verifyNoMoreInteractions(mockRepository);
}
```

### Step 8: Generate Test Data Builders (Optional)
For complex objects, create builder methods:

```java
private User createTestUser(String id, String name) {
    return User.builder()
        .id(id)
        .name(name)
        .email(name.toLowerCase() + "@example.com")
        .createdAt(LocalDateTime.now())
        .build();
}
```

### Step 9: Add Coverage for Edge Cases
Include boundary and special cases:

```java
@Nested
@DisplayName("Edge case tests")
class EdgeCaseTests {
    @Test
    @DisplayName("should handle empty list")
    void shouldHandleEmptyList() {
        List<User> emptyList = Collections.emptyList();
        List<String> result = userService.extractNames(emptyList);
        assertThat(result).isEmpty();
    }

    @Test
    @DisplayName("should handle null optional")
    void shouldHandleNullOptional() {
        when(mockRepository.findById(anyString())).thenReturn(Optional.empty());
        Optional<User> result = userService.getUser("123");
        assertThat(result).isEmpty();
    }
}
```

## Examples

### Example 1: Generate Tests for Simple Service

**Source Code:**
```java
@Service
@RequiredArgsConstructor
public class UserService {
    private final UserRepository userRepository;

    public Optional<User> getUser(String id) {
        return userRepository.findById(id);
    }

    public User createUser(String name, String email) {
        if (name == null || name.isBlank()) {
            throw new IllegalArgumentException("Name cannot be blank");
        }
        User user = new User(name, email);
        return userRepository.save(user);
    }
}
```

**Generated Test:**
```java
@ExtendWith(MockitoExtension.class)
@DisplayName("UserService Tests")
class UserServiceTest {

    @Mock
    private UserRepository mockRepository;

    @InjectMocks
    private UserService userService;

    @Nested
    @DisplayName("getUser() tests")
    class GetUserTests {

        @Test
        @DisplayName("should return user when ID exists")
        void shouldReturnUser_WhenIdExists() {
            // Arrange
            String userId = "123";
            User expectedUser = new User("John Doe", "[email protected]");
            when(mockRepository.findById(userId))
                .thenReturn(Optional.of(expectedUser));

            // Act
            Optional<User> result = userService.getUser(userId);

            // Assert
            assertThat(result).isPresent();
 

Related in Backend & APIs