Joost van der Sluis wrote:

>>> If I have several tests defined for a component. The component is
>>> created and destroyed in the setup and teardown procedures. And then one
>>> test is done.
>>>
>>> But now, when all tests are performed. I want to run those tests again,
>>> but then with one different value for a property of the component.
>>>
>>> And then once again, with another property change.
>>>
>>> How can I do that in w nice way?
>> The framework as designed in JUnit has no external input. So, the
>> simplest way is to write a set of tests in which you use the same setup
>> and teardown code and assign the value to a property in the body of the
>> test method.
> 
> But then, how can I run those tests more then once?
> 
> Or else I've to add wrappers for all the properties I want to change.
> for example 10 tests, running with 20 different settings writing =
> 20*10=200 procedures...
> 
>> or you could decide to read the property from a text file, but in this
>> case you should always remember to change this value and repeat the
>> tests, non practical at all.
>> Can you send me an example of your tests for which you need this, maybe
>> a concrete case could give me a better idea.
> 
> See the attachment in my mail from 11:40 pm. The tests in TestDBBasics.
> I want to run them all with GetNDataset(x).Packetrecords := -1, 1, 5,
> 10, 100
> 
> Btw: what do you think of the tests? Improvements are welcome...
Didn't have the time to look at your tests yet, but I've written a small
example on how to effectively write parameterized tests in fpcunit, that
I'm attaching to this mail.
It proves once again that the junit framework design is quite flexible
and can be simply adapted to different testing needs. I added a short
description and some comments to the code to see how to proceed.
Ciao, Dean
unit paramstests;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, fpcunit, testutils, testregistry; 

type
{sometimes the different tests to run have a lot of common functionality
and they differ only for the presence of a different parameter, or a different
property of the class under test. To remove duplication and unnecessary code
there is the possibility to manually build a parameterized test suite, see the
following example that can be used as a template. The steps are simple, create
a new constructor for the testcase that has the parameters you'll want to pass
in the tests (in the following examples the parameters are a string input parameter
and an integer parameter to use for the testing of the results). In this constructor
you have to call the inherited CreateWithName constructor passing the name of the
actual test (in the following code the actual test is the DoTest procedure that
performs a simple test of the lenght function for the string passed as parameter to
the testcase). The parameters are then stored in some private fileds of the testcase.
Then you'll have to construct the test suite manually, see the
Suite class function, passing the constructor of the testcase with the wanted parameters.
Finally you'll add the constructed test to the test registry using the
GetTestRegistry.AddTest function in the initialization section.
In this example you'll see that four isolated different tests with the same name (DoTest)
will be created. The only drawback is in the fact that in case of failure it's not
immediate to see which test went wrong, as the tests have the same name. I suggest
to pass some information in the string description of the extended assertequals function
as a hint (in the DoTest example below I've inserted the parameter that was passed into the test)

The same parameterized testcase could be constructed by loading the parameters
from an xml file or from an ini file instead of storing them in the private fields
of the testcase. I leave this simple implementation as an exercise for the reader :)


  { TParameterizedTestCase }

  TParameterizedTestCase = class(TTestCase)
  private
    aParam: string;
    aOut: integer;
  public
    constructor Create(const aParameter: string; aOutput: integer); virtual; overload;
    class function Suite: TTestSuite;
  published
    procedure DoTest;
  end;

implementation

{ TParameterizedTestCase }

constructor TParameterizedTestCase.Create(const aParameter: string; aOutput: integer);
begin
  //create a new DoTest testcase
  inherited CreateWithName('DoTest');
  //store the parameters
  aParam := aParameter;
  aOut := aOutput;
end;

class function TParameterizedTestCase.Suite: TTestSuite;
begin
//manually create the test suite
  Result := TTestSuite.Create('TParameterizedTestCase');
  Result.AddTest(TParameterizedTestCase.Create('', 0));
  Result.AddTest(TParameterizedTestCase.Create('o', 1));
  Result.AddTest(TParameterizedTestCase.Create('two', 3));
  Result.AddTest(TParameterizedTestCase.Create('three', 5));
end;

procedure TParameterizedTestCase.DoTest;
begin
//insert here the common functionality of the parameterized test
//here for example we are testing the Length function:
  AssertEquals('test ' + aParam, aOut, length(aParam));
  // notice that the 'test ' + aParam description was added to be able to
  //distinguish which test went wrong
end;

initialization
  //register the manually created suite
  GetTestRegistry.AddTest(TParameterizedTestCase.Suite);
end.

Reply via email to