使用 Visual Studio for Mac 在 macOS 上构建完整的 .NET Core 解决方案
Visual Studio for Mac 提供用于开发 .NET Core 应用程序的功能全面的集成开发环境 (IDE)。 本文演示了构建包含可重用的库和单元测试的 .NET Core 解决方案。
本教程介绍了如何创建接受来自用户的搜索词和文本字符串、使用类库中的方法计算字符串中出现的搜索词的次数,并将结果返回给用户的应用程序。 该解决方案还包括类库的单元测试(作为单元测试概念的介绍)。 如果希望使用完整的示例学习该教程,请下载示例解决方案。 有关下载说明,请参阅示例和教程。
Note
你的反馈非常有价值。 有两种方法可以向开发团队提供有关 Visual Studio for Mac 的反馈:
- 在 Visual Studio for Mac 中,从菜单选择“帮助” > “报告问题” ,或从欢迎屏幕中选择“报告问题” ,将打开一个窗口,以供填写 bug 报告。 可在开发人员社区门户中跟踪自己的反馈。
- 若要提出建议,从菜单中选择“帮助” > “提供建议” ,或从欢迎屏幕中选择“提供建议” ,转到 Visual Studio for Mac 开发人员社区网页。
先决条件
若要了解有关先决条件的详细信息,请参阅 .NET Core 依赖项和要求。 有关 Visual Studio 2019 for Mac 完整系统要求的信息,请参阅 Visual Studio 2019 for Mac 产品系列系统要求。
生成库
在“开始”窗口,选择“新建项目” 。 在“.NET Core” 节点下的“新建项目” 对话框中,选择“.NET 标准库” 模板。 此命令将创建一个 .NET Standard 库,该库面向 .NET Core 及支持 .NET Standard 版本 2.1 的任何其他 .NET 实现。 如果安装了多个版本的 .NET Core SDK,则可以为库选择不同版本的 .NET Standard。 选择“.NET Standard 2.1”,然后选择“下一步” 。
将项目命名为“TextUtils”(“Text Utilities”的短名称),将解决方案命名为“WordCounter”。 使“在解决方案目录中创建项目目录” 保持选中状态。 选择“创建” 。
在“解决方案” 边栏中,展开
TextUtils
节点以显示模板提供的类文件 Class1.cs。 按住 Ctrl 并单击该文件,从上下文菜单中选择“重命名” ,然后将该文件重命名为 WordCount.cs 。 打开文件并将内容替换为以下代码:using System; using System.Linq; namespace TextUtils { public static class WordCount { public static int GetWordCount(string searchWord, string inputString) { // Null check these variables and determine if they have values. if (string.IsNullOrEmpty(searchWord) || string.IsNullOrEmpty(inputString)) { return 0; } // Convert the string into an array of words. var source = inputString.Split(new char[] { '.', '?', '!', ' ', ';', ':', ',' }, StringSplitOptions.RemoveEmptyEntries); // Create the query. Use ToLowerInvariant to match uppercase/lowercase strings. var matchQuery = from word in source where word.ToLowerInvariant() == searchWord.ToLowerInvariant() select word; // Count the matches, which executes the query. Return the result. return matchQuery.Count(); } } }
通过使用以下三种不同的方法之一保存文件:使用键盘快捷方式 ⌘+s,从菜单中选择“文件” > “保存” ,或按住 Ctrl 并单击文件的选项卡,并从上下文菜单中选择“保存” 。 下图显示 IDE 窗口:
在 IDE 窗口底部边距处选择“错误” ,打开“错误” 面板。 选择“生成输出” 按钮。
从菜单中选择“生成” > “生成所有” 。
生成解决方案。 生成输出面板显示生成成功。
创建测试项目
单元测试在开发和发布期间提供自动化的软件测试。 本教程中使用的测试框架是 xUnit(版本 2.4.0 或更高版本),使用下列步骤将 xUnit 测试项目添加到解决方案时将自动安装此框架:
在“解决方案” 边栏中,按住 Ctrl 并单击
WordCounter
解决方案并选择“添加” > “添加新项目” 。在“新建项目” 对话框中,从“.NET Core” 节点中选择“测试” 。 在“下一步” 后,选择“xUnit 测试项目” 。
如果有多个版本的 .NET Core SDK,则需要选择此项目的版本。 选择“.NET Core 3.1” 。 将新项目命名为"TestLibrary",然后选择“创建” 。
若要使测试库使用
WordCount
类,请将引用添加到TextUtils
项目中。 在“解决方案” 边栏中,按住 Ctrl 并单击“TestLibrary” 下的“依赖项” 。 从上下文菜单中选择“编辑引用” 。在“编辑引用” 对话框中,选择“项目” 选项卡上的“TextUtils” 项目。选择“确定” 。
在 TestLibrary 项目中,将 UnitTest1.cs 文件重命名为 TextUtilsTests.cs。
打开该文件,并将代码替换为以下代码:
using Xunit; using TextUtils; using System.Diagnostics; namespace TestLibrary { public class TextUtils_GetWordCountShould { [Fact] public void IgnoreCasing() { var wordCount = WordCount.GetWordCount("Jack", "Jack jack"); Assert.NotEqual(2, wordCount); } } }
下图显示了就地使用单元测试代码的 IDE。 请注意
Assert.NotEqual
语句。请务必使新的测试失败一次,以确定其测试逻辑正确无误。 该方法使用“Jack”和“jack”(大写和小写)传递名称“Jack”(大写)和字符串。 如果
GetWordCount
方法运行正常,则返回搜索词的两个实例的计数。 为了有意进行失败测试,首先实现测试断言,即搜索词“Jack”的两个实例不是由GetWordCount
方法返回的。 继续执行下一步骤,有意使测试失败。打开屏幕右侧的“单元测试” 面板。 从菜单中选择“查看” > “测试” 。
单击“停靠” 图标使此面板保持打开状态。 (在下图中突出显示。)
单击“全部运行” 按钮。
测试失败,这是正确的结果。 测试方法断言不会从提供给
GetWordCount
的方法的字符串“Jack jack”中返回inputString
“Jack”的两个实例。 因为已在GetWordCount
方法中对单词的大小写进行了分解,所以返回了两个实例。 2 不等于 2 的断言失败。 这是正确的结果,且测试的逻辑良好。通过将
Assert.NotEqual
更改为Assert.Equal
来修改IgnoreCasing
测试方法。 使用键盘快捷方式 Ctrl+s 保存该文件,从菜单选择“文件” > “保存” ,或按住 Ctrl 并单击文件的选项卡,并从上下文菜单中选择“保存” 。searchWord
Jack”应返回两个实例,并且inputString
“Jack jack”传递到GetWordCount
。 通过单击“单元测试” 面板中的“运行测试” 按钮或屏幕底部的“测试结果” 面板中的“重新运行测试” 按钮重新运行测试。 测试通过。 在字符串"Jack jack"(忽略大小写)中有“Jack”的两个实例,且测试断言为true
。使用
Fact
测试单个返回值仅仅是借助单元测试可以实现的功能的开始。 另一个功能强大的技术是允许你使用Theory
立即测试多个值。 将以下方法添加到你的TextUtils_GetWordCountShould
类。 添加该方法后,在类中有两个方法:[Theory] [InlineData(0, "Ting", "Does not appear in the string.")] [InlineData(1, "Ting", "Ting appears once.")] [InlineData(2, "Ting", "Ting appears twice with Ting.")] public void CountInstancesCorrectly(int count, string searchWord, string inputString) { Assert.NotEqual(count, WordCount.GetWordCount(searchWord, inputString)); }
CountInstancesCorrectly
检查GetWordCount
方法计数是否正确。InlineData
提供计数、搜索词和要检查的输入字符串。 测试方法为数据的每行运行一次。 请再次注意,使用Assert.NotEqual
首先声明失败,即使知道数据中的计数是正确的,且这些值与GetWordCount
方法所返回的计数相匹配。 有意执行测试失败的步骤起初看起来像是浪费时间,但是首先通过失败测试检查测试的逻辑对于测试逻辑而言,是一项重要检查。 如果在预期失败时找到一种可通过的测试方法,则你已在测试逻辑中找到 bug。 每次创建测试方法时,都值得采取此步骤。保存文件并重新运行测试。 大小写测试通过,但三个计数测试失败。 这与我们预期的结果完全一致。
通过将
Assert.NotEqual
更改为Assert.Equal
来修改CountInstancesCorrectly
测试方法。 保存该文件。 重新运行测试。 所有测试通过。
添加控制台应用
在“解决方案” 边栏中,按住 Ctrl 并单击
WordCounter
解决方案。 通过从“.NET Core” > “应用” 模板中选择模板来添加新的控制台应用程序项目。 选择“下一步” 。 将项目命名为 WordCounterApp。 选择“创建” 以在解决方案中创建项目。在“解决方案” 边栏中,按住 Ctrl 并单击新“WordCounterApp” 项目的“依赖项” 。 在“编辑引用” 对话框中,选中“TextUtils” ,然后选择“确定” 。
打开 Program.cs 文件。 将代码替换为以下代码:
using System; using TextUtils; namespace WordCounterApp { class Program { static void Main(string[] args) { Console.WriteLine("Enter a search word:"); var searchWord = Console.ReadLine(); Console.WriteLine("Provide a string to search:"); var inputString = Console.ReadLine(); var wordCount = WordCount.GetWordCount(searchWord, inputString); var pluralChar = "s"; if (wordCount == 1) { pluralChar = string.Empty; } Console.WriteLine($"The search word {searchWord} appears " + $"{wordCount} time{pluralChar}."); } } }
按住 Ctrl 并单击
WordCounterApp
项目,并从上下文菜单中选择“运行项目” 。 运行应用时,在控制台窗口中的提示符处提供搜索词和输入字符串的值。 应用指示搜索词在字符串中出现的次数。要探索的最后一个功能是使用 Visual Studio for Mac 进行调试。 在
Console.WriteLine
语句上设置断点:在第 23 行的左边距处选择,可以看到代码行旁边出现红色的圆圈。 或者,在代码行上的任意位置进行选择,然后从菜单中选择“运行” > “切换断点” 。按住 Ctrl 并单击
WordCounterApp
项目。 从上下文菜单中选择“开始调试项目” 。 应用运行时,输入搜索词“cat”和“The dog chased the cat, but the cat escaped.” 以供字符串进行搜索。 到达Console.WriteLine
语句时,将在执行该语句前暂停执行程序。 在“本地” 选项卡中,可以看到searchWord
、inputString
、wordCount
和pluralChar
值。在“即时” 面板中,键入“wordCount = 999;”,然后按 Enter 键。 此命令将无意义的值 999 分配到
wordCount
变量,显示可以在调试时替换变量值。在工具栏中,单击“继续” 。 查看控制台窗口中的输出。 它报告调试应用时所设置的不正确的值 999。
可以使用相同的过程通过单元测试项目来调试代码。 按住 Ctrl 并单击“测试库” 项目,然后从上下文菜单中选择“启动调试项目” ,而不是启动 WordCount 应用项目。 Visual Studio for Mac 在附加了调试器的情况启动测试项目。 执行将在添加到测试项目的任何断点或基础库代码处停止。