我使用DUnit测试一个Delphi库。我有时遇到情况,我写了几个非常类似的测试来检查功能的多个输入。
有没有办法在DUnit中编写(类似于)参数化测试?例如,将输入和预期输出指定到合适的测试过程,然后运行测试套件并获得测试的多次运行中的哪一个失败的反馈?
(编辑:一个例子)
例如,假设我有两个这样的测试:
procedure TestMyCode_WithInput2_Returns4(); var Sut: TMyClass; Result: Integer; begin // Arrange: Sut := TMyClass.Create; // Act: Result := sut.DoStuff(2); // Assert CheckEquals(4,Result); end; procedure TestMyCode_WithInput3_Returns9(); var Sut: TMyClass; Result: Integer; begin // Arrange: Sut := TMyClass.Create; // Act: Result := sut.DoStuff(3); // Assert CheckEquals(9,Result); end;
我可能有更多的这些测试完全相同的事情,但有不同的投入和期望。我不想将它们合并成一个测试,因为我希望他们能够独立地通过或失败。
解决方法
您可以使用DSharp来改进您的DUnit测试。特别是新单位
DSharp.Testing.DUnit.pas(在德尔福2010及以上)。
只需将它添加到TestFramework之后,您就可以向测试用例添加属性。那么它可能看起来像这样:
unit MyClassTests; interface uses MyClass,TestFramework,DSharp.Testing.DUnit; type TMyClassTest = class(TTestCase) private FSut: TMyClass; protected procedure SetUp; override; procedure TearDown; override; published [TestCase('2;4')] [TestCase('3;9')] procedure TestDoStuff(Input,Output: Integer); end; implementation procedure TMyClassTest.SetUp; begin inherited; FSut := TMyClass.Create; end; procedure TMyClassTest.TearDown; begin inherited; FSut.Free; end; procedure TMyClassTest.TestDoStuff(Input,Output: Integer); begin CheckEquals(Output,FSut.DoStuff(Input)); end; initialization RegisterTest(TMyClassTest.Suite); end.
当你运行它,你的测试看起来像这样:
由于Delphi中的属性只接受常量,所以属性只是将参数作为一个字符串,其中值以分号分隔。但是没有什么可以阻止您创建自己的属性类,该属性类采用正确类型的多个参数来防止“魔术”字符串。无论如何,你只限于可以是const的类型。
您还可以在方法的每个参数上指定Values属性,并使用任何可能的组合(如NUnit)进行调用。
另外,在写单元测试的时候,我想写个尽可能少的代码。此外,我想看看测试在看到界面部分时没有挖掘实现部分(我不会说:“让我们做BDD”)做什么。这就是为什么我更喜欢声明性的方式。