2009-04-01 17 views
10

DUnitの通常の動作方法は、公開されたメソッドをいくつか書き、DUnitでテストとして実行することです。私がやりたいことは少し違っています。私は、データに基づいて実行時にテストを作成したいと思っています。出力ファイルを作成するために入力ファイルを処理する特定のモジュールをテストしようとしています。私は、対応する既知の良い出力ファイルを持つテスト入力ファイルのセットを持っています。この考え方は、入力を処理し、既知の良いものに対して出力をチェックする、各入力ファイル用のテストを動的に作成することです。データ駆動DUnitテスト

実際のデータソースはここでは重要ではありません。難しいのは、DUnitをデータ駆動型に動作させることです。この問題のために、データソースが単なる乱数生成器であるとします。各1

  1. は、実行時に名前が付けられ

    は、実行時にいくつかのテストオブジェクト(TTestCaseまたは何でも)を作成し、それらの10と言う、:ここでは難易度の心に届く例の具体的な問題がありますランダムに生成された整数から。 ( '名前'によって、テストランナーツリーに表示されるテストの名前を意味します)

  2. ランダムな整数に基づいて合格または不合格になります。偶数のために渡す、奇数のために失敗する。

のDUnitの設計から、それはこのようなことを可能にするために念頭に置いて、十分な柔軟性を設計されたように、それ見えます。私はそれがあるとは確信していません。 TAbstractTestとITestを継承して独自のテストクラスを作成しようとしましたが、いくつかの重要なメソッドにアクセスできませんでした。私もTTestCaseを継承しようとしましたが、そのクラスは公開されたメソッドを実行するアイデアと密接に結びついています(テストはメソッドの名前が付けられているので、すべてのテストは「go」と呼ばれ、すべてのテストは個別に名前を付けたい)

また、DUnitの代わりに、私が望むことができるものがありますか?

答えて

17
program UnitTest1; 

{$IFDEF CONSOLE_TESTRUNNER} 
{$APPTYPE CONSOLE} 
{$ENDIF} 

uses 
    Forms, Classes, SysUtils, 
    TestFramework, 
    GUITestRunner, 
    TextTestRunner; 

{$R *.RES} 

type 
    TIntTestCase = class(TTestCase) 
    private 
    FValue: Integer; 
    public 
    constructor Create(AValue: Integer); reintroduce; 
    function GetName: string; override; 
    published 
    procedure Run; 
    end; 

{ TIntTestCase } 

constructor TIntTestCase.Create(AValue: Integer); 
begin 
    inherited Create('Run'); 
    FValue := AValue; 
end; 

function TIntTestCase.GetName: string; 
begin 
    Result := Format('Run_%.3d', [FValue]); 
end; 

procedure TIntTestCase.Run; 
begin 
    Check(FValue mod 2 = 0, Format('%d is not an even value', [FValue])); 
end; 

procedure RegisterTests; 
const 
    TestCount = 10; 
    ValueHigh = 1000; 
var 
    I: Integer; 
begin 
    Randomize; 
    for I := 0 to TestCount - 1 do 
    RegisterTest(TIntTestCase.Create(Random(ValueHigh) + 1)); 
end; 

begin 
    Application.Initialize; 
    RegisterTests; 
    if IsConsole then 
    TextTestRunner.RunRegisteredTests 
    else 
    GUITestRunner.RunRegisteredTests; 
end. 
+0

それは素晴らしいです。ありがとう。私は似たようなことを試していましたが、道に沿っていくつかの間違いがありました。再度、感謝します。 –

+0

私は助けてくれるとうれしいです。 –

+0

データ駆動型のケースと普通のテストケースの両方を同じテストクラスに含めることをお勧めしますか? –

2

基本的には、各データファイルごとに1つの他のテストを呼び出す単一の「スーパーテスト」機能が必要です。これは私たちのDUnitテストで行います。使用可能な各ファイルを順番にループでロードし、必要に応じてCheckを使用してテストを実行します。

最後のアプリとそのデータの読み込みと解析を同じプロジェクトでテストする代わりに、FinalBuilderのようなアプリケーションをループすることもできます(おそらくDUnitアプリをループしてパラメータ)をさまざまな異なるデータファイルで置き換えます。その後、アプリケーションが実行され、分析が行われ、保存後に終了します。別のアプリは結果データと理想データを比較し、必要に応じて失敗を報告します。

+0

各テストには時間がかかり、通常は一度に数個しか破損しないため、スーパーテストアイデアは動作しません。コードを修正するためには、これらのテストだけを分離する必要があります。毎回スーパーテスト全体を走らせることは残念なことに非常に遅いでしょう。 –

+0

@dangph:これはFinalBuilderのテストが行​​われる場所です。個々のテストは失敗する可能性がありますが、その中にtry/catch機能を使用して単一のエラーを記録しますが、残りのエラーを記録し、 。 – mj2008

+0

@ mj2008、私たちがやっていることは、かなりぎりぎりとしたモジュールをリファクタリングすることです。私たちが物をリファクタリングするとき、テストは中断します。テストはかなり遅いため、コードを修正している間に壊れたテスト(DUnitチェックボックスを使用)を実行したいのですが、通常は数回ループする必要があります。 –

関連する問題