我使用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”)做什么。这就是为什么我更喜欢声明性的方式。