0

我正在为一些具有多个 API 版本的软件编写 API 的包装库,并且在多个平台之间同时但单独开发的许多共享调用。随着时间的推移,他们甚至已经合并平台以使用相同的代码库,只是在不同的命名空间和 *.exe 构建下。

我通过编写一个单一的代码库来做到这一点,然后通过构建配置使用预处理器指令和条件编译符号来选择性地使用某些代码进行构建。大约 90% 的代码实际上可以在版本和平台之间重用,所以这很有帮助。在被测项目端一切正常。

但是,我在使用 NUnit 和 NCrunch 对该项目进行单元测试时遇到问题。我创建了相同的构建配置来加载正确的常量并为集成测试项目创建正确的构建文件夹。但是,我注意到两个奇怪的问题:

  1. NUnit 似乎忽略了集成测试项目中的预处理器指令。例如,在下面的示例中,无论配置如何(例如 BUILD_Bar_2015=true),第一行代码总是被命中(BUILD_Foov16=true),即使在 Visual Studio 中看起来所需的行集(对应于当前配置变量) 是唯一一个活跃的:

    [TestFixture]
    public class FooBarIncApplicationTests
    {
       #if BUILD_Foov16
            public const string path = @"C:\Program Files (x86)\FooBarInc\FooV16\Foo.exe";
       #elif BUILD_Foov17
            public const string path = @"C:\Program Files (x86)\FooBarInc\FooV17\Foo.exe";
       #elif BUILD_Bar_2013
            public const string path = @"C:\Program Files (x86)\FooBarInc\Bar 2013\Bar.exe";
       #elif BUILD_Bar_2015
            public const string path = @"C:\Program Files (x86)\FooBarInc\Bar 2015\Bar.exe";
       #endif
    
       [Test]
       public void FooBarIncApplication_Initialize_New_Instance_Defaults()
       {
          using (FooBarIncApplication app = new FooBarIncApplication(path))
          {
          ...
          }
       }
    }
    
  2. 此外,似乎当我通过 NCrunch 运行测试时,它只使用与列出的第一个配置创建的构建相对应的 *.dll(例如,它总是测试为 Foo.exe v16 编译的 *.dll。

在我看来,这两个问题是相关的。我想知道 NUnit 和/或 NCrunch 是否无法处理这样的设置,或者是否有一种特殊的方式我应该处理这种独特的设置?

我更大的问题是 #2,即 NCrunch 似乎仅在从第一个配置构建的 *.dll 上运行 NUnit,这使得无法测试任何其他配置。也许这是项目依赖项的问题?(上面示例中的路径是我通过 API 与之交互的程序,而不是我的 *.dll 项目。)

4

2 回答 2

1

好的,我发现了问题所在。如果您曾经为多个 DLL 构建配置测试 NCrunch,这一点值得了解!

当 NCrunch 运行时,生成的 *.dll 和确定(并逐步执行)的代码覆盖率不受 Visual Studio 中指定的当前配置的影响。它始终由 Visual Studio 加载项目时的项目默认配置确定。这意味着为了更改测试配置,您需要修改 *.csproj 文件。

例如,我有 Foov16 和 Foov17 的配置定义,如下所示。为了将项目设置为 Foov17 以使 NCrunch 能够正常工作,必须在默认配置(第一个元素)中引用 Foov17 的配置:

<PropertyGroup>
   <Configuration Condition=" '$(Configuration)' == '' ">Debug-Foov17</Configuration>
   <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
   <ProjectGuid>{...}</ProjectGuid>
   <OutputType>Library</OutputType>
   <AppDesignerFolder>Properties</AppDesignerFolder>
   <RootNamespace>FooBarInc.API</RootNamespace>
   <AssemblyName>FooBarInc.API</AssemblyName>
   <TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
   <FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug-Foov16|AnyCPU'">
   <DebugSymbols>true</DebugSymbols>
   <OutputPath>bin\AnyCPU\Debug-Foov16\</OutputPath>
   <DefineConstants>TRACE;DEBUG;BUILD_Foov16</DefineConstants>
   <DebugType>full</DebugType>
   <PlatformTarget>AnyCPU</PlatformTarget>
   <ErrorReport>prompt</ErrorReport>
   <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
   <DocumentationFile>bin\AnyCPU\Debug-Foov16\FooBarInc.API.XML</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug-Foov17|AnyCPU'">
   <DebugSymbols>true</DebugSymbols>
   <OutputPath>bin\AnyCPU\Debug-Foov17\</OutputPath>
   <DefineConstants>TRACE;DEBUG;BUILD_Foov17</DefineConstants>
   <DebugType>full</DebugType>
   <PlatformTarget>AnyCPU</PlatformTarget>
   <ErrorReport>prompt</ErrorReport
   <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
   <DocumentationFile>bin\AnyCPU\Debug-Foov17\FooBarInc.API.XML</DocumentationFile>
</PropertyGroup>
于 2017-10-18T00:34:32.547 回答
0

不确定这是否对您有帮助。如果我理解正确,您想在测试用例中注入不同的 exe 路径,并让测试用例为每个 exe 路径运行。您可以尝试为此使用NUnits TestCase属性。来自 NUnit 网站的示例:

   [TestCase(12,3,4)]
   [TestCase(12,2,6)]
   [TestCase(12,4,3)]
   public void DivideTest(int n, int d, int q)
   {
     Assert.AreEqual( q, n / d );
   }

基于此,您可以将测试重写为:

[TestCase(@"C:\Program Files (x86)\FooBarInc\FooV16\Foo.exe")]
[TestCase(@"C:\Program Files (x86)\FooBarInc\FooV17\Foo.exe")]
public void FooBarIncApplication_Initialize_New_Instance_Defaults(string path)
{
    using (FooBarIncApplicatio app = new FooBarIncApplicatio(path))
    {
    ...
    }
 }

基于此,测试用例将使用 exe 的版本 16 和版本 17 运行。额外的好处:您不必切换 VS 配置来运行所有测试。

如果您仍想使用条件测试用例执行,您可以使用CategorySystem.Diagnostics.Conditional属性。有关其他信息,请参阅此stackoverflow 链接

希望有帮助。

于 2017-10-17T05:57:29.200 回答