
Unit Test Boundary Conditions
- 2.1k installs
- 318 repo stars
- Updated June 22, 2026
- giuseppe-trisciuoglio/developer-kit
unit-test-boundary-conditions is an agent skill that Provides edge case, corner case, boundary condition, and limit testing patterns for Java unit tests. Validates minimum/maximum values, null cases, empty collections, n
About
The unit-test-boundary-conditions 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 when writing .java test files to ensure code handles limits, corner cases, and special inputs correctly. Covers numeric boundaries, string edge cases, collection states, floating-point precision, date/time limits, and off-by-one scenarios. **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 with or 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 with AssertJ 6.
- Numeric min/max limits, null/empty/whitespace inputs
- Overflow/underflow validation, collection boundaries
- Off-by-one errors, floating-point precision
- Identify boundaries: List numeric limits (MIN_VALUE, MAX_VALUE, zero), string states (null, empty, whitespace), collecti
- Apply parameterized tests: Use `@ParameterizedTest` with `@ValueSource` or `@CsvSource` for multiple boundary values
Unit Test Boundary Conditions by the numbers
- 2,070 all-time installs (skills.sh)
- +125 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #381 of 2,153 Testing & QA skills by installs in the Skillselion catalog
- Security screen: MEDIUM risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
unit-test-boundary-conditions capabilities & compatibility
- Capabilities
- numeric min/max limits, null/empty/whitespace in · overflow/underflow validation, collection bounda · off by one errors, floating point precision · identify boundaries: list numeric limits (min_va · apply parameterized tests: use `@parameterizedte
- Use cases
- testing · debugging · ci cd
What unit-test-boundary-conditions says it does
Covers numeric boundaries, string edge cases, collection states, floating-point precision, date/time limits, and off-by-one scenarios.
**Identify boundaries**: List numeric limits (MIN_VALUE, MAX_VALUE, zero), string states (null, empty, whitespace), collection sizes (0, 1, many) 2.
npx skills add https://github.com/giuseppe-trisciuoglio/developer-kit --skill unit-test-boundary-conditionsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2.1k |
|---|---|
| repo stars | ★ 318 |
| Security audit | 3 / 3 scanners passed |
| Last updated | June 22, 2026 |
| Repository | giuseppe-trisciuoglio/developer-kit ↗ |
How do I apply unit-test-boundary-conditions correctly using the SKILL.md workflows and reference files?
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, floati
Who is it for?
Developers and software engineers working with unit-test-boundary-conditions patterns from the skill documentation.
Skip if: Skip when cached docs are empty, boilerplate-only, or outside the skill documented scope.
When should I use 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,
What you get
Grounded unit-test-boundary-conditions guidance with highlights, triggers, and evidence quotes from SKILL.md.
- JUnit boundary test methods
- Concurrency edge-case test templates
Files
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;
assertThat(min).isBefore(max);
assertThat(DateUtils.isValid(min)).isTrue();
assertThat(DateUtils.isValid(max)).isTrue();
}
@Test
void shouldHandleLeapYearBoundary() {
LocalDate leapYearEnd = LocalDate.of(2024, 2, 29);
assertThat(leapYearEnd).isNotNull();
}
@Test
void shouldRejectInvalidDateInNonLeapYear() {
assertThatThrownBy(() -> LocalDate.of(2023, 2, 29))
.isInstanceOf(DateTimeException.class);
}
}Array Index Boundary Testing
class ArrayBoundaryTest {
@Test
void shouldHandleFirstElementAccess() {
int[] array = {1, 2, 3, 4, 5};
assertThat(array[0]).isEqualTo(1);
}
@Test
void shouldHandleLastElementAccess() {
int[] array = {1, 2, 3, 4, 5};
assertThat(array[array.length - 1]).isEqualTo(5);
}
@Test
void shouldThrowOnNegativeIndex() {
int[] array = {1, 2, 3};
assertThatThrownBy(() -> array[-1])
.isInstanceOf(ArrayIndexOutOfBoundsException.class);
}
@Test
void shouldThrowOnOutOfBoundsIndex() {
int[] array = {1, 2, 3};
assertThatThrownBy(() -> array[10])
.isInstanceOf(ArrayIndexOutOfBoundsException.class);
}
@Test
void shouldHandleEmptyArray() {
int[] empty = {};
assertThat(empty.length).isZero();
assertThatThrownBy(() -> empty[0])
.isInstanceOf(ArrayIndexOutOfBoundsException.class);
}
}Best Practices
- Test at boundaries explicitly: don't rely on random testing
- Test null and empty separately from valid inputs
- Use parameterized tests for multiple boundary cases
- Test both sides of boundaries (just below, at, just above)
- Verify error messages for invalid boundary inputs
- Document why specific boundaries matter for your domain
- Test overflow/underflow for all numeric operations
Constraints and Warnings
- Integer overflow: Use
Math.addExact()to detect silent overflow - Floating-point precision: Never use exact equality; always use tolerance-based assertions
- NaN behavior:
NaN != NaN; useFloat.isNaN()orDouble.isNaN() - Collection size limits: Be mindful of memory with large test collections
- String encoding: Test with Unicode characters for internationalization
- Date/time boundaries: Account for timezone transitions and daylight saving
- Array indexing: Always test index 0, length-1, and out-of-bounds
References
- Integer.MIN_VALUE/MAX_VALUE
- Double.MIN_VALUE/MAX_VALUE
- AssertJ Floating Point
- Boundary Value Analysis
- references/concurrent-testing.md - Thread safety patterns
- references/parameterized-patterns.md - Off-by-one and parameterized examples
Concurrent Boundary Testing Reference
Null and Race Conditions
import java.util.concurrent.*;
class ConcurrentBoundaryTest {
@Test
void shouldHandleNullInConcurrentMap() {
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
map.put("key", "value");
assertThat(map.get("nonexistent")).isNull();
}
@Test
void shouldHandleConcurrentModification() {
List<Integer> list = new CopyOnWriteArrayList<>(List.of(1, 2, 3, 4, 5));
for (int num : list) {
if (num == 3) {
list.add(6);
}
}
assertThat(list).hasSize(6);
}
@Test
void shouldHandleEmptyBlockingQueue() throws InterruptedException {
BlockingQueue<String> queue = new LinkedBlockingQueue<>();
assertThat(queue.poll()).isNull();
}
}Thread Safety Patterns
class ThreadSafetyBoundaryTest {
@Test
void shouldHandleAtomicOperations() {
AtomicInteger counter = new AtomicInteger(0);
counter.incrementAndGet();
counter.addAndGet(Integer.MAX_VALUE);
assertThat(counter.get()).isGreaterThan(0);
}
@Test
void shouldHandleSynchronizedBlocks() {
Object lock = new Object();
int[] count = {0};
synchronized (lock) {
count[0]++;
}
assertThat(count[0]).isEqualTo(1);
}
}Parameterized Boundary Testing Reference
Multiple Boundary Cases
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
class ParameterizedBoundaryTest {
@ParameterizedTest
@CsvSource({
"null, false",
"'', false",
"' ', false",
"a, true",
"abc, true"
})
void shouldValidateStringBoundaries(String input, boolean expected) {
boolean result = StringValidator.isValid(input);
assertThat(result).isEqualTo(expected);
}
@ParameterizedTest
@ValueSource(ints = {Integer.MIN_VALUE, 0, 1, -1, Integer.MAX_VALUE})
void shouldHandleNumericBoundaries(int value) {
assertThat(value).isNotNull();
}
static Stream<Arguments> edgeCaseProvider() {
return Stream.of(
Arguments.of(Integer.MIN_VALUE, "min"),
Arguments.of(-1, "negative"),
Arguments.of(0, "zero"),
Arguments.of(1, "positive"),
Arguments.of(Integer.MAX_VALUE, "max")
);
}
@ParameterizedTest
@MethodSource("edgeCaseProvider")
void shouldTestAllEdgeCases(int value, String description) {
assertThat(value).isNotNull();
}
}Off-By-One Testing
class OffByOneBoundaryTest {
@ParameterizedTest
@CsvSource({
"-1, false",
"0, true",
"1, true",
"99, true",
"100, false",
"101, false"
})
void shouldValidateRangeBoundaries(int value, boolean expected) {
boolean inRange = value >= 0 && value <= 100;
assertThat(inRange).isEqualTo(expected);
}
@Test
void shouldHandleArrayIndexOffByOne() {
int[] array = {1, 2, 3};
assertThat(array.length).isEqualTo(3);
assertThat(array[0]).isEqualTo(1);
assertThat(array[array.length - 1]).isEqualTo(3);
}
}Related skills
Forks & variants (1)
Unit Test Boundary Conditions has 1 known copy in the catalog totaling 25 installs. They canonicalize to this original listing.
- giuseppe-trisciuoglio - 25 installs
How it compares
Use unit-test-boundary-conditions for Java concurrency edge-case snippets rather than general TDD planning or frontend component testing skills.
FAQ
Who is unit-test-boundary-conditions for?
Developers and software engineers working with unit-test-boundary-conditions patterns from the skill documentation.
When should I use 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 when
Is unit-test-boundary-conditions safe to install?
Review the Security Audits panel on this page before installing in production.