【问题标题】:Unit testing code that uses a Singleton使用单例的单元测试代码
【发布时间】:2015-03-06 22:34:02
【问题描述】:

我有使用单例的代码(这恰好是针对网站的,所以单例的范围只有一个请求;每个请求都有自己的单例)。

我的代码(恰好位于 HttpModule 中)执行以下操作:

1 - 检查 Singleton 对象是否为空,如果是,则对其进行初始化。 2 - 按照以下方式更新此单例对象的属性:

if(A)
{
    SingletonHolder.Current.X = Y;
}
else
{
    SingletonHolder.Current.X = Z;
}

然后我想围绕这个方法进行一些单元测试来检查逻辑是否正确。假设我们需要以下 4 个测试:

  1. GivenMethodCall_WhenA_ThenXSetToY
  2. GivenMethodCall_WhenA_ThenXNotSetToZ
  3. GivenMethodCall_WhenNotA_ThenXSetToZ
  4. GivenMethodCall_WhenNotA_ThenXNotSetToY

这些测试在一次运行一个时运行良好,但是当在 VS2013 中使用 NUnit 测试运行器运行时,我们会遇到一些失败,因为每个测试都是并行运行的,并且被测方法正在更新同一个单例具有不同值的对象的属性。

有什么可以解决这个问题的模式的建议吗?

谢谢

格里夫

【问题讨论】:

  • 一种使您的课程正确并发的模式。不使用单例的更好模式。无论如何,这就是您进行测试的原因
  • 是否可以选择摆脱单例?那将是最好的事情。在请求开始时创建它并将其传递给需要它的方法。
  • 我不清楚这个重要的细节:如果单例每个请求都是唯一的,为什么每个测试调用都不是唯一的?这里有什么区别?
  • 这取决于测试的结构。无论如何,我假设 OP 是独立于 ASP.Net 本身进行测试的,因此,测试不是在 HTTP 请求的上下文中运行的。因此,如果没有在每个测试方法的开头和结尾显式设置和拆除 Singleton 对象,这将是预期的行为(除非您使用的是 xUnit ;))。
  • 被测代码是 HttpApplication 的 BeginRequest 事件的 EventHandler。在这种方法中,我们创建了一个单例“上下文”类,它包含我们网页中的代码可能需要的所有内容(因此,站点、客户、缓存、跟踪器等信息)。丹尼尔,我很抱歉,我错了,Singleton 当然适用于 AppDomain 中的所有内容 - 我将自己与 HttpApplication 上的 Items Collection 混淆了(根据请求)。也许我需要在不同的 AppDomains 中运行每个测试(或者这有点过头了?)。

标签: unit-testing tdd automated-tests integration-testing


【解决方案1】:

您可能只需要在测试夹具中提供一个用SetUpAttribute 方法装饰的方法来执行初始设置每个测试方法运行之前,另一个用TearDownAttribute 装饰的方法运行每个测试方法之后。 nUnit SetUpAttribute 的文档位于 here

这将允许您(在您的 SetUp 方法中)初始化您的 Singleton 对象,然后(在您的 TearDown 方法中)将您的 Singleton 对象设置为 null 以便 SetUp 可以重新实例化/初始化该对象以供下一次使用测试。

【讨论】:

  • 不确定这会有什么帮助。如果所有测试并行运行,那么每个测试的设置将一起运行,每个测试都尝试设置相同的单例。各个测试将一起运行并更新此单例,导致某些测试的 Asserts 失败,然后每个测试的 TearDown 将运行。
  • 那么这里的根本缺陷是当您有正在测试的全局静态数据时并行运行测试。连续运行测试并使用 SetUp/TearDown 方法,这个问题应该会消失。
  • 我们使用 VS2013 中的 NUnit 测试适配器来运行我们的测试,它会自动并行运行它们。我们目前对我们的应用程序进行了数千次测试,它们都在几分钟内完成。我可以设想在这个领域进行数百次测试,所以我认为如果可能的话,我更愿意让这些测试并行运行。我在上面的帖子上发表了关于在不同的 AppDomains 中运行测试的评论(包括指向 StackOverflow 的链接建议这一点)。我想这可能是要走的路。对此有什么想法吗?
  • 我看不出不同的 AppDomain 会有什么影响。如果 AppDomain 中的测试并行运行,您仍然会遇到同样的问题。否则,每个单元测试方法都需要一个 AppDomain——我认为这会相当昂贵。您可以将一个选项传递给测试运行程序以禁用单元测试的并行执行——如果它对您可行的话。如果没有,那么我怀疑您将不得不像其他人所说的那样尝试使用 Singleton 对象以外的东西。
  • @DrGriff:NUnit 2.6 和 Visual Studio 的 NUnitAdapter 都不能并行运行测试。它们按顺序运行。如果您使用 Pnunit,它将并行运行,或者新的 3.0 版本。所以肯定有其他原因导致了这个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-05-15
  • 2019-07-05
  • 2012-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
相关资源
最近更新 更多