测试与调试是开发过程当中不可缺少的环节。本教程将通过对”鹦鹉学舌”插件对”如何测试与调试 Newbe.Mahua”.
测试 测试分类多种多样,其中,”单元测试”是最开始的细粒度测试。
掌握单元测试的技能,将会在使用 Newbe.Mahua 进行开发时无往不利的成功秘诀。
本教程将使用 VS2017 作为开发 IDE 进行演示。
新建测试项目
引入测试框架 .Net 测试框架众多,主流的有 MSTest、NUnit 和 XUnit。本教程选择 XUnit 进行演示。
通过 nuget 安装以下包,全部安装最新版本即可:
xunit xunit.runner.visualstudio FluentAssertions Autofac.Extras.Moq 可以不用先了解每个包时什么作用,看了代码,自然就会清楚。
添加单元测试代码 先看一下需要测试的”鹦鹉学舌”插件的核心逻辑,将消息回发给消息发送者。
using Newbe.Mahua.MahuaEvents;namespace Newbe.Mahua.Plugins.Parrot.MahuaEvents { public class PrivateMessageFromFriendReceivedMahuaEvent : IPrivateMessageFromFriendReceivedMahuaEvent { private readonly IMahuaApi _mahuaApi; public PrivateMessageFromFriendReceivedMahuaEvent ( IMahuaApi mahuaApi ) { _mahuaApi = mahuaApi; } public void ProcessFriendMessage (PrivateMessageFromFriendReceivedContext context ) { _mahuaApi.SendPrivateMessage(context.FromQq, context.Message); } } }
通过项目引用,引用”Newbe.Mahua.Plugins.Parrot”项目。
在新建的测试项目”Newbe.Mahua.Plugins.Parrot.Tests”中新建一个类”ParrotTest”,并填写以下代码:
using Autofac.Extras.Moq;using FluentAssertions;using Newbe.Mahua.MahuaEvents;using Newbe.Mahua.Plugins.Parrot.MahuaEvents;using System;using Xunit;using Xunit.Abstractions;namespace Newbe.Mahua.Plugins.Parrot.Tests { public class ParrotTest { private readonly ITestOutputHelper _testOutputHelper; public ParrotTest (ITestOutputHelper testOutputHelper ) { _testOutputHelper = testOutputHelper; } [Fact(DisplayName = "将消息回发给消息发送者" ) ] public void Test ( ) { using (var mocker = AutoMock.GetStrict()) { mocker.VerifyAll = true ; #region Arrange var mahuaApi = mocker.Mock<IMahuaApi>(); var msgSend = false ; mahuaApi .Setup(x => x.SendPrivateMessage("472158246" , "呵呵哒" )) .Callback<string , string >((qq, msg) => { _testOutputHelper.WriteLine($"测试将消息发送给{qq} ,消息是{msg} " ); msgSend = true ; }); #endregion #region Action IPrivateMessageFromFriendReceivedMahuaEvent @event = mocker.Create<PrivateMessageFromFriendReceivedMahuaEvent>(); @event .ProcessFriendMessage(new PrivateMessageFromFriendReceivedContext { FromQq = "472158246" , Message = "呵呵哒" , SendTime = DateTime.Now }); #endregion #region Assert msgSend.Should().BeTrue(); #endregion } } } }
通过阅读代码的注释,相信真正的勇士已经领会了其中的奥义。
运行测试代码
来吧!真正的勇士,就绿了它们!
需求变化 需求变了,只有消息当中有”收到回复”这个字符串,那么才需要回发,并且要删除其中的”收到回复”字符串。
在测试项目新加一个实现类,来实现上面的业务逻辑。
using Newbe.Mahua.MahuaEvents;namespace Newbe.Mahua.Plugins.Parrot.Tests { public class PrivateMessageFromFriendReceivedMahuaEventV2 : IPrivateMessageFromFriendReceivedMahuaEvent { private readonly IMahuaApi _mahuaApi; public PrivateMessageFromFriendReceivedMahuaEventV2 ( IMahuaApi mahuaApi ) { _mahuaApi = mahuaApi; } public void ProcessFriendMessage (PrivateMessageFromFriendReceivedContext context ) { if (context.Message?.Contains("收到回复" ) == true ) { var msg = context.Message.Replace("收到回复" , string .Empty); _mahuaApi.SendPrivateMessage(context.FromQq, msg); } } } }
显然,这个业务逻辑,至少需要两个单元测试。一个测试的消息中包含”收到回复”,另一个则不包含。
由此,新建”ParrotTestV2”类,并填写以下代码:
using Autofac.Extras.Moq;using FluentAssertions;using Newbe.Mahua.MahuaEvents;using System;using Xunit;using Xunit.Abstractions;namespace Newbe.Mahua.Plugins.Parrot.Tests { public class ParrotTestV2 { private readonly ITestOutputHelper _testOutputHelper; public ParrotTestV2 (ITestOutputHelper testOutputHelper ) { _testOutputHelper = testOutputHelper; } [Fact(DisplayName = "消息包含“收到回复”" ) ] public void Test1 ( ) { using (var mocker = AutoMock.GetStrict()) { mocker.VerifyAll = true ; var mahuaApi = mocker.Mock<IMahuaApi>(); var msgSend = false ; mahuaApi .Setup(x => x.SendPrivateMessage("472158246" , "请马上捐款" )) .Callback<string , string >((qq, msg) => { _testOutputHelper.WriteLine($"测试将消息发送给{qq} ,消息是{msg} " ); msgSend = true ; }); IPrivateMessageFromFriendReceivedMahuaEvent @event = mocker.Create<PrivateMessageFromFriendReceivedMahuaEventV2>(); @event .ProcessFriendMessage(new PrivateMessageFromFriendReceivedContext { FromQq = "472158246" , Message = "请马上捐款收到回复" , SendTime = DateTime.Now }); msgSend.Should().BeTrue(); } } [Fact(DisplayName = "消息不包含“收到回复”" ) ] public void Test2 ( ) { using (var mocker = AutoMock.GetStrict()) { mocker.VerifyAll = true ; IPrivateMessageFromFriendReceivedMahuaEvent @event = mocker.Create<PrivateMessageFromFriendReceivedMahuaEventV2>(); @event .ProcessFriendMessage(new PrivateMessageFromFriendReceivedContext { FromQq = "472158246" , Message = "呵呵哒" , SendTime = DateTime.Now }); } } } }
自己手动尝试的过程中可能会出现,没出现”绿”的问题。不要放弃,要么测试错了,要么业务逻辑错误。电脑是不会错的。
其实上面的业务逻辑中是存在 BUG 的:QQ 无法发送空的消息,所以,如果对方的消息只包含”收到回复”四个字,那么真正运行的时候会报错。
因此,要增加额外的逻辑判断和单元测试,来确保这个 BUG 不会发生。真正的勇士,自己就会动手。
最后 单元测试就是为了确保代码逻辑在小范围内绝对正确的开发行为,很有必要。
单元测试只要 Newbe.Mahua 提供的接口稳定,自己的业务逻辑没有变化,那么你的业务逻辑就永远能够通过单元测试。也就是说,这段代码就是为了确保你有底气说出:”我的代码不可能出错!”
以上演示代码,均可以在本项目代码仓库中找到。
调试 单元测试是开发阶段最初的测试,但事实是,绝大多数的人更喜欢”跑一下看看”。因此调试,也就很有必要。
构建 在构建脚本build.ps1
中,将$configuration
从Release
改为Debug
,然后运行build.bat
完成构建。
复制 将生成的所有内容复制到对应机器人平台。
启动调试 修改项目属性中的调试选项卡配置,并且将插件项目设置为启动项目,F5 启动调试,下断点,命中,就这么简单。
调试框架源码 从 1.6 版本开始,使用 VS 2017.5 及以上的版本,将可以实现无需下载源码,便可以调试源码的目的,只需要在 VS 中打开下图设置即可。
至此,调试便可以正常进行了。
教程链接 发布说明