unit-test-utility-methods — Claude Code skill: unit tests for utils
Writes unit tests for utility classes and static methods, covering nulls, empty input, boundaries and floating-point precision.
npx skills add giuseppe-trisciuoglio/developer-kit --skill unit-test-utility-methods -a claude-codeWhat unit-test-utility-methods does
The skill lays out a sequence for utility code: name the test class after the utility, cover the happy path, then edge cases — null, empty string, whitespace, a single element — and boundaries such as max values and precision. Test names read like shouldCapitalizeFirstLetter rather than test1. Assertions use AssertJ, and repeated inputs go through @ParameterizedTest.
Worked examples cover string helpers, math and percentage calculations, validators for email, URL and card numbers, and collection helpers. Pure functions need no mocks. The exception is a dependency like Clock, shown with MockitoExtension and @Mock.
The constraints are spelled out. Static methods are not mocked, and reflection is a last resort. Exact equality fails on floating point, so the skill calls for isCloseTo with a delta. Stateful utilities are harder to test, which is why the guidance leans on immutability.
What it helps with
- write tests for static methods on a utility class
- check how a helper behaves on null and empty input
- cover boundary values and numeric precision
- build a parameterized test over similar inputs
- test email, URL and card validators
Example prompts for the agent
- Write tests for
StringUtilscoveringcapitalizeandisEmpty - Cover
MathUtils.percentageandMathUtils.round, including division by zero - Create a
@ParameterizedTestforValidatorUtils.isValidEmailover a set of addresses
How to install unit-test-utility-methods
1Skills CLI (Vercel)
npx skills add giuseppe-trisciuoglio/developer-kit --skill unit-test-utility-methods -a claude-code2Manually: put the files in place
~/.claude/skills/unit-test-utility-methods/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/unit-test-utility-methods/
1Skills CLI (Vercel)
npx skills add giuseppe-trisciuoglio/developer-kit --skill unit-test-utility-methods -a codex2Manually: put the files in place
.agents/skills/unit-test-utility-methods/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add giuseppe-trisciuoglio/developer-kit --skill unit-test-utility-methods -a cursor2Manually: put the files in place
.cursor/skills/unit-test-utility-methods/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install giuseppe-trisciuoglio/developer-kit unit-test-utility-methods2Manually: put the files in place
.github/skills/unit-test-utility-methods/SKILL.md1Skills CLI (Vercel)
npx skills add giuseppe-trisciuoglio/developer-kit --skill unit-test-utility-methods -a gemini-cli2Platform CLI
gemini skills install https://github.com/giuseppe-trisciuoglio/developer-kit --path plugins/developer-kit-java/skills/unit-test-utility-methodsManually: put the files in place
.devin/skills/unit-test-utility-methods/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add giuseppe-trisciuoglio/developer-kit --skill unit-test-utility-methods -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about unit-test-utility-methods
How do I install unit-test-utility-methods in Claude?
Run npx skills add giuseppe-trisciuoglio/developer-kit --skill unit-test-utility-methods -a claude-code. The skill lands in ~/.claude/skills/unit-test-utility-methods/SKILL.md.
What does unit-test-utility-methods do?
It generates unit tests for utility classes, static methods and pure functions, checking nulls, empty values, boundaries and precision with AssertJ and @ParameterizedTest.
Do utility tests need mocks?
Not for pure functions. A mock is only needed for an external dependency such as Clock, shown with MockitoExtension and @Mock.
Source text
SKILL.md · MIT
---
name: unit-test-utility-methods
description: Provides patterns for testing utility classes, static methods, and helper functions. Validates pure functions, null handling, edge cases, and boundary conditions. Generates AssertJ assertions and @ParameterizedTest for string utils, math utils, validators, and collection helpers. Use when testing utils, test helpers, helper functions, static methods, or verifying utility code correctness.
allowed-tools: Read, Write, Bash, Glob, Grep
---
# Unit Testing Utility Classes and Static Methods
## Overview
This skill generates tests for utility classes with static helper methods and pure functions. It provides patterns for testing null handling, edge cases, boundary conditions, and common utilities like string manipulation, calculations, data validation, and collections. Pure functions require no mocking.
## When to Use
Use this skill when:
- Writing tests for utility/helper classes with static methods
- Testing pure functions with no state or side effects
- Testing string manipulation, formatting, or transformation utilities
- Testing calculation, conversion, or math helper functions
- Testing data validation and formatter utilities
- Verifying null/empty input handling in utility code
- Testing collections or array helper methods
## Instructions
1. **Create test class**: Name it after the utility (e.g., `StringUtilsTest`)
2. **Test happy path**: Valid inputs with expected outputs
3. **Test edge cases**: null, empty, whitespace, single elements
4. **Test boundary conditions**: max/min values, large numbers, precision
5. **Use descriptive names**: `shouldCapitalizeFirstLetter` instead of `test1`
6. **Use AssertJ**: For readable, chainable assertions
7. **Use `@ParameterizedTest`**: For multiple similar inputs (see `references/parameterized-tests.md`)
8. **Avoid mocking**: Pure utilities need no mocks
## Examples
### Basic Static Utility Test
```java
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.*;
class StringUtilsTest {
@Test
void shouldCapitalizeFirstLetter() {
assertThat(StringUtils.capitalize("hello")).isEqualTo("Hello");
}
@Test
void shouldReturnNullForNullInput() {
assertThat(StringUtils.capitalize(null)).isNull();
}
@Test
void shouldHandleEmptyString() {
assertThat(StringUtils.capitalize("")).isEmpty();
}
@Test
void shouldHandleSingleCharacter() {
assertThat(StringUtils.capitalize("a")).isEqualTo("A");
}
}
```
### Comprehensive Example: isEmpty Implementation
```java
// Input: public static boolean isEmpty(String str)
// { return str == null || str.trim().isEmpty(); }
class StringUtilsTest {
@Test
void shouldReturnTrueForNullString() {
assertThat(StringUtils.isEmpty(null)).isTrue();
}
@Test
void shouldReturnTrueForEmptyString() {
assertThat(StringUtils.isEmpty("")).isTrue();
}
@Test
void shouldReturnTrueForWhitespaceOnly() {
assertThat(StringUtils.isEmpty(" ")).isTrue();
}
@Test
void shouldReturnFalseForNonEmptyString() {
assertThat(StringUtils.isEmpty("hello")).isFalse();
}
}
```
### Null-Safe Utility
```java
class NullSafeUtilsTest {
@Test
void shouldReturnDefaultWhenNull() {
assertThat(NullSafeUtils.getOrDefault(null, "default")).isEqualTo("default");
}
@Test
void shouldReturnValueWhenNotNull() {
assertThat(NullSafeUtils.getOrDefault("value", "default")).isEqualTo("value");
}
@Test
void shouldReturnFalseWhenBlank() {
assertThat(NullSafeUtils.isNotBlank(null)).isFalse();
assertThat(NullSafeUtils.isNotBlank(" ")).isFalse();
}
}
```
### Math/Calculation Utility
```java
class MathUtilsTest {
@Test
void shouldCalculatePercentage() {
assertThat(MathUtils.percentage(25, 100)).isEqualTo(25.0);
}
@Test
void shouldHandleZeroDivisor() {
assertThat(MathUtils.percentage(50, 0)).isZero();
}
@Test
void shouldRoundToDecimalPlaces() {
assertThat(MathUtils.round(3.14159, 2)).isEqualTo(3.14);
}
@Test
void shouldHandleFloatingPointWithTolerance() {
assertThat(MathUtils.multiply(0.1, 0.2))
.isCloseTo(0.02, within(0.0001));
}
}
```
### Collection Utility
```java
class CollectionUtilsTest {
@Test
void shouldFilterList() {
List<Integer> result = CollectionUtils.filter(List.of(1, 2, 3, 4), n -> n % 2 == 0);
assertThat(result).containsExactly(2, 4);
}
@Test
void shouldHandleNullList() {
assertThat(CollectionUtils.filter(null, n -> true)).isEmpty();
}
@Test
void shouldJoinWithSeparator() {
assertThat(CollectionUtils.join(List.of("a", "b", "c"), "-")).isEqualTo("a-b-c");
}
@Test
void shouldDeduplicateList() {
assertThat(CollectionUtils.deduplicate(List.of("a", "b", "a")))
.containsExactlyInAnyOrder("a", "b");
}
}
```
### Data Validation Utility
```java
class ValidatorUtilsTest {
@Test
void shouldValidateEmailFormat() {
assertThat(ValidatorUtils.isValidEmail("[email protected]")).isTrue();
assertThat(ValidatorUtils.isValidEmail("invalid")).isFalse();
}
@Test
void shouldValidateUrlFormat() {
assertThat(ValidatorUtils.isValidUrl("https://example.com")).isTrue();
assertThat(ValidatorUtils.isValidUrl("not a url")).isFalse();
}
@Test
void shouldValidateCreditCard() {
assertThat(ValidatorUtils.isValidCreditCard("4532015112830366")).isTrue();
assertThat(ValidatorUtils.isValidCreditCard("1234567890123456")).isFalse();
}
}
```
### Utility with Clock Dependency (Rare)
```java
@ExtendWith(MockitoExtension.class)
class DateUtilsTest {
@Mock
private Clock clock;
@Test
void shouldGetDateFromClock() {
when(clock.instant()).thenReturn(Instant.parse("2024-01-15T10:00:00Z"));
assertThat(DateUtils.today(clock)).isEqualTo(LocalDate.of(2024, 1, 15));
}
}
```
## Best Practices
- **Test pure functions exclusively** - no side effects or state dependency
- **Cover happy path and edge cases** - null, empty, whitespace, extreme values
- **Use descriptive test names** - `shouldReturnNullWhenInputIsNull`
- **Use `@ParameterizedTest`** for multiple similar inputs (see `references/parameterized-tests.md`)
- **Test boundary conditions** - min/max values, overflow, precision
- **Avoid mocking pure functions** - only mock external dependencies like Clock
- **Keep tests independent** - no order dependency between tests
## Constraints and Warnings
- **No mocking static methods**: Use reflection utilities only when absolutely necessary
- **Pure function requirement**: Stateful utilities are harder to test; prefer immutability
- **Floating point precision**: Never use exact equality; use `isCloseTo(delta)`
- **Null handling consistency**: Decide whether utility returns null or throws; test accordingly
- **Thread safety**: Static utilities must be thread-safe; verify concurrent behavior separately
- **Immutable inputs**: Document whether utilities modify input parameters
- **Edge cases reference**: See `references/edge-cases.md` for boundary testing patterns
© giuseppe-trisciuoglio · MIT · giuseppe-trisciuoglio/developer-kit