【问题标题】:How can I test private methods with DUnit?如何使用 DUnit 测试私有方法?
【发布时间】:2009-01-07 22:10:49
【问题描述】:

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

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

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

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

【问题讨论】:

标签: delphi unit-testing dunit


【解决方案1】:

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

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;

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

【讨论】:

  • 是的,听起来不太消极,我不同意为了单元测试而保护您的私有方法,因为它们是私有的。我认为您应该测试公共接口。无论如何,公共方法都将使用您的私有方法。
  • 我(恭敬地)不同意,原因我在这里详细说明:blogs.teamb.com/craigstuntz/2009/01/12/37919
  • /Ben:private 和 protected 是不同的特性,各有优缺点;如果您希望能够测试私有方法,使这些受保护的方法只是让您的测试框架 (DUnit) 可以访问它们的粗略方法。接下来是什么:私人是邪恶的,严格的私人更是如此?我同意 Ben 的观点:单元测试是为了测试你的合约(例如,带有显式(接口)和显式(使用)规则的公共接口)。如果私有成员需要测试,您应该使该接口正式(可能是接口的一部分,内部类等)。
  • 单元测试提供了一个覆盖范围的工具。在这种情况下,TDD 宗教与 OOP 宗教冲突。期待圣战接踵而至。
【解决方案2】:

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

  {$IfNDef TEST}
  private
  {$EndIf}

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

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

  private
  {$IfDef TEST}
  public
  {$EndIf}

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

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

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

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

【讨论】:

    【解决方案3】:

    我推荐 Gerard Meszaros 的“XUnit Test Patterns”一书:

    Test-Specific Subclass

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

    Answer:添加公开 测试所需的状态或行为 到 SUT 的子类。

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

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

      • ...仅使用条件指令
      【解决方案5】:

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

      【讨论】:

        【解决方案6】:

        使用 Extended RTTI(Delphi 2010 和更新版本),通过 RTTI 调用私有方法是另一种选择。这个解决方案也是How do I test a class that has private methods, fields or inner classes?中评分最高的答案

        【讨论】:

          【解决方案7】:
          {$IFNDEF UNITEST}
          private
          {$ENDIF}
          

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

          【讨论】:

            猜你喜欢
            • 2015-03-13
            • 1970-01-01
            • 2020-06-27
            • 1970-01-01
            • 2019-03-10
            • 1970-01-01
            • 1970-01-01
            • 2010-09-19
            • 1970-01-01
            相关资源
            最近更新 更多