Answers:
我认为,单元测试应与生产代码放在单独的程序集中。这只是将单元测试与生产代码放在相同的一个或多个组件中的一些缺点:
我真的不了解任何优点。拥有一个额外的项目(或10个项目)不是坏事。
编辑:有关构建和运输的更多信息
我还建议任何自动化的构建过程都将生产和单元测试放在不同的位置。理想情况下,仅当生成生产代码并将产品文件复制到单元测试目录中时,才运行单元测试构建过程。以这种方式进行操作会导致实际的部分被分离以便装运,等等。此外,此时在特定目录中的所有测试上运行自动化的单元测试非常简单。
总而言之,这是每日构建,测试和运送钻头和其他文件的一般思路:
#if
。可以使用CI软件脚本中的编译器命令行参数来切换此自定义符号。请参阅msdn.microsoft.com/en-us/library/4y6tbswk.aspx。
单独的项目,但是在相同的解决方案中。(我一直在为产品提供单独的测试和生产代码解决方案,这太可怕了。您总是在两者之间切换。)
其他人陈述了单独项目的原因。请注意,如果您使用的是数据驱动的测试,那么如果您将测试包含在生产程序集中,则可能会导致大量的膨胀。
如果您需要访问生产代码的内部成员,请使用InternalsVisibleTo。
[assembly:InternalsVisibleTo("UnitTestProjectName")]
到项目AssemblyInfo.cs
文件中。
我不理解经常使用生产代码部署测试的异议。我领导了一个小型微型团队(由14人增加到130人)组成的团队。我们有六个左右的Java应用程序,我们发现将测试部署到现场以在特定位置执行它们非常有价值机器表现出异常行为。现场发生了随机问题,能够以零成本进行神秘的数千次单元测试是无价的,而且通常可以在几分钟内诊断出问题……包括安装问题,不稳定的RAM问题,特定于机器的问题,不稳定的网络问题,等等。我认为将测试投入领域非常有价值。此外,随机问题会在随机时间弹出,很高兴让单元测试坐在那里已经等待一时通知。硬盘空间很便宜。就像我们试图将数据和功能保持在一起(OO设计)一样,我认为将代码和测试保持在一起(功能+验证功能的测试)从根本上是有价值的。
我想将测试放在C#/。NET / Visual Studio 2008中的同一项目中,但是我仍然没有进行足够的研究来实现它。
将Foo.cs与FooTest.cs放在同一个项目中的一大好处是,当一个类缺少同级测试时,会不断提醒开发人员!这鼓励了更好的测试驱动的编码实践……漏洞更加明显。
将单元测试与代码放在同一项目中,以实现更好的封装。
您可以轻松地测试内部方法,这意味着您不会公开应该是内部的方法。
使单元测试接近您正在编写的代码也非常好。编写方法时,因为它在同一个项目中,所以可以轻松找到相应的单元测试。当您构建包含unitTests的程序集时,unitTest中的任何错误都会给您带来编译器错误,因此您仅在构建时必须保持unittest为最新。在单独的项目中进行单元测试,可能会导致一些开发人员忘记构建unittest-project,并在一段时间内丢失了损坏的测试。
您可以使用编译标签(IF #Debug)从生产代码中删除单元测试。
自动集成测试(由NUnit制造)应该位于单独的项目中,因为它们不属于任何单个项目。
Release
版本上运行测试,并且很少会遇到“ heisenbug”。
InternalsVisibleTo
单独的测试项目测试内部方法
Debug
,Approval
和Release
; 并通过所有发行优化来编译批准。而且,通常,单元测试并不适合在一开始就检测海森氏病(以我的经验)。您可能需要针对它们的特定集成回归测试-并且您可以将它们并排放置。
在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
。
更新:使用这种技术一段时间后,我还发现在VS Code中自定义图标以使测试(及其他内容)在资源管理器窗格中更显眼很有帮助:
为此,请使用Material Icon Theme扩展并将类似以下内容添加到VS Code首选项JSON:
"material-icon-theme.files.associations": {
"*.Tests.cs": "test-jsx",
"*.Mocks.cs": "merlin",
"*.Interface.cs": "yaml",
}
我的单元测试总是放在一个单独的项目中。实际上,对于我解决方案中的每个项目,都有一个单独的测试项目。测试代码不是应用程序代码,不应与它混合在一起。将它们保存在单独的项目中(至少使用TestDriven.Net)的一个好处是,我可以右键单击一个测试项目并运行该项目中的所有测试,只需单击一下即可测试整个应用程序代码库。
如果使用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开发人员想要的,但是为什么不呢?
我把它们放在单独的项目中。作为我们的一般规则,程序集的名称反映了名称空间的名称。因此,如果有一个名为Company.Product.Feature.sln的项目,则它具有Company.Product.Feature.dll的输出(程序集名称)。测试项目是Company.Product.Feature.Tests.sln,产生Company.Product.Feature.Tests.dll。
您最好将它们保留在单个解决方案中,并通过配置管理器控制输出。我们为每个主要分支(开发,集成,生产)都有一个命名配置,以代替使用默认的Debug和Release。配置设置完成后,您可以通过单击配置管理器中的“生成”复选框来包含或排除它们。(要获取配置管理器,请右键单击解决方案,然后转到配置管理器。)请注意,我发现Visual Studio中的CM有时有问题。有几次,我不得不进入项目和/或解决方案文件来清理它创建的目标。
另外,如果您使用的是Team Build(我确信其他.NET生成工具相同),则可以将生成与命名配置相关联。这意味着,例如,如果您不为“生产”构建构建单元测试,则构建项目也可以知道此设置,并且因为已将其标记为标准而无法构建它们。
另外,我们过去经常从构建机器上删除XCopy。该脚本将仅省略复制名为* .Tests.Dll的任何内容。这很简单,但是有效。
我真的受Robert Lopez 的Flood NN库的单元测试框架的启发。它为每个单元测试类使用一个不同的项目,并拥有一个容纳所有这些项目的解决方案,以及一个编译并运行所有测试的主项目。
整洁的东西也是项目的布局。源文件位于一个文件夹中,但是VS项目的文件夹位于下面。这使您可以为不同的编译器创建不同的子文件夹。所有VS项目都附带了代码,因此任何人都可以轻松地运行任何或所有单元测试。
我知道这是一个非常老的问题,但是我想补充一下我的经验,最近我将单元测试的习惯从单独的项目更改为相同的项目。
为什么?
首先,我非常倾向于使主项目文件夹结构与测试项目相同。所以,如果我有一个文件Providers > DataProvider > SqlDataProvider.cs
那么我将在单元测试项目中创建相同的结构,例如Providers > DataProvider > SqlDataProvider.Tests.cs
但是,在项目变得越来越大之后,一旦将文件从一个文件夹移动到另一个文件夹,或从一个项目移动到另一个项目,那么将这些文件与单元测试项目同步就变得非常麻烦。
其次,从要测试的课程导航到单元测试课程并非总是很容易。对于JavaScript和Python而言,这甚至更加困难。
最近,我开始练习,我创建的每个文件(例如 SqlDataProvider.cs
)都在创建另一个带有Test后缀的文件,例如SqlDataProvider.Tests.cs
乍一看似乎会膨胀文件和库引用,但是从长远来看,您将乍一看消除移动文件综合症,并且您还可以确保,每个要测试的单个文件都会有一个配对文件。与 .Tests
后缀。它使您轻松进入测试文件(因为它是并排的),而不是浏览单独的项目。
您甚至可以编写业务规则来扫描项目,并确定没有.Tests文件的类,并将其报告给所有者。您还可以轻松地告诉测试跑步者定位.Tests
课程。
特别是对于Js和Python,您不需要从其他路径导入引用,只需使用要测试的目标文件的相同路径即可。
我使用这种做法已经有一段时间了,我认为在项目规模与可维护性以及对于项目新手的学习曲线之间的折衷是非常合理的。
单独的项目,尽管我与自己争论是否应该共享相同的svn。目前,我正在为他们提供单独的svn存储库,其中一个称为
“ MyProject”-用于项目本身
一个叫
“ MyProjectTests”-用于与MyProject关联的测试。
这是相当干净的,其优点是提交给项目和提交给测试是完全分开的。这也意味着您可以根据需要移交项目的svn,而不必发布测试。这也意味着您可以具有用于测试和项目的branch / trunk / tag目录。
但是,我越来越倾向于在每个项目的单个svn存储库中包含以下内容。
我的项目 | \ Trunk | | \代码 | \测试 | \标签 | | \ 0.1 | | | \代码 | | \测试 | \ 0.2 | | \代码 | \测试 \分支 \ MyFork | \代码 \测试
我很想知道其他人对这个解决方案的看法。