【问题标题】:Unit Testing a class with an internal constructor使用内部构造函数对类进行单元测试
【发布时间】:2009-11-06 23:26:53
【问题描述】:

我有一个名为“Session”的类,它公开了几个公共方法。我想对这些进行单元测试,但是在生产中我需要控制“会话”对象的实例化,因此将构造委托给 SessionManager 类并将 Session 的构造函数设置为内部。

理想情况下,我希望将 Session 类与创建它/它们的 SessionManager 隔离开来测试 Session 类,以证明 Session 公开的公共接口按预期工作 - 但不能在不使用的情况下从测试中实例化 Session SessionManager 使我的测试比它们需要的更复杂/更没用。

解决这个问题的最佳方法是什么?

干杯,

莱尼。

【问题讨论】:

  • 请澄清:它是受保护的还是内部构造函数?

标签: c# unit-testing nunit


【解决方案1】:

没有什么能阻止您测试内部结构。只需使用 InternalsVisibleTo 属性使您的代码内部对测试套件可见:在 AssemblyInfo 中,添加

[assembly:InternalsVisibleTo("TestSuiteAssembly")]

【讨论】:

  • 这似乎是最简单的方法,所以我想我会这样做。谢谢。
  • 答案确实不完整 - 必须对程序集进行签名才能使其工作。
  • 我想挑战你不是真的,但已经两年半了 :) 我可能在 .net 3.5 中工作过
  • 我这样做了,但我有一个错误:Friend assembly reference 'TestSuiteAssembly' is invalid. Strong-name signed assemblies must specify a public key in their InternalsVisibleTo declarations. 我不知道如何检索 TestSuiteAssembly 的公钥。
【解决方案2】:

您可以让您的单元测试类从 Session 继承(假设您的测试框架不需要您从特定类继承)。例如,使用 NUnit :

[TestFixture]
public class SessionTest : Session
{
    public SessionTest()
        : base() // call protected constructor
    {
    }

    [Test]
    public void TestSomething()
    {
    }

}

【讨论】:

  • OP 说 ctor 是内部的,不受保护。
  • @Rex - 问题的标题是受保护的,而问题本身是内部的。
【解决方案3】:

或者,作为一种解决方法,您可以创建一个继承自 Session 并公开公共构造函数的 TestSession。然后在单元测试中使用与原始 Session 对象基本相同的 TestSession。

public class TestSession : Session
{

   public TestSession() : base()
   {

   }

}

【讨论】:

    【解决方案4】:

    您想使用像 TypeMock 这样的产品,它允许您创建模拟(伪造)类的实例,如下所示:

    var myInstance = Isolate.Fake.Instance<Session>();
    // mock behavior here
    // do assertions here
    

    您也可以使用 TypeMock 创建抽象类的实例,以供记录。

    【讨论】:

    • 模拟你想测试的同一个课程对我来说没有多大意义......那么你不会测试模拟而不是课程吗?
    • @Svish,你说得对,伪造的行为没有用,但它也可以创建真实实例并解决可访问性问题:Isolate.Fake.Instance(Members.CallOriginal)。这样你就有了一个类的实际实例,而谁的构造函数是不可访问的。免责声明 - 我在 Typemock 工作。
    【解决方案5】:

    我会质疑将会话类构造函数设为内部的价值。

    通常这意味着您试图阻止其他开发人员使用您的类。也许最好传达一下应用程序的这个特定部分是如何工作的,以及为什么您只想从会话管理器访问会话?

    【讨论】:

    • 我已经看到它在工厂模型中做了很多工作,您可能希望强制该类只在一个地方创建或销毁,但允许其他人引用它并使用它。
    • 我也见过很多 :) 我只是不明白它是如何增加任何价值的。当你想要扩展或测试时,它只会引起问题——就像伦纳德现在正在经历的那样。 MS 在这方面是最严重的违规者之一,有很多内部类有时会很有用,但我们就是无法访问它们!令人沮丧!
    • 作为一个曾经是 API 消费者的人,并且非常沮丧,就像你想知道为什么 MS 在内部、受保护等方面做这么多东西一样。现在我主要做 API 开发,我的东西被其他开发商。我花了很多时间清理别人的烂摊子,因为他们在使用我应该在内部制作的东西时遇到了麻烦。有时,期望能够传达“正确”使用我们编写的每一段代码是不现实的。
    • 另一种看待它的方式是通过将某些东西公开/虚拟/不密封,我明确地与每个接触该类的人签订了合同 - “这是可扩展的并且可以正常工作。”我必须采取许多额外的步骤来确保这是我可以做到的——这并不总是具有成本效益。因此,当无法做出保证时,它会保持内部/密封。
    • 很公平,尽管对于大多数不编写 API 的开发人员来说,我认为我的观点仍然成立。
    【解决方案6】:

    如果您可以使用“受保护的内部”构造函数离开,那么,假设您的测试在不同的程序集中,您可以将 InternalsVisibleTo 属性添加到您的“待测试程序集”。这将允许您的测试看到“待测试程序集”的内部成员。

    更新 出于某种原因,我读到您的构造函数受到保护。它已经是内部的,因此您可以很好地使用该属性。

    【讨论】:

      【解决方案7】:

      .Net Core可以修改.csproj

      ...
      <ItemGroup>
          <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
              <_Parameter1>$(AssemblyName).Tests</_Parameter1>
          </AssemblyAttribute>
      </ItemGroup>
      ...
      

      它将使您的测试项目的内部内容可见。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-12-03
        • 2012-06-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-26
        • 1970-01-01
        相关资源
        最近更新 更多