← Назад к вопросам
Какие будешь писать юнит-тесты при реализации интерфейса List
1.7 Middle🔥 111 комментариев
#Коллекции#Тестирование
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Какие будешь писать юнит-тесты при реализации интерфейса List
При реализации интерфейса List нужно покрыть все основные операции и edge case'ы.
Полный набор unit-тестов
@DisplayName("CustomList Tests")
class CustomListTest {
private CustomList<Integer> list;
@BeforeEach
void setUp() {
list = new CustomList<>();
}
// ===== TESTS FOR add() =====
@Test
@DisplayName("add() should add element to empty list")
void testAddToEmptyList() {
boolean result = list.add(1);
assertTrue(result);
assertEquals(1, list.size());
assertEquals(1, list.get(0));
}
@Test
@DisplayName("add() should add multiple elements")
void testAddMultipleElements() {
list.add(1);
list.add(2);
list.add(3);
assertEquals(3, list.size());
assertEquals(1, list.get(0));
assertEquals(2, list.get(1));
assertEquals(3, list.get(2));
}
@Test
@DisplayName("add() should handle resize when capacity exceeded")
void testAddWithResize() {
// Добавляем 15 элементов (дефолт capacity 10)
for (int i = 0; i < 15; i++) {
list.add(i);
}
assertEquals(15, list.size());
assertEquals(14, list.get(14));
}
@Test
@DisplayName("add() should accept null")
void testAddNull() {
boolean result = list.add(null);
assertTrue(result);
assertEquals(1, list.size());
assertNull(list.get(0));
}
@Test
@DisplayName("add() should allow duplicates")
void testAddDuplicates() {
list.add(1);
list.add(1);
list.add(1);
assertEquals(3, list.size());
}
// ===== TESTS FOR get() =====
@Test
@DisplayName("get() should return element at index")
void testGetElementAtIndex() {
list.add(10);
list.add(20);
list.add(30);
assertEquals(20, list.get(1));
}
@Test
@DisplayName("get() should throw IndexOutOfBoundsException for negative index")
void testGetNegativeIndex() {
list.add(1);
assertThrows(IndexOutOfBoundsException.class, () -> list.get(-1));
}
@Test
@DisplayName("get() should throw IndexOutOfBoundsException for index >= size")
void testGetIndexOutOfBounds() {
list.add(1);
assertThrows(IndexOutOfBoundsException.class, () -> list.get(1));
}
// ===== TESTS FOR remove() =====
@Test
@DisplayName("remove(Object) should remove element by value")
void testRemoveByValue() {
list.add(1);
list.add(2);
list.add(3);
boolean result = list.remove(Integer.valueOf(2));
assertTrue(result);
assertEquals(2, list.size());
assertEquals(1, list.get(0));
assertEquals(3, list.get(1));
}
@Test
@DisplayName("remove(Object) should return false if element not found")
void testRemoveNotFound() {
list.add(1);
list.add(2);
boolean result = list.remove(Integer.valueOf(999));
assertFalse(result);
assertEquals(2, list.size());
}
@Test
@DisplayName("remove(Object) should handle null")
void testRemoveNull() {
list.add(1);
list.add(null);
list.add(3);
boolean result = list.remove(null);
assertTrue(result);
assertEquals(2, list.size());
assertEquals(1, list.get(0));
assertEquals(3, list.get(1));
}
@Test
@DisplayName("remove(int) should remove element by index")
void testRemoveByIndex() {
list.add(10);
list.add(20);
list.add(30);
Integer removed = list.remove(1);
assertEquals(20, removed);
assertEquals(2, list.size());
assertEquals(30, list.get(1));
}
@Test
@DisplayName("remove(int) should throw for invalid index")
void testRemoveInvalidIndex() {
list.add(1);
assertThrows(IndexOutOfBoundsException.class, () -> list.remove(5));
}
// ===== TESTS FOR size() =====
@Test
@DisplayName("size() should return 0 for empty list")
void testSizeEmpty() {
assertEquals(0, list.size());
}
@Test
@DisplayName("size() should reflect changes after add/remove")
void testSizeChanges() {
assertEquals(0, list.size());
list.add(1);
assertEquals(1, list.size());
list.add(2);
list.add(3);
assertEquals(3, list.size());
list.remove(0);
assertEquals(2, list.size());
}
// ===== TESTS FOR isEmpty() =====
@Test
@DisplayName("isEmpty() should return true for empty list")
void testIsEmptyTrue() {
assertTrue(list.isEmpty());
}
@Test
@DisplayName("isEmpty() should return false for non-empty list")
void testIsEmptyFalse() {
list.add(1);
assertFalse(list.isEmpty());
}
// ===== TESTS FOR contains() =====
@Test
@DisplayName("contains() should return true if element exists")
void testContainsTrue() {
list.add(1);
list.add(2);
list.add(3);
assertTrue(list.contains(2));
}
@Test
@DisplayName("contains() should return false if element not exists")
void testContainsFalse() {
list.add(1);
list.add(2);
assertFalse(list.contains(999));
}
@Test
@DisplayName("contains() should handle null")
void testContainsNull() {
list.add(1);
list.add(null);
list.add(3);
assertTrue(list.contains(null));
}
// ===== TESTS FOR indexOf() =====
@Test
@DisplayName("indexOf() should return correct index")
void testIndexOf() {
list.add(10);
list.add(20);
list.add(30);
assertEquals(1, list.indexOf(20));
}
@Test
@DisplayName("indexOf() should return -1 if not found")
void testIndexOfNotFound() {
list.add(1);
assertEquals(-1, list.indexOf(999));
}
@Test
@DisplayName("indexOf() should return first occurrence")
void testIndexOfFirstOccurrence() {
list.add(1);
list.add(2);
list.add(2);
list.add(3);
assertEquals(1, list.indexOf(2));
}
// ===== TESTS FOR iterator() =====
@Test
@DisplayName("iterator() should iterate all elements")
void testIterator() {
list.add(1);
list.add(2);
list.add(3);
List<Integer> result = new ArrayList<>();
for (Integer element : list) {
result.add(element);
}
assertEquals(List.of(1, 2, 3), result);
}
@Test
@DisplayName("iterator() should work on empty list")
void testIteratorEmpty() {
assertFalse(list.iterator().hasNext());
}
@Test
@DisplayName("iterator.next() should throw NoSuchElementException when exhausted")
void testIteratorNextThrows() {
list.add(1);
Iterator<Integer> iter = list.iterator();
iter.next();
assertThrows(NoSuchElementException.class, iter::next);
}
@Test
@DisplayName("iterator.remove() should remove element")
void testIteratorRemove() {
list.add(1);
list.add(2);
list.add(3);
Iterator<Integer> iter = list.iterator();
iter.next(); // 1
iter.next(); // 2
iter.remove(); // удаляем 2
assertEquals(2, list.size());
assertEquals(1, list.get(0));
assertEquals(3, list.get(1));
}
// ===== STRESS TESTS =====
@Test
@DisplayName("stress test: add 10000 elements")
void testAddManyElements() {
for (int i = 0; i < 10000; i++) {
list.add(i);
}
assertEquals(10000, list.size());
assertEquals(9999, list.get(9999));
}
@Test
@DisplayName("stress test: performance of get() is O(1)")
void testGetPerformance() {
for (int i = 0; i < 1000; i++) {
list.add(i);
}
long start = System.nanoTime();
for (int i = 0; i < 1000; i++) {
list.get(i);
}
long duration = System.nanoTime() - start;
// Должно быть быстро (O(1) доступ)
assertTrue(duration < 1_000_000_000); // < 1 второй
}
}
Требуемое покрытие
- Все public методы — 100% покрытие
- Happy path — стандартные операции
- Edge cases — пустой список, null, граница размера
- Error cases — исключения
- Stress tests — производительность
- Integration — комбинированные операции
Best Practices
- @DisplayName для читаемых описаний тестов
- @BeforeEach для инициализации перед каждым тестом
- assertTrue/assertFalse для boolean проверок
- assertEquals для проверки значений
- assertThrows для проверки исключений
- Параметризованные тесты для разных типов данных
- Граничные условия (empty, null, first/last element)
- Инварианты — неизменяемые свойства
- Комбинированные операции — add->remove->add
- Производительность — O(1) get(), O(n) add/remove