您是否将单元测试放在同一个项目或其他项目中?

时间:2008-12-07 02:56:37

标签: c# unit-testing

为方便起见,您是否将单元测试放在同一个项目中,还是将它们放在单独的程序集中?

如果您像我们一样将它们放在一个单独的程序集中,我们最终会在解决方案中添加一些额外的项目。这对于编码时的单元测试很有用,但是如果没有所有这些额外的组件,你如何发布应用程序呢?

16 个答案:

答案 0 :(得分:104)

单独的项目,但在同一解决方案中。 (我曾经为测试和生产代码提供单独的解决方案 - 这太可怕了。你总是在两者之间切换。)

单独项目的原因如其他人所述。请注意,如果您正在使用数据驱动的测试,那么如果将测试包含在生产程序集中,则可能会导致相当大的膨胀。

如果您需要访问生产代码的内部成员,请使用InternalsVisibleTo

答案 1 :(得分:91)

在我看来,单元测试应该放在与生产代码不同的组件中。以下是与生产代码相同的装配或装配中放置单元测试的一些缺点:

  1. 单元测试附带生产代码。产品代码附带的唯一产品是生产代码。
  2. 单位测试会使装配体不必要地膨胀。
  3. 单元测试可能会影响自动或连续构建等构建过程。
  4. 我真的不知道任何专业人士。有一个额外的项目(或10)不是一个骗局。

    编辑:有关构建和发送的更多信息

    我还建议任何自动构建过程将生产和单元测试放到不同的位置。理想情况下,单元测试构建过程仅在生成代码构建时运行,并将产品文件复制到单元测试目录中。这样做会导致实际的比特被分开以便运送等。此外,在特定目录中的所有测试中此时运行自动单元测试是相当简单的。

    总结一下,以下是每日构建和测试以及位和其他文件传输的一般概念:

    1. 生产构建运行,将生产文件放入特定的“生产”目录。
      1. 仅建立生产项目。
      2. 将编译的位和其他文件复制到“生产”目录中。
      3. 将位和其他文件复制到发布候选目录中,即圣诞节发布目录中的“Release20081225”。
    2. 如果生产构建成功,则运行单元测试构建。
      1. 将生产代码复制到“tests”目录。
      2. 构建单元测试以“测试”目录。
      3. 运行单元测试。
    3. 向开发人员发送构建通知和单元测试结果。
    4. 当接受发布候选版本(如Release20081225)时,请运送这些位。

答案 2 :(得分:65)

我不理解经常反对使用生产代码部署测试。我领导了一个小团队(从14人增加到130人)。我们有六个左右的Java应用程序,我们发现它非常有价值,可以将测试部署到现场,以便在显示异常行为的特定机器上执行它们。在现场发生随机问题,能够以零成本投入数千个单元测试是非常宝贵的,并且经常在几分钟内诊断出问题......包括安装问题,片状RAM问题,机器特定问题,网络问题,我认为将测试带入现场是非常有价值的。此外,随机时间会出现随机问题,让位于那里的单元测试已经等待立即执行,这很好。硬盘空间很便宜。就像我们试图将数据和函数保持在一起一样(OO设计),我认为在将代码和测试保持在一起(功能+测试验证函数)方面有一些根本性的价值。

我想将我的测试放在C#/ .NET / Visual Studio 2008中的同一个项目中,但我仍然没有调查过这个实现它的想法。

将Foo.cs保存在与FooTest.cs相同的项目中的一大好处是,当一个类缺少兄弟测试时,开发人员会不断被提醒!这鼓励了更好的测试驱动编码实践......漏洞更加明显。

答案 3 :(得分:13)

将单元测试放在与代码相同的项目中,以实现更好的封装。

您可以轻松地测试内部方法,这意味着您不会公开应该是内部的方法。

让单元测试接近你正在编写的代码真的很不错。编写方法时,您可以轻松找到相应的单元测试,因为它位于同一个项目中。当你构建一个包含unitTests的程序集时,unitTest中的任何错误都会给你一个compilereerror,所以你必须保持你的unittest是最新的,只是为了构建。在单独的项目中进行单元测试可能会导致一些开发人员忘记构建单元测试项目,并且暂时缺少破坏的测试。

您可以使用编译标签(I​​F #Debug)从生产代码中删除单元测试。

自动集成测试(由NUnit制作)应该在一个单独的项目中,因为它们不属于任何单个项目。

答案 4 :(得分:10)

我的单元测试总是在一个单独的项目中进行。事实上,对于我在我的解决方案中的每个项目,都有一个独立的测试项目。测试代码不是应用程序代码,不应与其混合。将它们保存在单独的项目中的一个优点 - 至少使用TestDriven.Net - 是我可以右键单击测试项目并运行该项目中的所有测试,只需单击一下即可测试整个应用程序代码库。 / p>

答案 5 :(得分:7)

如果使用NUnit框架,则还有另外的理由将测试放在同一个项目中。 请考虑以下与单元测试混合的生产代码示例:

public static class Ext
{
     [TestCase(1.1, Result = 1)]
     [TestCase(0.9, Result = 1)]
     public static int ToRoundedInt(this double d)
     {
         return (int) Math.Round(d);
     }
}

此处的单元测试用作所测试代码的文档和规范。我不知道如何实现自我记录的这种效果,测试位于一个单独的项目中。该函数的用户必须搜索测试以查看这些测试用例,这是不太可能的。

更新:我知道TestCase属性的这种用法并不是NUnit的开发者所希望的,但为什么不呢?

答案 6 :(得分:3)

我在同一个项目和不同项目之间波动。

如果你发布一个库,用生产代码发布测试代码是一个问题,否则我发现它通常不是(虽然在你尝试之前有一个强大的心理障碍)。

将测试放在同一个项目中时,我发现在测试和测试的代码之间切换更容易,并且更容易重构/移动它们。

答案 7 :(得分:3)

我把它们放在不同的项目中。程序集的名称反映了名称空间的名称,这是我们的一般规则。因此,如果存在名为Company.Product.Feature.sln的项目,则它具有Company.Product.Feature.dll的输出(程序集名称)。测试项目是Company.Product.Feature.Tests.sln,产生了Company.Product.Feature.Tests.dll。

您最好将它们保存在单个解决方案中,并通过Configuration Manager控制输出。我们为每个主要分支(开发,集成,生产)命名配置,而不是使用默认的Debug和Release。完成配置设置后,可以通过单击Configuration Manager中的“Build”复选框来包含或排除它们。 (要获取配置管理器,请右键单击解决方案并转至Configuration Manager。)请注意,我发现Visual Studio中的CM有时会出错。有几次,我不得不进入项目和/或解决方案文件来清理它创建的目标。

此外,如果您正在使用Team Build(我确信其他.NET构建工具是相同的),您可以将构建与命名配置相关联。这意味着,如果您没有为“生产”构建构建单元测试,例如,构建项目也可以知道此设置,而不是构建它们,因为它们被标记为这样。

此外,我们过去常常从构建机器上执行XCopy。该脚本只会省略复制任何名为* .Tests.Dll的内容。这很简单,但很有效。

答案 8 :(得分:1)

我会说让他们分开。

除了上面提到的其他原因之外,将代码和测试放在一起会使测试覆盖率数字偏差。当您报告单元测试覆盖率时 - 报告的覆盖率更高,因为在运行单元测试时会涵盖测试。报告集成测试覆盖率时,报告的覆盖率较低,因为集成测试不会运行单元测试。

答案 9 :(得分:1)

在TypeScript项目中花费了一些时间后,通常将测试与测试代码一起放在文件中,我变得更喜欢这种方法,而不是将它们分开:

  • 导航到测试文件更快。
  • 重命名要测试的类时,更容易记住重命名测试。
  • 移动测试的类时,记住移动测试比较容易。
  • 如果一个类缺少测试,这是显而易见的。
  • 您不需要管理两个重复的文件结构,一个用于测试,一个用于代码。

因此,当我最近开始一个新的.NET Core项目时,我想看看是否有可能在C#项目中模仿这种结构,而不用随最终版本一起交付测试或测试程序集。

到目前为止,在项目文件中添加以下行似乎运行良好:

  <ItemGroup Condition="'$(Configuration)' == 'Release'">
    <Compile Remove="**\*.Tests.cs" />
  </ItemGroup>
  <ItemGroup Condition="'$(Configuration)' != 'Release'">
    <PackageReference Include="nunit" Version="3.11.0" />
    <PackageReference Include="NUnit3TestAdapter" Version="3.12.0" />
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
  </ItemGroup>

以上内容可确保在Release配置中,所有名为*.Tests.cs的文件都不会被编译,并且确保删除了必需的单元测试包引用。

如果您仍然希望在其发布配置中对类进行单元测试,则可以创建一个从Release派生的新配置,称为ReleaseContainingTests

答案 10 :(得分:0)

我真的受到Robert Lopez的Flood NN library单元测试框架的启发。它为每个单元测试类使用不同的项目,并有一个解决方案来保存所有这些项目,以及一个编译和运行所有测试的主项目。

整洁的东西也是项目的布局。源文件位于文件夹中,但VS项目的文件夹如下所示。这允许您为不同的编译器创建不同的子文件夹。所有VS项目都附带代码,因此任何人都可以轻松运行任何或所有单元测试。

答案 11 :(得分:0)

我知道这是一个非常古老的问题,但我想在那里添加我的经验,我最近将单元测试习惯从单独的项目改为同一个项目。

为什么?

首先,我倾向于将主项目文件夹结构与测试项目保持一致。所以,如果我在Providers > DataProvider > SqlDataProvider.cs下有一个文件,那么我在我的单元测试项目中创建相同的结构,如Providers > DataProvider > SqlDataProvider.Tests.cs

但是在项目变得越来越大之后,一旦你将文件从一个文件夹移动到另一个文件夹,或者从一个项目移动到另一个项目,那么将它们与单元测试项目同步就变得非常麻烦。

其次,从要测试的类导航到单元测试类并不总是很容易。这对JavaScript和Python来说更难。

最近,我开始练习,我创建的每个文件(例如SqlDataProvider.cs)我正在使用Test后缀创建另一个文件,例如SqlDataProvider.Tests.cs

一开始它似乎会膨胀文件和库引用,但从长远来看,你会乍看之下消除移动文件综合症,而且你也会确保那些被测试的候选人的每一个文件都会有带有.Tests后缀的配对文件。它使您可以轻松跳转到测试文件(因为它是并排的),而不是通过单独的项目查看。

您甚至可以编写业务规则来扫描项目并识别没有.Tests文件的类,并将其报告给所有者。您也可以轻松告诉您的测试运行员定位.Tests类。

特别是对于Js和Python,您不需要从不同的路径导入引用,您只需使用相同的目标文件路径进行测试。

我正在使用这种做法一段时间,我认为在项目规模与可维护性和项目新进入者的学习曲线之间进行非常合理的权衡。

答案 12 :(得分:0)

正如其他人回答的那样-在单独的项目中进行测试

尚未提及的一件事是,您实际上无法对nunit3-console.exe文件以外的任何文件运行.dll

如果您打算通过TeamCity运行测试,则会带来问题。

假设您有一个控制台应用程序项目。编译时,它会将可执行文件.exe返回到bin文件夹。

nunit3-console.exe中,您将无法运行在该控制台应用程序中定义的任何测试。

换句话说,控制台应用程序返回exe文件,而类库返回dll文件。

我今天刚被这个咬住了,很烂:(

答案 13 :(得分:0)

我最近一直在docker中进行部署。当Dockerfile可以轻松复制/ src目录并离开/ test目录时,我看不到拥有单独项目的价值。 但是我是dotnet的新手,可能会缺少一些东西。

答案 14 :(得分:-2)

单独的项目,虽然我与自己辩论是否应该共享相同的svn。目前,我给他们单独的svn存储库,一个名为

“MyProject” - 项目本身

和一个叫

“MyProjectTests” - 用于与MyProject相关的测试。

这是相当干净的,并且具有提交到项目并且提交测试的优点是完全独立的。这也意味着您可以根据需要移交项目的svn,而无需发布测试。它还意味着您可以为测试和项目提供分支/主干/标记目录。

但我越来越倾向于在单个svn存储库中为每个项目提供类似以下的内容。

MyProject
|\Trunk
| |\Code
|  \Tests
|\Tags
| |\0.1
| | |\Code
| |  \Tests
|  \0.2
|   |\Code
|    \Tests
\Branches
  \MyFork
   |\Code
    \Test

我很想知道其他人对此解决方案的看法。

答案 15 :(得分:-3)

<块引用>

为了方便起见,您将单元测试放在同一个项目中还是将它们放在单独的程序集中?

不,永远不要那样做。您的组件的使用者无法将您的测试代码与您的生产代码分开,因此,他们无法将其用于任何重要的事情。

从具有安全意识的消费者的角度来看,您程序集中的每个公共符号都是您客户产品的攻击面区域的一部分。他们为什么要使用包含任何非生产安全表面区域的程序集?

如果您认为在生产装配中包括单元测试是可以的,那就太丢脸了!

如果您接受此类组件以包含在您的产品中,那您将感到羞耻。


可以发布您的测试程序集吗?当然是,而且我认为这是最佳实践。它们可以为客户支持提供很大帮助,您的客户可能还希望将它们合并到他们自己的测试环境中。只是不要将您的测试位强加给您的客户。