По одной команде, без промедления, несколько тысяч клонов ринулись по узким сетевым коридорам, не ведая сомнений и страха поражения! Для того, чтобы сойтись в поединке и победить! Клоны, в большинстве своем не мастера, но запрограммированные на победу, просто четко выполняют инструкции, которые в случае удачи, ведут их к цели. Правила для всех одни, каждый сам за себя, но нет ни одного шанса выстоять и победить у человека, оказавшегося в этом месиве…
Это не эпизод легендарной саги «Звёздные войны» и не превью фантастической повести. Это описание нагрузочного тестирования сервера (построенного на технологиях Java), проведенного в ходе разработки игрового приложения «Покер» для социальных сетей.
Нагрузочному тестированию предшествовала реализация основной функциональности сервера: набора команд, сетевого интерфейса (Apache MINA), игрового движка и базы данных (Hibernate, MySQL). В процессе разработки использовалась непрерывная интеграция (сервер непрерывной интеграции Hudson), модульное тестирование (JUnit), интеграционное тестирование базы данных, нагрузочное тестирование сетевого интерфейса и логики приложения. В условиях, когда флеш-клиент игры находился в стадии начала разработки, стояла задача проведения интеграционного и нагрузочного тестирования игрового сервера. Был описан алгоритм инструкций для ботов покера, где поведение клона зависело от текущего состояния игровой ситуации, набора карт. С учетом того, что не было цели создать автоматического игрока с высоким мастерством, алгоритм был простым для реализации, но эффективным. Это позволило проводить тестирование игрового сервера посредством автоматических игроков наряду с реальными игроками. И клоны зачастую брали победу у людей числом, а не умением.
Как выше уже отмечалось, при разработке использовалось модульное тестирование, позволяющее проверить функциональность отдельных классов. Не обошлось без него и при разработке «мозга» движка — расчета покерной «руки» (определение выигрышной комбинации карт в ходе раздач карт). Для каждой комбинации были написаны тесты, позволяющие их проверить. Правила покера определяют следующие выигрышные комбинации:
Старшая карта;
Пара (две карты одного ранга);
Две пары (две пары одного ранга и еще две карты одного ранга);
Сет (три карты одного ранга);
Стрит (последовательность из пяти карт разной масти);
Флэш (любые пять карт одной масти);
Фул-хауз (три карты одного ранга и две карты тоже одного ранга);
Карэ (четыре карты одной и той же деноминации);
Стрит-флэш (последовательность из пяти карт одной и той же масти);
Флэш-рояль (пять старших карт какой-либо одной масти).
Таким образом имеются 10 выигрышных комбинаций карт и в простом случае максимально за 10 циклов расчета можно найти решение. Но даже начинающий игрок покера заметит, что часть игровых комбинаций имеет общие свойства, например, стрит-флэш владеет свойством стрит (последовательность из пяти карт...) и флеш (… одной масти). Таким образом число циклов расчета удалось сократить до 4. И у нас был набор юнит тестов на каждую комбинацию..., но уверенности в правильности расчета не было. Эта проблема была решена написанием теста, который использовал статистику по покерным комбинациям (вероятность выпадения покерной комбинации):
В данном тесте идет расчет 200000 случайных комбинаций, представлено число их выпадения в процентном соотношении и в численном (например, сет выпал в тесте 9609 в ~4.81% случаев). Расхождение между результатами этого теста и статистическими данными указало на ошибку, возникающую в результате того, что изначально не учли ряд особых правил в комбинациях, которые опытным игрокам прекрасно известны.
Таким образом, еще раз была подтверждена эффективность автоматического тестирования (модульного, интеграционного, нагрузочного) разрабатываемых приложений.