使用与代码不同的语言编写单元测试的(不利)优点是什么?

10

单元测试与生产代码有不同的要求。例如,单元测试可能不需要像生产代码一样具有高性能。

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

在我看来,使用IronPython和IronRuby编写测试语言比C#代码具有以下几个优点:

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

在使用两种不同的语言来编写测试和生产代码时,有哪些权衡之处?

10个回答

11

我想到的缺点有:

  • 根据语言的不同,你需要另一个开发环境(作为项目的附加依赖项,设置开发机器需要额外的努力,需要额外的许可证和培训等)。
  • 重构有时候可以由IDE自动支持,但很可能不支持其他语言。所以你必须手动重构。
  • 单元测试也可以作为编程示例使用。测试显示被测试的类应该如何使用。如果测试是用另一种语言编写的,则这种方法效果不佳。

2
将测试用例作为编程示例是一个好方法,也是检验代码可用性的绝佳方式。另一方面,你可以认为在VB.Net中编写针对C# API的测试套件可以测试该API在其他语言中的可用性。 - Mathias

7

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

另一个问题是任何想要开发您的代码库的人都必须了解这两种语言。


2
这在VS2010中使用C#和F#非常透明;调试器会像你预期的那样在源代码之间移动。至于其他语言,我无法发表评论。 - mqp
3
我曾维护过一个VB.net/C#混合解决方案-调试器运作良好,但是你的头脑并不总是那么灵活。 - Paddy

3
我非常喜欢铁系语言,但是在使用它们来测试静态编译代码时存在显著的缺点。使用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#的测试故事并不好。

如果我的理解有误,我很乐意接受纠正。 =)


我认为这个例子有点不公平:你正在比较使用模拟框架的代码与开放式模拟的代码。我非常确定,如果在两种情况下都采用相同的方法(即在C#中不使用Moq或在Ruby中使用Moq),差异会小得多。 - Jörg W Mittag
这是一个公正的评论,但据我所知,依赖于Linq表达式的库在Iron语言中是无法使用的。再次强调,我很乐意被证明是错误的。
  • http://rubyforge.org/pipermail/ironruby-core/2009-May/004536.html
- Ray Vernagus

2

我认为主要缺点是维护性。如果你使用C#编码,你的开发团队应该熟练掌握这种语言,新员工也应如此。你需要一个多功能的开发团队。

我认为还值得注意的是,你可能不希望人们用一种可能不是他们最擅长的语言编写测试。你的测试代码需要很强的鲁棒性。

在编写代码/测试时,你还需要在不同的语法之间切换-这有点麻烦。


2
我认为这是一个非常好的问题和值得考虑的想法 - 特别是在像Visual Studio/.NET这样的环境中,它很容易支持。
正面的方面 - 正如您所建议的那样 - 是您可以选择使用一种更适合创建测试的语言/工具,而不是您用于创建代码的语言。仅出于这个原因,它就值得一试。
负面的方面是,正如所建议的那样,你的开发人员 - 那些创建测试的人(我们必须记住不要混淆单元测试和测试驱动设计)可能应该能够流利地使用多种语言(我建议这种能力对于一个好的开发人员来说相当重要,但我有偏见!) - 更重要的是,你可能需要担心两者之间的结构差异(尽管如果你谈论的是.NET语言,那么这应该已经为你解决了)。
如果你超越“单元”测试到所有级别的测试,那么使用特定语言的特定能力可能会在建立测试案例方面带来优势。
最终问题是优点是否大于缺点......这可能有点具体情况具体分析。

1

最大的折衷是,如果有人想使用单元测试来确定某个操作的执行方式,用不同的语言编写会使其更难使用。此外,您还需要使您的C#代码符合CLS规范。


1
在构建API或库时,我经常将单元测试作为文档的一种形式,以说明如何最好地使用API或库。大部分时间,我构建的是一个C#库,我交付给的客户将会用C#代码来使用这个库。
出于文档的目的,至少有一部分我的测试总是会用目标语言编写。

1
最大的缺点是你也在单元测试中测试编译器依赖项。从某种意义上说,这也使它们成为集成测试。如果您希望代码可用于多种语言,则可能会使它们更可取,但这增加了一个您不需要的复杂性级别,如果您的代码只会在开发语言中使用,则可能不需要。
我能看到的一个优点是它进一步隔离正在开发的代码与测试本身。通过进一步将编写测试的行为与实际开发的代码分离,它迫使您真正考虑如何编写代码以通过测试,而不仅仅是将代码的初始开发移动到测试中。

1

我同意其他答案中提到的缺点,但我很惊讶为什么这么少有人谈论优点。

  • 跨语言进行TDD是学习新语言的好方法:用你熟悉的语言编写测试,用你正在学习的语言编写实现。当你学习时,你会发现比最初更好的编写代码的方法,但重构很容易,因为你有一个测试套件。
  • 必须掌握多种语言可以使你(和你的团队)保持敏锐。
  • 您可以获得更好的验证,以确保您的API在各种语言之间具有互操作性。

0

经验 1

在过去的一年中,我参与了一个由两个主要部分组成的项目:

  1. 一个 Grails Web 应用程序
  2. 和一个 Java Swing 应用程序

我们使用 Groovy 编写了 Java 单元测试,并且效果很好。使用 Groovy 进行单元测试在冗长度方面节省了很多时间,也使得伪造静态方法等操作成为可能。虽然有几个地方由于 Groovy 的动态类型而导致了意外结果,但总体来说这是一次积极的经历。

经验 2

我最近参与的另一个项目是一个 C# ASP.NET MVC 3 Web 应用程序,我使用 F# 编写了所有的单元测试。我选择 C# 作为 Web 应用程序的开发语言,因为我觉得它更适合 MVC 3。我选择 F# 作为单元测试的语言,因为它是我最喜欢的语言。我遇到的唯一问题是关于类型的小烦恼,比如 nulloption

结论

当我们有两种针对相同运行时的语言(C# / F# 和 Java / Groovy 在 CLR 和 JRE 上分别)其中一种用于生产代码,另一种用于单元测试时,至少在兼容性方面没有太多需要担心的问题。然后我认为这实际上是一个问题,即您和您的团队是否足够熟悉这两种语言(我想您可能也会考虑未来的维护者)。事实上,我认为您被迫使用不同的语言进行单元测试的时间是当单元测试语言实际上是您舒适或选择的语言而不是您的生产语言时。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接