使用 .NET CLI 组织和测试项目

本教程遵循 教程:使用 Visual Studio Code 使用 .NET 创建控制台应用程序,使你超越创建简单的控制台应用来开发高级且组织良好的应用程序。 演示如何使用文件夹来组织代码后,本教程介绍如何使用 xUnit 测试框架扩展控制台应用程序。

注释

本教程建议将应用程序项目和测试项目放置在单独的文件夹中。 一些开发人员更喜欢将这些项目保留在同一文件夹中。 有关详细信息,请参阅 GitHub 问题 dotnet/docs #26395

使用文件夹整理代码

如果要将新类型引入控制台应用中,可以通过向应用添加包含类型的文件来执行此作。 例如,如果将包含 AccountInformationMonthlyReportRecords 类型的文件添加到项目,则项目文件结构是平面的且易于导航:

/MyProject
|__AccountInformation.cs
|__MonthlyReportRecords.cs
|__MyProject.csproj
|__Program.cs

但是,仅在项目规模相对较小时,此平面结构才适用。 你能想象向项目添加 20 种类型会发生什么情况? 项目绝对不容易导航和维护,许多文件会散落项目的根目录。

若要组织项目,请创建一个新文件夹并将其命名为 “模型 ”以保存类型文件。 将类型文件放入 Models 文件夹中:

/MyProject
|__/Models
   |__AccountInformation.cs
   |__MonthlyReportRecords.cs
|__MyProject.csproj
|__Program.cs

逻辑上将文件分组到文件夹中的项目易于导航和维护。 在下一部分中,你将创建一个更复杂的示例,其中包含文件夹和单元测试。

使用 NewTypes 宠物样本进行组织和测试

先决条件

生成示例

对于以下步骤,您可以使用 NewTypes 宠物示例 来跟随操作,也可以创建自己的文件和文件夹。 这些类型在逻辑上组织成一个文件夹结构,允许以后添加更多类型,并且测试在逻辑上也放置在允许以后添加更多测试的文件夹中。

该示例包含两种类型,DogCat,并且它们都实现了一个通用接口 IPetNewTypes对于项目,目标是将宠物相关类型组织到 Pet 文件夹中。 如果稍后添加另一组类型,则 WildAnimals 例如,它们将放置在 NewTypes 文件夹中,并放在 “宠物 ”文件夹旁边。 WildAnimals 文件夹可能包含不属于宠物的动物的类型,例如SquirrelRabbit类型。 通过这种方式,当添加类型时,项目依然保持良好组织。

创建以下文件夹结构,其中包含指示的文件内容:

/NewTypes
|__/src
   |__/NewTypes
      |__/Pets
         |__Dog.cs
         |__Cat.cs
         |__IPet.cs
      |__Program.cs
      |__NewTypes.csproj

IPet.cs

using System;

namespace Pets
{
    public interface IPet
    {
        string TalkToOwner();
    }
}

Dog.cs

using System;

namespace Pets
{
    public class Dog : IPet
    {
        public string TalkToOwner() => "Woof!";
    }
}

Cat.cs

using System;

namespace Pets
{
    public class Cat : IPet
    {
        public string TalkToOwner() => "Meow!";
    }
}

Program.cs

using System;
using Pets;
using System.Collections.Generic;

namespace ConsoleApplication
{
    public class Program
    {
        public static void Main(string[] args)
        {
            List<IPet> pets = new List<IPet>
            {
                new Dog(),
                new Cat()
            };

            foreach (var pet in pets)
            {
                Console.WriteLine(pet.TalkToOwner());
            }
        }
    }
}

NewTypes.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>

请执行以下命令:

dotnet run

获取以下输出:

Woof!
Meow!

可选练习:您可以通过扩展此项目来添加新的宠物类型,例如添加一个Bird。 使鸟的 TalkToOwner 方法向所有者发出 Tweet!。 再次运行应用。 输出将包含 Tweet!

测试示例

NewTypes 项目已准备就绪,与宠物相关的类型均置于一个文件夹中,因此具有良好的组织。 接下来,创建测试项目,并开始使用 xUnit 测试框架编写测试。 单元测试允许你自动检查宠物类型的行为,以确认它们正常运行。

导航回 src 文件夹,并在其中创建包含 NewTypesTests 文件夹的测试文件夹。 在 NewTypesTests 文件夹中的命令提示符下,执行 dotnet new xunit。 此命令生成两个文件: NewTypesTests.csprojUnitTest1.cs

测试项目当前无法测试NewTypes中的类型,并且需要对NewTypes项目进行引用。 若要添加项目引用,请使用 dotnet reference add 以下命令:

dotnet reference add ../../src/NewTypes/NewTypes.csproj

或者,还可以通过向 NewTypesTests.csproj 文件添加<ItemGroup>节点来手动添加项目引用:

<ItemGroup>
  <ProjectReference Include="../../src/NewTypes/NewTypes.csproj" />
</ItemGroup>

NewTypesTests.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
    <PackageReference Include="xunit" Version="2.8.1" />
    <PackageReference Include="xunit.runner.visualstudio" Version="2.8.1" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="../../src/NewTypes/NewTypes.csproj"/>
  </ItemGroup>

</Project>

NewTypesTests.csproj 文件包含以下包引用:

  • Microsoft.NET.Test.Sdk,.NET 测试基础结构
  • xunit,xUnit 测试框架
  • xunit.runner.visualstudio,测试运行程序
  • NewTypes,要测试的代码

UnitTest1.cs 的名称更改为 PetTests.cs ,并将文件中的代码替换为以下代码:

using System;
using Xunit;
using Pets;

public class PetTests
{
    [Fact]
    public void DogTalkToOwnerReturnsWoof()
    {
        string expected = "Woof!";
        string actual = new Dog().TalkToOwner();

        Assert.NotEqual(expected, actual);
    }

    [Fact]
    public void CatTalkToOwnerReturnsMeow()
    {
        string expected = "Meow!";
        string actual = new Cat().TalkToOwner();

        Assert.NotEqual(expected, actual);
    }
}

可选练习:如果之前添加了Bird类型,可为所有者生成Tweet!,请将测试方法添加到PetTests.cs文件中,BirdTalkToOwnerReturnsTweet以检查该TalkToOwner方法能否正确适用于该Bird类型。

注释

尽管期望 expectedactual 值相等,但使用 Assert.NotEqual 检查的初始断言表明这些值并不相等。 始终先创建一个预计会失败的测试,以便检查测试逻辑。 确认测试失败后,请调整断言以允许测试通过。

下面显示了完整的项目结构:

/NewTypes
|__/src
   |__/NewTypes
      |__/Pets
         |__Dog.cs
         |__Cat.cs
         |__IPet.cs
      |__Program.cs
      |__NewTypes.csproj
|__/test
   |__NewTypesTests
      |__PetTests.cs
      |__NewTypesTests.csproj

test/NewTypesTests 目录中开始。 使用 dotnet test 命令运行测试。 此命令启动项目文件中指定的测试运行程序。

如预期所示,测试失败,控制台会显示以下输出:

Test run for C:\Source\dotnet\docs\samples\snippets\core\tutorials\testing-with-cli\csharp\test\NewTypesTests\bin\Debug\net5.0\NewTypesTests.dll (.NETCoreApp,Version=v5.0)
Microsoft (R) Test Execution Command Line Tool Version 16.8.1
Copyright (c) Microsoft Corporation.  All rights reserved.

Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
[xUnit.net 00:00:00.50]     PetTests.DogTalkToOwnerReturnsWoof [FAIL]
  Failed PetTests.DogTalkToOwnerReturnsWoof [6 ms]
  Error Message:
   Assert.NotEqual() Failure
Expected: Not "Woof!"
Actual:   "Woof!"
  Stack Trace:
     at PetTests.DogTalkToOwnerReturnsWoof() in C:\Source\dotnet\docs\samples\snippets\core\tutorials\testing-with-cli\csharp\test\NewTypesTests\PetTests.cs:line 13

Failed!  - Failed:     1, Passed:     1, Skipped:     0, Total:     2, Duration: 8 ms - NewTypesTests.dll (net5.0)

将测试中的断言从 Assert.NotEqual 更改为 Assert.Equal

using System;
using Xunit;
using Pets;

public class PetTests
{
    [Fact]
    public void DogTalkToOwnerReturnsWoof()
    {
        string expected = "Woof!";
        string actual = new Dog().TalkToOwner();

        Assert.Equal(expected, actual);
    }

    [Fact]
    public void CatTalkToOwnerReturnsMeow()
    {
        string expected = "Meow!";
        string actual = new Cat().TalkToOwner();

        Assert.Equal(expected, actual);
    }
}

使用 dotnet test 命令重新运行测试,并获取以下输出:

Test run for C:\Source\dotnet\docs\samples\snippets\core\tutorials\testing-with-cli\csharp\test\NewTypesTests\bin\Debug\net5.0\NewTypesTests.dll (.NETCoreApp,Version=v5.0)
Microsoft (R) Test Execution Command Line Tool Version 16.8.1
Copyright (c) Microsoft Corporation.  All rights reserved.

Starting test execution, please wait...
A total of 1 test files matched the specified pattern.

Passed!  - Failed:     0, Passed:     2, Skipped:     0, Total:     2, Duration: 2 ms - NewTypesTests.dll (net5.0)

测试通过。 在与所有者谈话时,宠物类型的方法返回正确的值。

你已学习了使用 xUnit 组织和测试项目的技术。 继续使用这些技术在你自己的项目中应用它们。 祝你编码愉快!