Какие тесты написать для проверки удаления первого элемента при добавлении третьего в стек емкостью два?
Что проверяют
Замечаете ли вы, что описанное поведение уже не классический стек: вытеснение самого старого элемента свойственно кольцевому буферу, а не LIFO. Интервьюер смотрит, уточните ли вы контракт и проверите ли состояние через публичные методы. Следом часто спрашивают, как реализовать такое без list.pop(0).
Как отвечать
Сначала зафиксируйте контракт вслух: при переполнении самый нижний элемент молча выбрасывается, pop по-прежнему отдаёт последний добавленный, размер никогда не превышает ёмкость. Дальше тесты на pytest:
- вытеснение:
push(1),push(2),push(3), затемpop()возвращает 3, следующийpop()возвращает 2, третий бросает исключение пустого стека. Так видно, что единица исчезла; - размер: после третьего
pushвыполняетсяlen(stack) == 2; - вершина:
peek()после вытеснения возвращает 3; - нет лишнего вытеснения:
push(1),push(2),pop(),push(3), и в стеке остаются 1 и 3. Реализация, которая вытесняет по счётчику операций, на этом упадёт; - многократное переполнение: пять
pushподряд, внутри остаются два последних; - граница ёмкости: стек ёмкостью 1 и проверка, что конструктор отвергает 0 и отрицательное значение через
ValueError.
Набор удобно оформить через @pytest.mark.parametrize: последовательность операций на входе, ожидаемые результаты pop на выходе.
Про реализацию: list.pop(0) сдвигает все элементы и стоит O(n). В стандартной библиотеке есть collections.deque(maxlen=2): при append в полную очередь элемент с противоположного конца выбрасывается сам, а pop() снимает с правого края за O(1).
Где спотыкаются
Называют это поведение подтверждением LIFO. LIFO описывает порядок извлечения, а выбрасывание самого старого элемента это отдельное правило, и его стоит проговорить.
Проверяют внутреннее поле stack.items == [2, 3]. Тест привязан к реализации и сломается при переходе на deque.
Ограничиваются одним сценарием с тремя элементами и не проверяют pop вперемешку с push, где и прячутся ошибки счётчиков.