Информация об изменениях

Сообщение Re: а вопрос с подковыркой от 11.11.2021 18:07

Изменено 11.11.2021 18:11 Quebecois

Re: а вопрос с подковыркой
Здравствуйте, BlackEric, Вы писали:

BE>А потом меня попросили написать юнит-тест на это.


BE>Как такое тестировать? Реально стартовать потоки в тесте? Но где гарантия, что потоки случайно не вызовут методы в нужном порядке.

"в лоб" это протестировать нельзя, т.к. с точки зрения теста это выглядит так:

1. Тест вызвал метод
2. (возможное переключение контекста)
3. Метод сделал lock()
4. (возможное переключение контекста)
5. Метод сделал что-то полезное

Не зная, что внутри метода, тест не может отличить переключение контекста между моментами 2 и 4, соответственно, убедиться, что lock() был сделан. Это можно определить статистически, смотря на время вызова/возврата и считая относительные вероятности, но делать это для собственного кода — мазохизм.

Я бы это разбил на 2 задачи:
1. Проверяем последовательность методов в одном потоке
2. Проверяем, что методы делают lock() через вспомогательный метод

Вспомогательный метод должен делать lock() и ждать какого-то события. Тестирование тогда будет выглядеть так:

1. Запускаем второстепенный поток, который берет lock()
2. Запускаем еще один поток, который вызывает метод
3. Убеждаемся, что метод не вернул управление за N миллисекунд
4. Освобождаем lock
5. Убеждаемся, что метод вернул управление через M миллисекунд

Но это тоже полу-костыль. Не-костыльный вариант — это объявить свой ISynchronizationManager, который будет создавать mutex-ы. Тест может имплементироавть свою версию, считающую, сколько раз ее вызвали из каких потоков, и дающую задержки, где надо.

Но это в теории. На практике вероятность, что кто-то уберет из работающего метода lock() просто, чтобы поглумиться, стремится к нулю. Скорее, его зарефакторят, разделив на 2 метода, оставя lock во внешнем, а потом через год вызовут внутренний метод из свежедобавленного, где забудут lock(). Против таких вещей unit-тесты бесполезны, а вот хороший стресс-тест, жарящий пару реалистичных юзкейсов потоков так из 50, выявит это на лету.

Но это с точки зрения инженера. А в организационном плане, если насяльника сказал, что нужны 100% тесты, но надо делать большие голубые глаза и справшивать совета. Потому что если вы с умным видом изложите на собеседовании перечисленное выше, то вас не возьмут, как overqualified.
Re: а вопрос с подковыркой
Здравствуйте, BlackEric, Вы писали:

BE>А потом меня попросили написать юнит-тест на это.


BE>Как такое тестировать? Реально стартовать потоки в тесте? Но где гарантия, что потоки случайно не вызовут методы в нужном порядке.

"в лоб" это протестировать нельзя, т.к. с точки зрения теста это выглядит так:

1. Тест вызвал метод
2. (возможное переключение контекста)
3. Метод сделал lock()
4. (возможное переключение контекста)
5. Метод сделал что-то полезное

Не зная, что внутри метода, тест не может отличить переключение контекста между моментами 2 и 4, соответственно, убедиться, что lock() был сделан. Это можно определить статистически, смотря на время вызова/возврата и считая относительные вероятности, но делать это для собственного кода — мазохизм.

Я бы это разбил на 2 задачи:
1. Проверяем последовательность методов в одном потоке
2. Проверяем, что методы делают lock() через вспомогательный метод

Вспомогательный метод должен делать lock() и ждать какого-то события. Тестирование тогда будет выглядеть так:

1. Запускаем второстепенный поток, который берет lock()
2. Запускаем еще один поток, который вызывает метод
3. Убеждаемся, что метод не вернул управление за N миллисекунд
4. Освобождаем lock
5. Убеждаемся, что метод вернул управление через M миллисекунд

Но это тоже полу-костыль. Не-костыльный вариант — это объявить свой ISynchronizationManager, который будет создавать mutex-ы. Тест может имплементироавть свою версию, считающую, сколько раз ее вызвали из каких потоков, и дающую задержки, где надо.

Но это в теории. На практике вероятность, что кто-то уберет из работающего метода lock() просто, чтобы поглумиться, стремится к нулю. Скорее, его зарефакторят, разделив на 2 метода, оставя lock во внешнем, а потом через год вызовут внутренний метод из свежедобавленного, где забудут lock(). Против таких вещей unit-тесты бесполезны, а вот хороший стресс-тест, жарящий пару реалистичных юзкейсов потоков так из 50, выявит это на лету.

Но это с точки зрения инженера. А в организационном плане, если насяльника сказал, что нужны 100% тесты, то надо делать большие голубые глаза и справшивать, с сахаром или без. Потому что если вы с умным видом изложите на собеседовании перечисленное выше, то вас не возьмут, как overqualified.