戻る 進む

Calcにmulとdivという掛け算と割り算をするメソッドを追加してみます。

ええとその前に、XPですこし勘違いしていたようです。今までは空の実装を先に書いて、テストを作るという風にしてました。これはコンパイルエラーになる からだったんですが、これは別にコンパイルエラーしてもいいようです。何はともあれまずテストが先で完成形のイメージが出来てから、エラーを順番に潰して いくのがXP風なようです。関係ないですが僕はコンパイルエラー恐怖症かもしれません・・・。というわけで、まずテストを書きます。
今はtestsディレクトリにいます。

vim CalcTest.cpp

 1  #include "CalcTest.h"
2
3 /*
4 @TARGET
5 ../Calc.h
6 */
7
8 /*
9 @PRIVATE
10 Calc* calc;
11 */
12
13 void CalcTest::setUp () {
14 calc = new Calc;
15 }
16
17 void CalcTest::tearDown () {
18 delete calc;
19 }
20
21 //========================================
22 // Test Cases
23 //========================================
24
25 //足し算
26 void CalcTest::test_add () {
27 CPPUNIT_ASSERT_EQUAL( 2, calc->add(1,1) );
28 CPPUNIT_ASSERT_EQUAL( 1, calc->add(1,0) );
29 CPPUNIT_ASSERT_EQUAL( 1, calc->add(0,1) );
30 CPPUNIT_ASSERT_EQUAL( 0, calc->add(0,0) );
31 CPPUNIT_ASSERT_EQUAL( 9, calc->add(6,3) );
32 CPPUNIT_ASSERT_EQUAL( 9, calc->add(3,6) );
33 }
34
35 //引き算
36 void CalcTest::test_sub () {
37 CPPUNIT_ASSERT_EQUAL( 0, calc->sub(1,1) );
38 CPPUNIT_ASSERT_EQUAL( 1, calc->sub(1,0) );
39 CPPUNIT_ASSERT_EQUAL( -1, calc->sub(0,1) );
40 CPPUNIT_ASSERT_EQUAL( 0, calc->sub(0,0) );
41 CPPUNIT_ASSERT_EQUAL( 3, calc->sub(7,4) );
42 }
43
44 //掛け算
45 void CalcTest::test_mul () {
46 CPPUNIT_ASSERT_EQUAL( 0, calc->mul(0,0) );
47 CPPUNIT_ASSERT_EQUAL( 1, calc->mul(1,1) );
48 CPPUNIT_ASSERT_EQUAL( 0, calc->mul(0,1) );
49 CPPUNIT_ASSERT_EQUAL( 0, calc->mul(1,0) );
50 CPPUNIT_ASSERT_EQUAL( 4, calc->mul(2,2) );
51 CPPUNIT_ASSERT_EQUAL( 9, calc->mul(3,3) );
52 CPPUNIT_ASSERT_EQUAL(16, calc->mul(4,4) );
53 CPPUNIT_ASSERT_EQUAL(12, calc->mul(3,4) );
54 }
55
56 //割り算
57 void CalcTest::test_div () {
58 CPPUNIT_ASSERT_EQUAL(0, calc->div(0,0) );
59 CPPUNIT_ASSERT_EQUAL(2, calc->div(2,1) );
60 CPPUNIT_ASSERT_EQUAL(1, calc->div(3,2) );
61 CPPUNIT_ASSERT_EQUAL(3, calc->div(15,4) );
62 CPPUNIT_ASSERT_EQUAL(0, calc->div(4,10) );
63 CPPUNIT_ASSERT_EQUAL(1, calc->div(10,10) );
64 }

コメントを付けて、test_mulとtest_divを追加しました。何かわざとらしいハプニングを期待させるようなのが混じっているような気もし ますが、気のせいです。


それじゃあ

test

Calcのメンバが無いとか云ってコンパイルが通りません。んではCalcのメンバを追加します。

vim ../Calc.h

1  class Calc {
2 public:
3 int add(int x, int y);
4 int sub(int x, int y);
5 int mul(int x, int y);
6 int div(int x, int y);
7 };
クラスの宣言にmulとdivを追加しました。まだ実装は書いてませんが、とりあえず・・・

test

コンパイルは通るようですが、リンクで外部参照が解決できないとか言いやがります。それでは次にテストランナーのビルドはできるけど、テストには失敗する ことを期待する空 の実装を書きます。

vim ../Calc.cpp

 1  #include "Calc.h"
2
3 int
4 Calc::add(int x, int y) {
5 return x+y;
6 }
7
8 int
9 Calc::sub(int x, int y) {
10 return x-y;
11 }
12
13 int
14 Calc::mul(int x, int y) {
15 return 0;
16 }
17
18 int
19 Calc::div(int x, int y) {
20 return 0;
21 }
Calc::mulとCalc::divを書きました。ではとりあえず・・・

test


コンパイルもリンクも通ってテストの実行結果はつぎのような感じです。

(テストの実行結果)

...F.F

!!!FAILURES!!!
Test Results:
Run:  4   Failures: 2   Errors: 0


1) test: CalcTest.test_mul (F) line: 47 CalcTest.cpp
expected: 1
but was:  0

2) test: CalcTest.test_div (F) line: 59 CalcTest.cpp
expected: 2
but was:  0



失敗してるのが確認できたので、ちゃんと実装を書きます。

vim ../Calc.cpp

13  int
14 Calc::mul(int x, int y) {
15 return x*y;
16 }
17
18 int
19 Calc::div(int x, int y) {
20 return x/y;
21 }

これで全てのテストが通るはずです!

test


(テストの実行結果)

...E

!!!FAILURES!!!
Test Results:
Run:  4   Failures: 0   Errors: 1


1) test: CalcTest.test_div (E)
 "caught unknown exception"



おおっ!なにやらエラーが発生しています!!(わざとらしい)
エラーと失敗は違います。どうやらtest_divテストケースで謎の例外が発生してるようです。行番号が出れば良いんですが、そういう気の利いた事はで きな いようなのでtest_devをチェックして怪しいところを見つけます。
58      CPPUNIT_ASSERT_EQUAL(0, calc->div(0,0) );

ゼロで割ってるので、これですね。
例外のチェックをするマクロは一応CPPUNIT_TEST_EXCEPTIONというのがあるんですが、このマクロはテストスイートに例外を投げるテス トケー スを登録するやつです。自作スクリプトでは今のとこ全てのテストケースをCPPUNIT_TESTとしてスイートにまとめるような仕組みなので、例外処理 を使ってチェックします。

vim CalcTest.cpp

56  //割り算
57 void CalcTest::test_div () {
58 CPPUNIT_ASSERT_EQUAL(2, calc->div(2,1) );
59 CPPUNIT_ASSERT_EQUAL(1, calc->div(3,2) );
60 CPPUNIT_ASSERT_EQUAL(3, calc->div(15,4) );
61 CPPUNIT_ASSERT_EQUAL(0, calc->div(4,10) );
62 CPPUNIT_ASSERT_EQUAL(1, calc->div(10,10) );
63 //例外チェック
64 bool exp_chk = false;
65 try {
66 calc->div(0,0);
67 } catch (...) {
68 exp_chk = true;
69 }
70 CPPUNIT_ASSERT( exp_chk );
71 }

やる気の無い例外処理ですいません・・・。まあこういう風に例外の発生もテストできるよ ということで、とりあえず・・・

test


(テストの実行結果)

....

OK (4 tests)



というわけで、一応テストケースで書いた仕様を全て満たしたCalcクラスの機能追加が完了しました。
テストコードとテスト対象のコードを修正したらtestと打つだけで必要なものを更新して、最新の状態で全てのテストを(毎回)走らせることができたの で、テストにまつわる労力を大幅に削減できたと思います。今回はひとつのメソッドがそれぞれで完結してますが、他のメソッドをコールしたり複雑な場合は全 てのテストを素早く実行できるというのはコードの修正が楽になると思いました。

あと、ここまで書いて知ったのですが、河童プロジェクトというのがある そうです。具体的にどういうものかはまだ詳しくは調べていないのですが、「CppUnitめんどくさい」という僕と同じようなコンセプトで雛型の生成やテ ストケースの追加、テスト実行プログラムの生成などをするツール群のようです。


つづく