Amaze UI Logo

Newbe便是新生,唯有不断蜕变才能焕然新生。


即将上线
尽请期待!

Newbe.Mahua 测试与调试

测试与调试是开发过程当中不可缺少的环节。本教程将通过对”鹦鹉学舌”插件对”如何测试与调试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
{
    /// <summary>
    /// 来自好友的私聊消息接收事件
    /// </summary>
    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)
        {
            // 这是xunit特有的信息输出方法,其他框架可以使用Console.Writeline
            _testOutputHelper = testOutputHelper;
        }

        [Fact(DisplayName = "将消息回发给消息发送者")]
        public void Test()
        {
            // 一般的单元测试都分为三个部分 Arrange(准备) Action(执行) 和 Assert(断言)
            // Arrange 对单元测试中需要测试的准备参数进行初始化
            // Action 执行需要测试的逻辑
            // Assert 对测试结果是否正确进行判断
            using (var mocker = AutoMock.GetStrict())
            {
                // Moq的参数,确定在整个单元测试结束之后,所有被模拟的方法都已经被执行。
                mocker.VerifyAll = true;

                #region Arrange

                // 生成一个IMahuaApi的实现,这个实现的所有方法都是没有实现的,需要进一步填充
                var mahuaApi = mocker.Mock<IMahuaApi>();

                // 用来记录消息是否已经发送的变量,为了在断言中使用
                var msgSend = false;

                // 对MahuaApi中的SendPrivateMessage方法进行模拟
                // 当调用参数是“472158246”和“呵呵哒”时,调用xunit帮助类在控制台输出消息
                // 并设置变量msgSend为true  表示,消息确实已经回发了
                mahuaApi
                    .Setup(x => x.SendPrivateMessage("472158246", "呵呵哒"))
                    .Callback<string, string>((qq, msg) =>
                    {
                        _testOutputHelper.WriteLine($"测试将消息发送给{qq},消息是{msg}");
                        msgSend = true;
                    });

                #endregion

                #region Action

                //创建需要测试的类,由于使用了Autofac.Extras.Moq,构造函数注入的过程会自动执行
                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
{
    /// <summary>
    /// 只有包含收到回复,才需要回复
    /// </summary>
    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;
                    });

                // 这里使用的是V2
                IPrivateMessageFromFriendReceivedMahuaEvent @event =
                    mocker.Create<PrivateMessageFromFriendReceivedMahuaEventV2>();
                @event.ProcessFriendMessage(new PrivateMessageFromFriendReceivedContext
                {
                    FromQq = "472158246",
                    Message = "请马上捐款收到回复",
                    SendTime = DateTime.Now
                });

                // 注意,这里是true
                msgSend.Should().BeTrue();
            }
        }

        [Fact(DisplayName = "消息不包含“收到回复”")]
        public void Test2()
        {
            using (var mocker = AutoMock.GetStrict())
            {
                mocker.VerifyAll = true;

                // 因为我们确定不会调用IMahuaApi,所以不需要Mock

                // 这里使用的是V2
                IPrivateMessageFromFriendReceivedMahuaEvent @event =
                    mocker.Create<PrivateMessageFromFriendReceivedMahuaEventV2>();
                @event.ProcessFriendMessage(new PrivateMessageFromFriendReceivedContext
                {
                    FromQq = "472158246",
                    Message = "呵呵哒",
                    SendTime = DateTime.Now
                });
            }
        }
    }
}

    

自己手动尝试的过程中可能会出现,没出现”绿”的问题。不要放弃,要么测试错了,要么业务逻辑错误。电脑是不会错的。

其实上面的业务逻辑中是存在BUG的:QQ无法发送空的消息,所以,如果对方的消息只包含”收到回复”四个字,那么真正运行的时候会报错。

因此,要增加额外的逻辑判断和单元测试,来确保这个BUG不会发生。真正的勇士,自己就会动手。

最后

单元测试就是为了确保代码逻辑在小范围内绝对正确的开发行为,很有必要。

单元测试只要Newbe.Mahua提供的接口稳定,自己的业务逻辑没有变化,那么你的业务逻辑就永远能够通过单元测试。也就是说,这段代码就是为了确保你有底气说出:”我的代码不可能出错!”

以上演示代码,均可以在本项目代码仓库中找到。

调试

单元测试是开发阶段最初的测试,但事实是,绝大多数的人更喜欢”跑一下看看”。因此调试,也就很有必要。

构建

在构建脚本build.ps1中,将$configurationRelease改为Debug,然后运行build.bat完成构建。

修改构建参数

复制

将生成的所有内容复制到对应机器人平台。

启动调试

修改项目属性中的调试选项卡配置,并且将插件项目设置为启动项目,F5启动调试,下断点,命中,就这么简单。

修改调试启动项目

调试框架源码

从 1.6 版本开始,使用 VS 2017.5 及以上的版本,将可以实现无需下载源码,便可以调试源码的目的,只需要在VS中打开下图设置即可。

开启源链接支持

至此,调试便可以正常进行了。

=========================更多内容分割线=========================

教程链接

开始第一个QQ机器人【适用于v1.8及以上】

Newbe.Mahua.Samples.ApiExtensions 对IMahuaApi进行扩展

Newbe.Mahua.Samples.LiveGirl 操作定时任务

Newbe.Mahua.Samples.Sqlite SQLite操作实例

Newbe.Mahua 测试与调试

Newbe.Mahua 扩展设置中心

发布说明

Newbe.Mahua 1.8 消息发送Fluent API

Newbe.Mahua 1.7.0 支持API扩展

Newbe.Mahua 1.6.0 开发便利性提升


回到顶部
b站直播
听说正在直播码字,要不要前去帮忙刷一下人气?
邀您体验
限时特惠,现在接受邀请获得QQ机器人免费体验卡!