上一章介绍了手动创建单元测试依赖,和Moq的小demo

这一章我们看一下Moq的使用。


不过,at the vary beginning,我想再和大家确认两个概念问题——Stub(存根)和Mock(模拟)

StubMock都是测试方法依赖隔离的伪造对象,不同之处是Stub是测试方法运行所需要的依赖,

Mock是测试方法验证说需要的依赖。

听懂了么?没有懂对不对。没关系,我们上代码。

    public class Foo2
    {
        private ILog _log1;
        private ILog _log2;

        public Foo2(ILog log1,ILog log2)
        {
            _log1 = log1;
            _log2 = log2;
        }

        public void DoB()
        {
            //do something
            var text = _log1.Read();
            _log2.Write(text);
        }

    }

还是之前的日志系统的例子,不过这次我们做的是从日志系统1中读取内容,存入到日志系统2中。

看一下我们的测试代码

        [TestMethod]
        public void TestMethod3()
        {
            var fakeLog1 = new Mock<ILog>();
            var fakeLog2 = new Mock<ILog>();
            fakeLog1.Setup(log => log.Read()).Returns("I'm slim");
            var foo = new Foo2(fakeLog1.Object,fakeLog2.Object);
            foo.DoB();
            fakeLog2.Verify(log => log.Write("I'm slim"));
        }

解释一下fakeLog1.Setup(log => log.Read()).Returns("I'm slim");是设置fakeLog1在调用Read方法时,一定会返回"I'm slim",

fakeLog2.Verify(log => log.Write("I'm slim"));则是验证fakeLog2是否被调用了Write方法,并且传入的参数是"I'm slim"

这个时候我们说fakeLog1Stub,而fakeLog2Mock

52335029026

StubMoq中对应方法的是Setup,Mock对应的方法是Verify

英文好的同学可以参见https://martinfowler.com/articles/mocksArentStubs.html

Martin Fowler大大对这两个概念有比较明确的解释。

请注意这里的MockMoq框架中的Mock<T>不是一个概念!!

这也是Moq框架被众多开发人员诟病的一点。

这时有读者会问了,讲这么多概念,头都晕了,但是对我写单元测试没有一点用呀。

不是的,分清这个概念最重要的一点就是不要让你写出下面的代码:

52336333517

这个是同时StubMock了同一个方法。非常正确,但是无用。

关键是这种写法出现在了我们团队真实的单元测试代码中。。。

名不正,则言不顺;言不顺,则事不成理论不清晰的行动,总是不能在长期的战斗中获胜

在单元测试框架中,(尤其是Moq这种概念不清楚的),时刻清除你的伪对象在做什么,是非常重要的一点


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

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