diff paper/unittest.tex @ 6:f59edc38c858

add graphic files.
author koba <koba@cr.ie.u-ryukyu.ac.jp>
date Sun, 06 Feb 2011 01:58:33 +0900
parents
children f953f01c58bf 028ed9741872
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/paper/unittest.tex	Sun Feb 06 01:58:33 2011 +0900
@@ -0,0 +1,90 @@
+\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}
+
+このテストの結果、全てのオブジェクトの初期位置と状態遷移した値が正しいことが
+分かった。しかし、ここで行った単体テストはゲームにおける、ある一瞬の値の正誤
+しか調べることができない。ゲームプログラムは時間の経過と共にオブジェクトの
+パラメータが常に変化するため、こうした一般的な単体テストではゲームのバグを
+発見するのは難しい。