Mercurial > hg > Papers > 2011 > koba-master
view paper/unittest.tex @ 14:19be75493fbb
fix.
author | koba <koba@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Tue, 15 Feb 2011 18:04:22 +0900 |
parents | d711f469cdb7 |
children |
line wrap: on
line source
\chapter{CppUnit による単体テスト} \label{chapter:unittest} ここでは一般的なテスト駆動開発のフレームワークの例として CppUnit の紹介と、 過去に CppUnit を用いて行われた Cerium の単体テストについて述べる。 \section{CppUnit} CppUnit は、xUnit と呼ばれる、単体テストを自動化するテスティング フレームワークの内の一つで C++ 用に開発されている。 CppUnit の特徴はテストケースを増やすことが容易であり、1 つの事象に対して 様々なテストケースを同時にテストする事ができる。また、羅列したテストケースは 一括で実行、結果の表示ができる。(図\ref{fig:cpptest}) \begin{figure}[h] \includegraphics[scale=0.6]{images/test_example.pdf} \caption{CppUnitTest} \label{fig:cpptest} \end{figure} \newpage \section{CppUnit によるゲームプログラムの単体テスト} 我々は過去に CppUnit を用いてゲームプログラムの単体テストを行なっている。 このテストでは Cerium のオブジェクト管理システムである SceneGraph (\ref{sec:scenegraph}節) を用い、3 つの SceneGraph ノードを持つオブジェクトの テストを行った。このオブジェクトは本体の他に左右にパーツを 1 つずつ持つ。 本体を tree の root として左右のパーツがその子供になっている。 (図\ref{fig:boss1}) \begin{figure}[htbp] \includegraphics[scale=0.8]{images/boss1_SG.pdf} \caption{boss1} \label{fig:boss1} \end{figure} この boss1 は右に一定速度で移動し、画面上の適当な位置に来ると State パターン により左方向への移動に状態が遷移する、簡単なゲームの例題となっている。 \begin{verbatim} static void boss1_move_right(SceneGraphPtr node, int screen_w, int screen_h) { node->xyz[0] += node->stack_xyz[0]; if(node->xyz[0] > screen_w-280) { node->set_move_collision(boss1_move_left, boss1_collision); } } static void boss1_move_left(SceneGraphPtr node, int screen_w, int screen_h) { node->xyz[0] -= node->stack_xyz[0]; if(node->xyz[0] < 280) { node->set_move_collision(boss1_move_right, boss1_collision); } } \end{verbatim} このテストでは root のアドレスを取得し、そこから tree を辿って 各オブジェクトの座標を取得し、その初期化が正しいか、状態遷移において正しい 値を保持しているか調べた。 \begin{verbatim} void sgTest::rootTest() { test_init(); sg_root->print_member(); CPPUNIT_ASSERT_EQUAL((float)width/2, sg_root->xyz[0]); CPPUNIT_ASSERT_EQUAL(0.0f, sg_root->xyz[1]); CPPUNIT_ASSERT_EQUAL(-100.0f, sg_root->xyz[2]); } void sgTest::childTest() { while (sg_root) { if(sg_root->children != NULL) { sg_root->children->print_member(); ... sg_root = sg_root->children; } else if(sg_root->brother != NULL) { sg_root->brother->print_member(); CPPUNIT_ASSERT_EQUAL(0.0f, sg_root->brother->xyz[0]); ... sg_root = sg_root->brother; } else { ... \end{verbatim} このテストの結果、全てのオブジェクトの初期位置と状態遷移した値が正しいことが 分かった。少なくとも初期化の段階でバグが発生していないことだけは保証された。 \section{ゲームプログラムに対する単体テストの欠点} しかし、ここで行った単体テストは、ゲームにおける、ある一瞬の値が正しいか どうかを調べるには効果的だが、常にオブジェクトのパラメータが時間の経過と 共に変化するゲームプログラムにおいては有効的とは言えない。 ゲームプログラムにおけるバグは他のオブジェクトのパラメータとの関係に依る ところが多く、こうした一般的な単体テストではゲームのバグを発見するのは 難しい。