前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Moq基础(一)

Moq基础(一)

作者头像
黄腾霄
发布2020-06-10 10:48:31
1.1K0
发布2020-06-10 10:48:31
举报
文章被收录于专栏:黄腾霄的博客

在教程开始之前,先回顾下单元测试应该有哪些特点?


运行快,自动化,结果稳定,隔离等等。

但是并不是所有的方法都能写出这样的单元测试。比如说有如下类:

代码语言:javascript
复制
    public class Foo
    {
        private Log _log;
        public Foo(Log log)
        {
            _log = log;
        }

        public void DoA()
        {
            //do something
            _log.Write("Finish A");
        }
    }

这个类依赖于一个日志对象Log

代码语言:javascript
复制
    public class Log
    {
        private readonly string _uri;

        public Log(string uri)
        {
            _uri = uri;
        }

        public void Write(string text)
        {
            using (var stream = File.AppendText(_uri))
            {
                stream.Write(text);
            }
        }

        public string Read()
        {
            if (!File.Exists(_uri))
            {
                return string.Empty;
            }

            using (var stream = File.OpenRead(_uri))
            {
                using (var reader = new StreamReader(stream))
                {
                    return reader.ReadToEnd();
                }
            }
        }
    }

现在我们期望能够写一个单元测试,验证运行DoA方法时,是否向日志写入了Finish A

那么问题来了,我们需要在每次运行单元测试时,要真正的读写文件。那么这个单元测试能够做到运行快,结果稳定,隔离等等要求么?如果我们的例子中的日志系统换成数据库,网络请求会怎样呢?

如果这个时候我们能够伪造一个日志系统,是否问题就能够解决了呢?

那么首先我们需要引入一个接口ILog

代码语言:javascript
复制
    public interface ILog
    {
        void Write(string text);

        string Read();
    }

    public class Log:ILog
    {
        //some code
    }

相应的,待测类也要做一些改动

代码语言:javascript
复制
	public class Foo
    {
        private ILog _log;

        public Foo(ILog log)
        {
            _log = log;
        }

        public void DoA()
        {
            //do something
            _log.Write("Finish A");
        }
    }

这样我们就可以制造一个FakeLog将测试环境同真实的文件系统进行隔离。

好,我们看下FakeLog的代码

代码语言:javascript
复制
    public class FakeLog : ILog
    {
        public string Log { get; private set; }

        public void Write(string text)
        {
            Log = text;
        }

        public string Read()
        {
            throw new NotImplementedException();
        }
    }

我们要测试的只有日志写入,因此Read方法不需要实现,另外我们还需要一个简单的方式能够把写入的内容暴露出来。所以这里还定义了一个属性Log用于展示写入的日志内容。

下面是测试代码

代码语言:javascript
复制
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
            var fakeLog = new FakeLog();
            var foo = new Foo(fakeLog);
            foo.DoA();
            Assert.AreEqual("Finish A",fakeLog.Log);
        }
    }

运行一下,绿色,很好。

那么就结束了么?不是的,单元测试还有一个特点是易于编写。我们这样子手工编写一个单元测试成本还是太高了。这么简单的东西是不是应该有一个隔离框架来做呢?

于是就到了我们的主角,Moq

先让大家体验一下使用Moq的自动创建代码来替换我们手动创建的FakeLog

代码语言:javascript
复制
        [TestMethod]
        public void TestMethod2()
        {
            var fakeLog = new Mock<ILog>();
            var foo = new Foo(fakeLog.Object);
            foo.DoA();
            fakeLog.Verify(log => log.Write("Finish A"));
        }

就是这么简单,完全不用自己实现FakeLog,并且用一个lambda表达式就完成了我们期望的验证。

运行测试,绿色,通过。

很棒是不是,这就是自动化的隔离框架的作用。

接下去就会带你进入Moq的世界


本文会经常更新,请阅读原文: https://xinyuehtx.github.io/post/Moq%E5%9F%BA%E7%A1%80-%E4%B8%80.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名黄腾霄(包含链接: https://xinyuehtx.github.io ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-04-10 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档