.NETテストプログラミング入門2
前回述べたようにテストコードが長く再利用できない状態は、オブジェクト指向プログラミングとしては問題です。具体的に言うと、特定のクラスに依存している事が問題です。どのクラスのメソッドであってもテスト出来るように改良せねばなりません。この場合、オブジェクト指向プログラミングの考え方では、インタフェースを使用してテストコードを改良します。
using System;
using System.IO;
interface IConsoleOut
{
void MessageOutPut();
}
class Tester
{
public bool ConsoleOutCheck( IConsoleOut target, string right )
{
//出力先を変えてテストを行いやすくする
TextWriter tmp = Console.Out;
StringWriter writer = new StringWriter();
Console.SetOut( writer );
//テスト対象を実行
target.MessageOutPut();
//出力設定を元に戻す
Console.SetOut( tmp );
////出力値をテスト
bool result = writer.ToString().Equals( right );
return result;
}
}
この様にインタフェースを使用すると、親子関係がない多数のクラスのメソッドを、テスト出来るテストコードへ生まれ変わります。親クラスを指定していない点に注目して下さい。コンソールへ文字列を出力するクラスが親子関係を持つ事は、オブジェクト指向設計の観点から言って不自然なので、この場面ではインタフェースが適しています。特に多重継承が出来ない.NETでは、コンソールへ文字列を出力する為だけに、親クラスを定義して継承するのは得策ではありません。
class Piyo : IConsoleOut
{
public void MessageOutPut()
{
Console.WriteLine( "おはピヨ♪" );
}
}
class HelloWorld : IConsoleOut
{
public void MessageOutPut()
{
Console.WriteLine( "Hello World!" );
}
}
class Test
{
static void Main( string[] args )
{
//テストの準備
Tester tester = new Tester();
//Piyoクラスのテストを実行
Console.WriteLine("これからPiyoテストを実行します。");
Piyo piyo = new Piyo();
string right = "おはピヨ♪" + Environment.NewLine;
bool result = tester.ConsoleOutCheck(
( IConsoleOut ) piyo,
right );
string message = result == true ? "テスト成功" : "テスト失敗";
Console.WriteLine( message );
Console.WriteLine();
//HelloWorldクラスのテストを実行
Console.WriteLine( "これからHelloWorldテストを実行します。" );
HelloWorld hello = new HelloWorld();
right = "Hello World!" + Environment.NewLine;
result = tester.ConsoleOutCheck(
( IConsoleOut ) hello,
right );
message = result == true ? "テスト成功" : "テスト失敗";
Console.WriteLine( message );
Console.WriteLine();
}
}
短いサンプルでは便利さが分かり難いかもしれませんが、長い文字列を処理結果に応じて出力するメソッドであっても、同様にテストできる点を考えると便利なテストコードだと言えます。しかしながら、このテストコードもまだまだ改善するべき余地があります。テストのためだけにインタフェースを実装するのは大変おかなしな事です。テスト対象はテストの事を考えず、適切なメソッドを定義できる様にするべきです。テストコードはテスト対象を変えるものではあってはなりません。
この問題点に対処する方法は・・・次回へ続く。