17

我有一门课,我正在用 DUnit 对它进行单元测试。它有许多方法一些公共方法和私有方法。

type
  TAuth = class(TDataModule)
  private
    procedure PrivateMethod;
  public
    procedure PublicMethod;
  end;

为了为此类编写单元测试,我必须公开所有方法。

是否有不同的方法来声明私有方法,以便我仍然可以测试它们但它们不是公共的?

4

7 回答 7

21

您无需将它们公开。受保护就行。然后,您可以对类进行子类型化以进行单元测试并显示受保护的方法。例子:

type
  TAuth = class(TDataModule)
  protected
    procedure MethodIWantToUnitTest;
  public
    procedure PublicMethod;
  end;

现在您可以为您的单元测试子类型化它:

interface

uses
  TestFramework, Classes, AuthDM;

type
  // Test methods for class TAuthDM
  TestAuthDM = class(TTestCase)
     // stuff
  end;

  TAuthDMTester = class(TAuthDM)
  public
    procedure MethodIWantToUnitTestMadePublic;
  end;

implementation

procedure TAuthDMTester.MethodIWantToUnitTestMadePublic;
begin
  MethodIWantToUnitTest;
end;

但是,如果您要进行单元测试的方法与数据模块的关系如此密切,以至于除了私有之外,它们是不安全的,那么您真的应该考虑重构方法以分离需要成为单元的代码测试和访问数据模块内部的代码。

于 2009-01-07T22:16:46.420 回答
9

这有点hacky,但我认为这是最简单,更清晰的方法。使用这个条件编译指令:

  {$IfNDef TEST}
  private
  {$EndIf}

您的单元测试项目必须在project → conditional defines. 如果没有可见性规范,它们就会被发布。

注意:如果私有可见性不是类声明中的第一个可见性,它将获得先前的定义。一种更安全但更冗长且不太清晰的方法是:

  private
  {$IfDef TEST}
  public
  {$EndIf}

与子类化或其他方法相比,这有很多优点:

  • 没有额外的复杂性:代码中没有额外的类。
  • 没有人可以“错误地”继承和覆盖你的类:你保留你的架构。
  • 当你说一个方法被保护时,你有点期望它会被覆盖。你是在告诉谁在阅读你的代码。一个不应该被覆盖的受保护的方法会让你的代码读者感到困惑,这违反了我的第一个编程原则:“必须编写代码才能被其他人阅读。”
  • DUnit 是在他们自己的单元中,而不是无处不在。
  • 你不要碰凌乱的 RTTI。

我认为这是一个更清晰的解决方案,并且比选定的答案更好。

当我使用它时,我还将测试项目配置为将构建对象放在主项目的不同目录中。这可以防止带有 TEST 指令的二进制文件与其他代码混合。

于 2011-09-13T20:33:55.177 回答
5

我推荐 Gerard Meszaros 的“ XUnit 测试模式”一书:

测试特定子类

问题:当我们需要访问 SUT 的私有状态时,如何使代码可测试?

答案:添加将测试所需的状态或行为暴露给 SUT 的子类的方法。

...如果被测系统 (SUT) 不是专门为可测试而设计的,我们可能会发现测试无法访问必须在测试中的某个时间点进行初始化或验证的状态。

文章还解释了何时使用它以及它会带来哪些风险。

于 2010-03-13T09:50:55.953 回答
4

将 DUnit 代码放入您的单元中。然后,您可以访问任何您喜欢的内容。

于 2010-03-15T00:29:44.030 回答
4

一般来说,当我遇到这种情况时,我经常意识到我违反了单一责任原则。当然,我对您的具体情况一无所知,但也许,私有方法应该在他们自己的类中。TAuth 将在其私有部分中引用这个新类。

于 2012-02-07T12:03:11.780 回答
2

使用扩展 RTTI(Delphi 2010 和更新版本),通过 RTTI 调用私有方法是另一种选择。此解决方案也是如何测试具有私有方法、字段或内部类的类中最受好评的答案?

于 2012-11-15T12:34:47.253 回答
2
{$IFNDEF UNITEST}
private
{$ENDIF}

简单的解决方案,这几乎不是一个黑客。我经常需要测试私有方法,而这种技术会尽可能减少复杂性。

于 2014-08-24T17:36:12.807 回答