单元测试应该在哪里?

时间:2010-08-04 12:55:50

标签: unit-testing continuous-integration build-automation

我对单元测试比较陌生,而且我发现虽然很多消息来源说你应该编写单元测试,但是很少有人会说明将它们放在你的项目中的任何指示。

我见过的唯一建议是将它们与生产代码放在一起,或构建一个镜像生产代码的目录结构。我在第一种方法中看到的问题是,当你完全构建系统时,很难提取出那些测试;对于第二个,您将如何测试仅在包级别可见的功能?

是否有合适的方法来组织单元测试,以便您可以轻松地自动化构建过程并仍然可以访问需要测试的所有内容?

编辑:对于那些对某种特定语言感到疑惑的人,我主要使用的是Java。但是,我想找到一个与语言无关的解决方案,所以无论我在哪个平台上工作,我都可以应用它。

6 个答案:

答案 0 :(得分:5)

第二种方法是最好的。为测试创建并行源树。设置您的包结构相同。你没有说你正在使用什么语言,但如果它是Java,那么测试源代码树中的代码将能够很好地访问主源代码树中的代码。包中有一些来自一个源代码树的代码和一些来自另一个源代码树的代码是无关紧要的 - 生产代码和测试代码仍然在同一个包中。

答案 1 :(得分:5)

您没有指明您正在使用的平台和工具,这会对选项产生影响。我正在回答.NET和Visual Studio的观点:

我的团队(处理一个非常大的项目)成功地使用了将代码和测试放在一起的方法。对于解决方案中的给定(子)命名空间,中有一个“_Test”文件夹(子)命名空间,(“_”是让Visual Studio在其他所有内容中显示它的黑客攻击解决方案浏览器中的那个命名空间。)

我在团队中引入了TDD,并认为在测试和代码之间进行最小摩擦对于采用这种做法的成功至关重要。因此,测试总是“物理上接近”它测试的代码;你不想在一个巨大的解决方案中寻找代码和测试之间的跳转。

当你想到它时,这是有道理的。代码和测试像阴阳一样。这也意味着在修改1个程序集中的类型时只需要重建1个程序集(我们的解决方案中有超过30个项目,这样我们只有在通过TDD,方式发展类时才能安全地使用Build Current Project 比完整的解决方案构建更快。)

将代码和测试结合在一起也解决了能够测试内部类的问题。但是,在.NET平台上,如果要将内容分开,也可以使用InternalsVisibleTo Assembly-level属性来授予对单独测试程序集的访问权限。

我可以看到在单独装配中进行测试的唯一原因是避免运送该代码。但是,如果您正在使用构建自动化,那么这个方面可以通过另一种方式解决。由于Visual Studio的项目文件是XML,我们只需让构建服务器使用小型XSLT对项目文件进行预处理,以便从发布版本中的编译中剥离* / _ Test / *文件夹中的每个文件。

答案 2 :(得分:4)

  

我在第一种方法中看到的问题是,当你完整构建系统时,很难提取这些测试

您总是可以根据某些命名约定过滤类,例如打包时的特殊后缀或前缀(例如,不要在Java中包含**/*Test.class)。我不太喜欢这种方法,但我觉得它很乱,很脆弱。

  

对于第二个,您将如何测试仅在包级别可见的功能?

除非我遗漏了什么,否则我没有看到这个问题。您可以在相同的包中使用类,并让它们生活在不同的树中,例如:

  • src/main/java申请来源
    • src/main/java/foo/Bar.java
  • src/test/java用于测试来源
    • src/test/java/foo/BarTest.java

Bar.javaBarTest.java都位于相同的foo包中,但位于不同的目录中。这是我使用的方法。

  

是否有合适的方法来组织单元测试,以便您可以轻松地自动化构建过程并仍然可以访问需要测试的所有内容?

嗯,正如所暗示的那样,我的测试源应用程序源存在于相同的项目中但在 distinct 中目录树,这对我来说非常好。

这实际上是Maven建议的默认布局(参见Introduction to the Standard Directory Layout)。无论你使用什么语言,这都可能会给你一些想法。

答案 3 :(得分:1)

我建议你有一个单独的项目(或项目)进行单元测试。

在项目树上只为测试项目创建一个文件夹也是一个好主意。这样,如果您需要在没有测试的情况下构建系统,则应该在不构建测试的情况下进行构建配置,尽管构建测试并将其作为CI(持续集成)的一部分运行是一个好主意,而不仅仅是打包生产安装程序中的代码或将其复制到特定文件夹。

根据所使用的技术,可以在包级别上看到测试功能 - 例如.NET可以使用 InternalVisibleTo 属性使内部方法和类可见。您应该问自己是否需要测试该功能,不建议测试私有方法 - 因为它们往往会发生变化。

答案 4 :(得分:1)

这可能取决于您现在使用的是什么。使用visual studio / .net,通常的做法似乎是每个生产dll的测试dll,以及dll中类和测试类的模糊镜像。对于ruby / python等,一个单独的测试目录,以及一个镜像所测试内容的层次结构。

“提取”那些测试是什么意思?对于你来说,完整的构建是否涉及编译和运行测试?

包级别的可见性可能是一个问题。我想如果你的测试是在单独的包中,你只需要对直接可见的东西进行测试,但无论如何都会间接测试内部的东西。

答案 5 :(得分:1)

什么是测试,什么是应用程序?

让我们考虑测试如何适应图片......

  • 测试并不直接适用于公众所关注的任何事情 - 他们只是希望它能够运作
  • 测试适用于开发人员,通常是业务
  • 测试可以与模块处于相同的比例,但是采用二分法处理
  • 如果测试文件可以与给定封装结构中的模块并排存在,那么逻辑上 - 在分形架构中 - 测试的一小部分也必须在给定模块中的对象比例。 (想想,目录| _file | _module | _object - 其中system == component && component == system && (system == system || system == subsystem )

最后一个是传达测试本质上与模块分离,并且在逻辑上不能在每个尺度上相互补充 - 要真正理解这一点,我敦促你研究分形& 自对称类型理论类别理论

但是,特定应用程序可以大大改变您拥有的选项......

从JavaScript的角度来看,一个不可知的,甚至使用高级架构方案 - 似乎在/src中包含您的测试可能会使您的构建过程复杂化。此外,当您的src目录中存在多个,少得多的测试时,您将为其他开发人员创建不太可读的逻辑绑定。您想要保护并封装您进行测试,将其私有化给您的团队成员,而不是任何与您的应用公开互动的人。

尽管如此,根据应用程序的具体情况,沿着这条路走下去仍然是值得的 - 如果 - 你可以确保它是安全的&没有创建不必要的复杂性,或者扼杀自动化。

某些高级架构将此方法用于在离散规模上进行全面封装,但它仍可能以安全性,自动化和生产力为代价(因此业务)。

根据经验,使用行业标准的脚手架:

/app
    |-lib
    |-src
    |-test

..你可能无法出错。