(用不同语言编写单元测试代码的缺点是什么?

时间:2009-11-13 15:09:39

标签: c# .net unit-testing ironpython

单元测试与生产代码有不同的要求。例如,单元测试可能不必像生产代码那样高效。

或许有时候用更适合编写单元测试的语言编写单元测试有意义吗?我想到的具体示例是使用C#编写应用程序,但使用IronRuby或IronPython编写测试。

正如我所看到的,使用IronPython和IronRuby比C#代码作为测试语言有几个优点:

  • 动态类型语言中的模拟可以更简单
  • IronPython具有较少的详细类型注释,在单元测试中不需要
  • 通过在解释器中键入命令,无需重新编译即可实验性地调用测试

在测试和生产代码中使用两种不同语言的权衡是什么?

10 个答案:

答案 0 :(得分:11)

我想到的缺点:

  • 根据语言的不同,您需要另一个开发环境(项目的额外依赖性,设置开发机器的额外工作量,额外的许可证,额外的培训......)
  • IDE有时支持
  • 重构 - 但很可能不支持其他语言。所以你必须手动重构它们。
  • 单元测试也可用作编程示例。测试显示了如何使用测试类。如果测试用不同的语言编写,这种方法效果不佳。

答案 1 :(得分:7)

一个明显的潜在问题是令人困惑的调试体验。我个人并没有尝试在.NET中跨语言进行调试 - 如果你从IronPython进入C#代码会发生什么?

另一个问题是,任何想要在代码库上开发的人都必须知道这两种语言。

答案 2 :(得分:3)

我是Iron语言的忠实粉丝,但使用它们测试静态编译的代码存在明显的缺点。使用Ruby / Python测试Ruby / Python效果很好,即您可以通过多种方式伪造对象。但是使用Ruby / Python测试C#会导致比所希望的更复杂。

考虑一个您正在编写ASP MVC项目的场景,您希望伪造出向控制器发出请求的浏览器类型。在C#中,你可以像这样模拟它(使用Moq):

var fakeRequest = new Moq.Mock<System.Web.HttpRequestBase>();
fakeRequest.Setup(request => request.Browser.Type).Returns("Fake");

在IronRuby中,它看起来像这样:

class FakeBrowser < HttpBrowserCapabilitiesBase
  def type
    "Fake"
  end
end

class FakeRequest < HttpRequestBase
  def browser
    FakeBrowser.new
  end
end

需要伪造的背景越深,它就越复杂。在C#中,模拟框架会自动为您执行子类型操作,但是在动态语言中,您将会有很多工作要做。像PyMock或Mocha这样的模拟库不能用于这样的测试,因为测试中的代码具有强大的类型依赖性,而Ruby / Python框架生成的虚假对象将不符合这些依赖项。随着IronRuby和IronPython的成熟,我希望看到情况有所改善,但现在测试C#的故事并不是那么好。

如果我认为这是错误的,我很乐意纠正。 =)

答案 3 :(得分:2)

我认为它的主要缺点是可维护性。如果您使用C#编写代码,那么您的开发团队就能胜任该语言,新员工也是如此。你需要一个多功能的开发团队。

我认为值得注意的是,您可能不希望人们用可能不是最强的语言编写测试。您的测试代码需要健壮。

您还需要在编写代码/测试时切换语法 - 这有点令人讨厌。

答案 4 :(得分:2)

我认为这是一个很好的问题和一个值得考虑的想法 - 特别是在像Visual Studio / .NET这样容易支持的环境中

正如你所建议的那样,优点是你可以选择使用一种语言/工具来创建更适合创建测试的测试,而不是用于创建代码的代码,仅此一点,它值得一个思想。

正如建议的那样,缺点是您的开发人员 - 那些创建测试的人(我们必须记住不要将单元测试与测试驱动设计混淆)可能应该能够流利使用多种语言(我建议对于一个优秀的开发人员来说,这样做的能力是相当重要的,但我有偏见!) - 更重要的是,您可能不得不担心两者之间的结构差异(尽管如果您正在谈论.NET语言应该如此为你承保。)

如果您超越“单元”测试,在各个级别的测试中,特定语言的特定功能可能有助于构建测试用例,那么它会变得更加有趣。

最终的问题是优势是否超过了劣势......这可能在某种程度上与案例有关。

答案 5 :(得分:1)

最大的权衡是,如果某人正在考虑使用单元测试来确定如何执行某项操作,那么用不同的语言编写会使其更难使用。此外,您必须使您的C#代码符合CLS。

答案 6 :(得分:1)

在构建API或库时,我经常提供单元测试作为最佳使用API​​或库的文档形式。大多数时候我构建了一个C#库,我正在交付一个客户端,他将编写C#代码来使用该库。

为了便于记录,至少我的一些测试将始终用目标语言编写。

答案 7 :(得分:1)

最大的缺点是您还在单元测试中测试编译器依赖项。从某种意义上说,这也使它们成为集成测试。如果您希望您的代码可以从多种语言中使用,那么这可能会使它们更受欢迎,但如果您的代码仅在生产中使用它所开发的语言,那么它会增加一些您可能不需要的复杂性。

我可以看到的一个优点是它进一步隔离了从测试本身开发的代码。通过将编写测试的行为与开发中的实际代码分开,它迫使您真正考虑如何编写代码以通过测试,而不是简单地将代码的初始开发移动到测试本身。

答案 8 :(得分:1)

我同意其他有缺点的答案,但我很惊讶很少有人谈到优势。

  • 跨语言的TDD是学习新语言的好方法:用你熟悉的语言编写测试,并用你正在学习的语言实现。在您学习的过程中,您会发现编写代码的方式比您最初的方法更好,但重构很容易,因为您有一个测试套件。
  • 掌握多种语言可以让你(和你的团队)保持敏锐。
  • 您可以更好地验证您的API可以跨语言进行互操作。

答案 9 :(得分:0)

经验1

在过去的一年里,我参与了一个有两个主要部分的项目:

  1. Grails Web应用程序
  2. 和Java Swing应用程序
  3. 我们使用Groovy编写了Java单元测试,结果很好。使用groovy的单元测试花费了更少的冗长时间,并且还可以伪造静态方法等等。虽然有几个地方由于Groovy的动态类型而遇到了意想不到的结果,但总的来说这是一种积极的体验。

    经验2

    我最近的另一个项目是一个C#ASP.NET MVC 3 Web应用程序,我用F#编写了所有单元测试。我为网络应用程序选择了C#,因为我认为它在MVC 3中效果更好。我选择F#进行单元测试,因为它是我最喜欢的语言。我遇到的唯一问题是对nulloption等类型的轻微烦恼。

    结论

    当我们有两种语言针对相同的运行时(分别是CL#和JRE上的C#/ F#和Java / Groovy),其中一种用于生产代码,一种用于单元测试,没有太多担心关于兼容性至少。然后我认为这是一个问题,你和你的团队是否在这两种语言中都感觉足够舒服(我想你也可以考虑未来的维护者)。实际上,我认为你被迫使用不同语言进行单元测试的时候,单元测试语言实际上是你的生产语言的舒适或选择语言。

    我承认这种自由态度有一些例外。如果您正在设计一个由语言X使用的库,那么用X语言编写单元测试可能是个明智之举(至少有一些)。但对于应用程序代码,我从未发现使用与生产代码相同的语言编写单元测试特别有利。