Skip to content
Development
Skill

/unit-test-boundary-conditions

Provides edge case, corner case, boundary condition, and limit testing patterns for Java unit tests. Validates minimum/maximum values, null cases, empty collections, numeric overflow/underflow, floating-point precision, and off-by-one scenarios using JUnit 5 and AssertJ. Use

From plugin
developer-kit
345116 skills44 agents35 commands2 MCP
Install
$ npx -y skills add giuseppe-trisciuoglio/developer-kit --skill unit-test-boundary-conditions --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/unit-test-boundary-conditions

Context preview

The summary Claude sees to decide when to auto-load this skill.

Provides edge case, corner case, boundary condition, and limit testing patterns for Java unit tests. Validates minimum/maximum values, null cases, empty collections, numeric overflow/underflow, floating-point precision, and off-by-one scenarios using JUnit 5 and AssertJ. Use

SKILL.md

unit-test-boundary-conditions.SKILL.md
name: unit-test-boundary-conditions
description: Provides edge case, corner case, boundary condition, and limit testing patterns for Java unit tests. Validates minimum/maximum values, null cases, empty collections, numeric overflow/underflow, floating-point precision, and off-by-one scenarios using JUnit 5 and AssertJ. Use when writing .java test files to ensure code handles limits, corner cases, and special inputs correctly.
allowed-tools: Read, Write, Bash, Glob, Grep

Unit Testing Boundary Conditions and Edge Cases

Overview

Systematic patterns for testing boundary conditions, corner cases, and limit values in Java using JUnit 5. Covers numeric boundaries, string edge cases, collection states, floating-point precision, date/time limits, and off-by-one scenarios.

When to Use

  • Numeric min/max limits, null/empty/whitespace inputs
  • Overflow/underflow validation, collection boundaries
  • Off-by-one errors, floating-point precision

Instructions

1. **Identify boundaries**: List numeric limits (MIN_VALUE, MAX_VALUE, zero), string states (null, empty, whitespace), collection sizes (0, 1, many) 2. **Apply parameterized tests**: Use `@ParameterizedTest` with `@ValueSource` or `@CsvSource` for multiple boundary values 3. **Test both sides of boundaries**: Cover values just below, at, and just above each boundary 4. **Run tests after adding each boundary category** to catch issues early 5. **Verify floating-point precision**: Use `isCloseTo(expected, within(tolerance))` with AssertJ 6. **Test collection states**: Explicitly test empty (0), single (1), and many (>1) element scenarios 7. **Handle overflow/underflow**: Use `Math.addExact()` and `Math.subtractExact()` to detect arithmetic overflow 8. **Test date/time edges**: Verify leap years, month boundaries, timezone transitions 9. **Iterate based on failures**: When a boundary test fails, analyze the error to discover additional untested boundaries; add test cases for the newly discovered edge conditions

Examples

Requires: `junit-jupiter`, `junit-jupiter-params`, `assertj-core`.

Integer Boundary Testing

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import static org.assertj.core.api.Assertions.*;

class IntegerBoundaryTest {

  @ParameterizedTest
  @ValueSource(ints = {Integer.MIN_VALUE, Integer.MIN_VALUE + 1, 0, Integer.MAX_VALUE - 1, Integer.MAX_VALUE})
  void shouldHandleIntegerBoundaries(int value) {
    assertThat(value).isNotNull();
  }

  @Test
  void shouldDetectIntegerOverflow() {
    assertThatThrownBy(() -> Math.addExact(Integer.MAX_VALUE, 1))
      .isInstanceOf(ArithmeticException.class);
  }

  @Test
  void shouldDetectIntegerUnderflow() {
    assertThatThrownBy(() -> Math.subtractExact(Integer.MIN_VALUE, 1))
      .isInstanceOf(ArithmeticException.class);
  }

  @Test
  void shouldHandleZeroEdge() {
    int result = MathUtils.divide(0, 5);
    assertThat(result).isZero();

    assertThatThrownBy(() -> MathUtils.divide(5, 0))
      .isInstanceOf(ArithmeticException.class);
  }
}

String Boundary Testing

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

class StringBoundaryTest {

  @ParameterizedTest
  @ValueSource(strings = {"", " ", "  ", "\t", "\n"})
  void shouldRejectEmptyAndWhitespace(String input) {
    boolean result = StringUtils.isNotBlank(input);
    assertThat(result).isFalse();
  }

  @Test
  void shouldHandleNullString() {
    String result = StringUtils.trim(null);
    assertThat(result).isNull();
  }

  @Test
  void shouldHandleSingleCharacter() {
    assertThat(StringUtils.capitalize("a")).isEqualTo("A");
    assertThat(StringUtils.trim("x")).isEqualTo("x");
  }

  @Test
  void shouldHandleVeryLongString() {
    String longString = "x".repeat(1000000);

    assertThat(longString.length()).isEqualTo(1000000);
    assertThat(StringUtils.isNotBlank(longString)).isTrue();
  }
}

Collection Boundary Testing

class CollectionBoundaryTest {

  @Test
  void shouldHandleEmptyList() {
    List<String> empty = List.of();

    assertThat(empty).isEmpty();
    assertThat(CollectionUtils.first(empty)).isNull();
    assertThat(CollectionUtils.count(empty)).isZero();
  }

  @Test
  void shouldHandleSingleElementList() {
    List<String> single = List.of("only");

    assertThat(single).hasSize(1);
    assertThat(CollectionUtils.first(single)).isEqualTo("only");
    assertThat(CollectionUtils.last(single)).isEqualTo("only");
  }

  @Test
  void shouldHandleLargeList() {
    List<Integer> large = new ArrayList<>();
    for (int i = 0; i < 100000; i++) {
      large.add(i);
    }

    assertThat(large).hasSize(100000);
    assertThat(CollectionUtils.first(large)).isZero();
    assertThat(CollectionUtils.last(large)).isEqualTo(99999);
  }

  @Test
  void shouldHandleNullInCollection() {
    List<String> withNull = new ArrayList<>(List.of("a", null, "c"));

    assertThat(withNull).contains(null);
    assertThat(CollectionUtils.filterNonNull(withNull)).hasSize(2);
  }
}

Floating-Point Boundary Testing

class FloatingPointBoundaryTest {

  @Test
  void shouldHandleFloatingPointPrecision() {
    double result = 0.1 + 0.2;
    assertThat(result).isCloseTo(0.3, within(0.0001));
  }

  @Test
  void shouldHandleSpecialFloatingPointValues() {
    assertThat(Double.POSITIVE_INFINITY).isGreaterThan(Double.MAX_VALUE);
    assertThat(Double.NEGATIVE_INFINITY).isLessThan(Double.MIN_VALUE);
    assertThat(Double.NaN).isNotEqualTo(Double.NaN);
  }

  @Test
  void shouldHandleZeroInDivision() {
    assertThat(1.0 / 0.0).isEqualTo(Double.POSITIVE_INFINITY);
    assertThat(-1.0 / 0.0).isEqualTo(Double.NEGATIVE_INFINITY);
    assertThat(0.0 / 0.0).isNaN();
  }
}

Date/Time Boundary Testing

class DateTimeBoundaryTest {

  @Test
  void shouldHandleMinAndMaxDates() {
    LocalDate min = LocalDate.MIN;
    LocalDate max = LocalDate.MAX;
Read more
Ships withdeveloper-kit

Modular plugin marketplace for Claude Code and agentic CLIs, with validated, spec-driven skills, agents, commands, and workflows for Java, TypeScript, Python, PHP, AWS, and AI.

Get the whole plugin

Other skills on developer-kit.