eXtreme Programmingテスト技法―xUnitではじめる実践XPプログラミング (OOP foundations)
- 作者: 日本XPユーザグループ,長瀬嘉秀
- 出版社/メーカー: 翔泳社
- 発売日: 2001/11
- メディア: 単行本
- クリック: 20回
- この商品を含むブログ (14件) を見る
さて、毎度毎度 suite 関数やら main 関数やら書くのはめんどくさいし、テストが増えたら管理が大変になって止めてしまうのがオチなので自動化してみる。
自動生成されたテストクラス
自動生成の対象はテストクラスに suite 部分を付加したクラスとTestRunner を付加した main 関数の2つ。
以下のようなファイルが生成される。
Test.cpp
#include <cppunit/TestCase.h> #include <cppunit/TestSuite.h> #include <cppunit/TestRunner.h> #include <cppunit/TestCaller.h> USING_NAMESPACE_CPPUNIT using namespace std; #include "SampleTest.h" class tmpSampleTest : public SampleTest { public: tmpSampleTest( const char* name ) : SampleTest( name ) {} static Test* suite() { TestSuite* suite = new TestSuite( "SampleTest"); suite->addTest( new TEST_CALLER( SampleTest, testCalc)); suite->addTest( new TEST_CALLER( SampleTest, testMem)); suite->addTest( new TEST_CALLER( SampleTest, testSolve)); return suite; } }; int main( int argc, char* argv[] ) { TestRunner runner; runner.addTest( "SampleTest", tmpSampleTest::suite() ); return runner.run( argc, argv ); }
指針
CppUnit-x の TestCase クラスかは派生した SampleTest クラスを自分で作成する。
作成する内容は void testXXXX() というテスト関数とコンストラクタのみ。
そこから tmpSampleTest を派生し、suite 関数を付加する。
tempSampleTest と runner を含む main 関数は自動生成する。
自動化作成手順
テストコード作成
テストコードは void testXXXX() というテストケースとコンストラクタのみのクラスとする。
SampleTest.h
class SampleTest : public TestCase { public: // いつもきまった書き方のコンストラクタ SampleTest( const char* name ) : TestCase( name ) {} // 実行したいテストメソッド void testCalc(){} void testMem(){} void testSolve(){} };
TestSuite 自動生成コード
後述する TestRunnerFactory.rb からテストコードを渡され、テストケースを検索しテストスイートを作成する。
TestSuiteFactory.rb
class TestSuiteFactory def initialize( classname ) @classname = classname @testMethods = [] end def makeAddSuite "\trunner.addTest( \"" + @classname + "\", tmp" + @classname + "::suite() );\n"; end def makeSuiteMethod( file ) file.puts "#include \"" + @classname + ".h\"" file.puts "class tmp" + @classname + " : public " + @classname file.puts "{" file.puts "public:" file.puts "\ttmp" + @classname + "( const char* name ) : " + @classname + "( name ) {}\n" file.puts "\tstatic Test* suite()" file.puts "\t{" file.puts "\t\tTestSuite* suite = new TestSuite( \"" + @classname + "\");\n" @testMethods.each{ |method| file.puts "\t\tsuite->addTest( new TEST_CALLER( " + @classname + ", " + method + "));" } file.puts "\t\treturn suite;" file.puts "\t}" file.puts "};" file.puts "" end def parse lex = /.void (test.*)\(\).*/ File.readlines( @classname + ".h" ).each do |f| if lex =~ f then @testMethods.push( $1 ) end end end end
TestRunner 自動生成コード
実行フォルダを検索し、テスト対象ファイルを TestRunnerFactory.rb に渡すことでテストスイートを作成する。
すべてのテストスイートが作成されたら、main 関数にてテストランナーを作成する。
TestRunnerFactory.rb
require "TestSuiteFactory.rb" class TestRunnerFactory def initialize @tests = [] end def getTestList dir = Dir.open( Dir.pwd ) reg = /(.*Test)\.h/ dir.each { |file| if reg =~ file then @tests.push TestSuiteFactory.new( $1 ) end } dir.close end def makeRunner tester = File.new( "Tester.cpp", "w" ) tester.puts "#include <cppunit/TestCase.h>" tester.puts "#include <cppunit/TestSuite.h>" tester.puts "#include <cppunit/TestRunner.h>" tester.puts "#include <cppunit/TestCaller.h>" tester.puts "USING_NAMESPACE_CPPUNIT" tester.puts "using namespace std;" tester.puts "" @tests.each { |aClass| aClass.parse aClass.makeSuiteMethod( tester ) } tester.puts "int main( int argc, char* argv[] )" tester.puts "{" tester.puts "\tTestRunner runner;" @tests.each { |aClass| tester.puts aClass.makeAddSuite } tester.puts "\treturn runner.run( argc, argv );" tester.puts "}" tester.close end end factory = TestRunnerFactory.new factory.getTestList factory.makeRunner
自動実行 bat ファイル
今回は Windows + VC の環境なので、TestRunnerFactory.rb で TestSuite と TestRunner を作成後、cl にてコンパイルし、そのまま生成された実行ファイルを実行する。
ruby TestRunnerFactory.rb cl -GX -ID:\_work\etc\cppunit-x-20020331 Tester.cpp cppunit.lib Tester.exe pause
まとめ
ここまでで、テストケースさえ書くことが出来れば bat ファイルを実行するだけでテスト実行まで自動でやってくれる。
今考えられる積み残しとしてはこんなとこかな。
コンパイルの部分を make ファイルかなんかに出来た:)- テストでエラーが発生した場合の処理を考える
- ソースを Subversion から持ってくる
うーん、一から順番にやっていくとカンタンだ。
本当にこんないいものをいままで使っていなかったことを後悔するよ(;´Д`)