Install any skill in seconds. Free to start, no credit card required.
Get Started Free →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.
.claude/skills/giuseppe-trisciuoglio-unit-test-utility-methods/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-10 | ✗→✓ | ▲ Improved | 28% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 70% | 0% |
| case-01 | ✗→✓ | ▲ Improved | 4% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 13% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 62% | 0% |
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.
Use this skill when:
StringUtilsTest)shouldCapitalizeFirstLetter instead of test1@ParameterizedTest: For multiple similar inputs (see references/parameterized-tests.md)javaimport 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"); } }
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(); } }
javaclass 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(); } }
javaclass 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)); } }
javaclass 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"); } }
javaclass ValidatorUtilsTest { @Test void shouldValidateEmailFormat() { assertThat(ValidatorUtils.isValidEmail("user@example.com")).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(); } }
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)); } }
shouldReturnNullWhenInputIsNull@ParameterizedTest for multiple similar inputs (see references/parameterized-tests.md)isCloseTo(delta)references/edge-cases.md for boundary testing patterns| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-04 | fail→fail | 23,208 | 11,481 | -51% | 1 | 1 | 0% | 2,876 | 4,012 | +39% | 0 | 0 | — |
case-10 | fail→pass | 13,348 | 8,382 | -37% | 1 | 1 | 0% | 2,660 | 3,395 | +28% | 0 | 0 | — |
case-11 | fail→pass | 13,198 | 13,356 | +1% | 1 | 1 | 0% | 2,655 | 4,517 | +70% | 0 | 0 | — |
case-01 | fail→pass | 17,485 | 12,589 | -28% | 1 | 1 | 0% | 3,900 | 4,040 | +4% | 0 | 0 | — |
case-02 | fail→pass | 26,480 | 13,688 | -48% | 1 | 1 | 0% | 4,025 | 4,558 | +13% | 0 | 0 | — |
case-03 | fail→pass | 14,338 | 14,042 | -2% | 1 | 1 | 0% | 2,899 | 4,684 | +62% | 0 | 0 | — |
case-05 | pass→pass | 11,075 | 8,869 | -20% | 1 | 1 | 0% | 1,984 | 3,492 | +76% | 0 | 0 | — |
case-06 | pass→pass | 12,261 | 12,383 | +1% | 1 | 1 | 0% | 2,426 | 4,236 | +75% | 0 | 0 | — |
case-07 | pass→pass | 13,410 | 10,281 | -23% | 1 | 1 | 0% | 2,823 | 4,087 | +45% | 0 | 0 | — |
case-08 | pass→pass | 10,430 | 9,850 | -6% | 1 | 1 | 0% | 2,137 | 3,633 | +70% | 0 | 0 | — |
case-09 | fail→pass | 8,051 | 7,227 | -10% | 1 | 1 | 0% | 1,531 | 3,189 | +108% | 0 | 0 | — |
case-12 | fail→pass | 8,658 | 9,496 | +10% | 1 | 1 | 0% | 1,746 | 3,641 | +109% | 0 | 0 | — |
case-13 | pass→pass | 14,199 | 9,256 | -35% | 1 | 1 | 0% | 2,673 | 3,718 | +39% | 0 | 0 | — |
case-14 | fail→pass | 15,867 | 13,262 | -16% | 1 | 1 | 0% | 3,591 | 4,944 | +38% | 0 | 0 | — |
case-15 | pass→pass | 14,580 | 10,320 | -29% | 1 | 1 | 0% | 2,847 | 3,855 | +35% | 0 | 0 | — |
case-16 | fail→pass | 12,372 | 10,778 | -13% | 1 | 1 | 0% | 2,523 | 4,143 | +64% | 0 | 0 | — |
case-17 | pass→pass | 10,653 | 4,992 | -53% | 1 | 1 | 0% | 2,072 | 2,752 | +33% | 0 | 0 | — |
case-18 | fail→pass | 12,613 | 7,318 | -42% | 1 | 1 | 0% | 2,430 | 3,072 | +26% | 0 | 0 | — |
case-19 | fail→pass | 16,485 | 10,746 | -35% | 1 | 1 | 0% | 3,316 | 4,116 | +24% | 0 | 0 | — |
case-20 | fail→pass | 7,052 | 5,365 | -24% | 1 | 1 | 0% | 1,534 | 2,837 | +85% | 0 | 0 | — |
case-21 | fail→pass | 12,745 | 7,470 | -41% | 1 | 1 | 0% | 2,470 | 3,171 | +28% | 0 | 0 | — |
case-22 | fail→pass | 5,197 | 5,243 | +1% | 1 | 1 | 0% | 863 | 2,869 | +232% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +64 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.