Модульное тестирование для научной вычислительной библиотеки

15

Раньше у меня был небольшой опыт модульного тестирования, в том, что я называю (не уничижительно), классический проект разработки программного обеспечения: MVC, с пользовательским интерфейсом, базой данных, бизнес-логикой на среднем уровне и т. Д. Теперь я пишу научную вычислительную библиотеку на C # (да, я знаю, что C # слишком медленный, использую C, не изобретайте колесо, и все такое, но у нас есть много людей, занимающихся научными вычислениями на моем факультете в C #, и нам это как-то нужно). Это небольшой проект с точки зрения индустрии разработки программного обеспечения, потому что я пишу его в основном самостоятельно, и время от времени с помощью нескольких коллег. Кроме того, мне не платят за это, и самое главное, это академический проект. Я имею в виду, я надеюсь, что это когда-нибудь будет иметь профессиональное качество, потому что я планирую пойти с открытым исходным кодом

В любом случае, проект становится большим (около 18 000 строк кода, который я считаю большим для проекта с одним человеком), и он выходит из моих рук. Я использую git для управления исходным кодом, и я думаю, что у меня все в порядке, но я тестирую, как в старой школе, я имею в виду, пишу полноценные консольные приложения, которые тестируют большую часть системы, главным образом потому, что я понятия не имею, как провести модульное тестирование в этом сценарии, хотя я чувствую, что это то, что я должен делать. Проблема в том, что библиотека содержит в основном алгоритмы, например, алгоритмы графов, классификаторы, числовые решатели, случайные распределения и т. Д. Я просто не знаю, как задать крошечные тестовые случаи для каждого из этих алгоритмов, и так как многие из них Стохастик Я не знаю, как проверить правильность. Для классификации, например, есть некоторые метрики, такие как точность и отзыв, но эти метрики лучше для сравнения двух алгоритмов, чем для оценки одного алгоритма. Итак, как я могу определить правильность здесь?

Наконец, есть и проблема производительности. Я знаю, что это совсем другой набор тестов, но производительность - это одна из важных характеристик научных инструментов, а не удовлетворенность пользователей или другие показатели разработки программного обеспечения.

Одна из моих самых больших проблем связана со структурами данных. Единственный тест, который я могу предложить для kd-дерева, это стресс-тест: вставьте много случайных векторов, а затем выполните много случайных запросов и сравните с наивным линейным поиском. То же самое для производительности. А с числовыми оптимизаторами у меня есть тестовые функции, которые я могу протестировать, но опять же, это стресс-тест. Я не думаю, что эти тесты могут быть классифицированы как модульные тесты и, что наиболее важно, выполняются непрерывно, поскольку большинство из них довольно тяжелые. Но я также думаю, что эти тесты должны быть выполнены, я не могу просто вставить два элемента, открыть корень, и да, это работает для случая 0-1-n.

Итак, каков (если таковой имеется) подход (модульное) тестирование для этого вида программного обеспечения? И как мне организовать модульные и тяжелые тесты вокруг цикла code-build-commit-integrate?

Алехандро Пиад
источник

Ответы:

19

Я бы сказал, что научные вычисления на самом деле вполне подходят для модульного тестирования. У вас есть определенные входы и выходы, четко определенные предварительные и постусловия, которые, вероятно, не будут меняться примерно раз в две недели в соответствии с прихотью какого-либо дизайнера, и нет сложных для тестирования требований пользовательского интерфейса.

Вы называете некоторые элементы, которые могут вызвать проблемы; вот что с ними делать:

  • рандомизированные алгоритмы: есть две возможности. Если вы действительно хотите проверить рандомизацию самостоятельно, просто запланируйте большое количество повторений и подтвердите, что ожидаемая доля случаев соответствует желаемому критерию с достаточно большими полями ошибок, что ложные неудачи тестирования будут довольно редкими. (Набор тестов, который ненадежно сигнализирует о фантомных ошибках, намного хуже, чем набор, который не улавливает все мыслимые дефекты.) В качестве альтернативы, используйте настраиваемый случайный источник и замените системные часы (или что бы вы ни использовали) детерминированным источником через зависимость инъекции, чтобы ваши тесты стали полностью предсказуемыми.
  • алгоритмы, определенные только с точки зрения точности / отзыва: ничто не мешает вам ввести целый набор входных данных и измерить точность и вызвать их, сложив их все; это просто вопрос полуавтоматической генерации таких тестовых примеров, чтобы предоставление тестовых данных не стало узким местом для вашей производительности. В качестве альтернативы, указание некоторых разумно выбранных пар ввода / вывода и утверждение, что алгоритм вычисляет точно требуемый ввод, также может работать, если процедура достаточно предсказуема.
  • нефункциональные требования: если спецификация действительно предъявляет явные требования к пространству / времени, то вам, в основном, нужно выполнить целые наборы пар ввода-вывода и убедиться, что использование ресурсов приблизительно соответствует требуемому шаблону использования. Хитрость заключается в том, чтобы сначала откалибровать свой собственный класс тестирования, чтобы вы не измеряли десять задач с разными размерами, которые оказываются слишком быстрыми для измерения или занимают так много времени, что запуск набора тестов становится непрактичным. Вы даже можете написать небольшой генератор вариантов использования, который создает тестовые наборы разных размеров, в зависимости от того, насколько быстро работает PU.
  • быстрые и медленные тесты: будь то модульные или интеграционные тесты, вы часто получаете много очень быстрых тестов и несколько очень медленных. Поскольку регулярное выполнение ваших тестов очень ценно, я обычно иду прагматическим путем и разделяю все, что у меня есть, на быстрый и медленный набор, чтобы быстрый можно было запускать как можно чаще (безусловно, перед каждым коммитом), и неважно, два теста «семантически» принадлежат друг другу или нет.
Килиан Фот
источник
+1. Большое спасибо, есть много, если понимание вашего ответа. Просто пара вопросов: как насчет алгоритмов оптимизации, таких как метаэвристика. У меня есть куча тестовых функций, но все, что я могу с ними сделать, это сравнить два разных алгоритма. Нужно ли также найти алгоритм бенчмарка? Что значит для генетического алгоритма быть правильным? И как мне проверить каждую из «параметризуемых» стратегий, таких как тип рекомбинации и мутации и т. Д.?
Алехандро Пиад
1
Для метаэвристики я бы выбрал несколько характерных пар ввода / вывода, то есть «известные успехи» подпрограммы, и проверил, что метод (или лучший из двух) действительно находит это решение. Проблемы «выбора вишни», которые, как оказалось, работают хорошо, конечно, нет проблем в исследованиях оптимизации, но для тестирования программного обеспечения это не проблема - вы не утверждаете качество алгоритма, просто правильная реализация. Это единственная «правильность», которую вы можете доказать. Что касается многопараметризуемых подпрограмм: да, я боюсь, что требуется комбинаторное количество тестов ...
Килиан Фот
Так что это похоже на разработку тривиального теста, который все правильные реализации должны решать точно? Есть ли способ доказать качество алгоритма? Я знаю, что большую часть времени не могу определить стандарт качества, но, по крайней мере, я мог бы пожелать, чтобы никакие изменения не снижали достигнутое качество?
Алехандро Пиад