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

Moq基础(四)

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

上一章讲了如何使用Setup伪造方法

这一章我们将伪造属性和事件


Setup:伪造属性

上一章我们说过setup系列不仅可以伪造方法,也可以伪造属性(毕竟属性本质也是方法,┓( ´∀` )┏)。这里依然用上一次的moq官方文档中的接口为例

代码语言:javascript
复制
public interface IFoo
{
    Bar Bar { get; set; }
    string Name { get; set; }
    int Value { get; set; }
    bool DoSomething(string value);
    bool DoSomething(int number, string value);
    string DoSomethingStringy(string value);
    bool TryParse(string value, out string outputValue);
    bool Submit(ref Bar bar);
    int GetCount();
    bool Add(int value);
    
    event EventHandler MyEvent; 
}

public class Bar 
{
    public virtual Baz Baz { get; set; }
    public virtual bool Submit() { return false; }
}

public class Baz
{
    public virtual string Name { get; set; }
}

这次不同的是,我们伪造的东西变成了Name方法。

记得小时候老师教我们做了好事,别人问你叫什么,你就要说“我叫红领巾”。

所以期望IFooName方法返回值是”红领巾”.那么就可以写

代码语言:javascript
复制
var fakeFoo = new Mock<IFoo>();
fakeFoo.Setup(fake => fake.Name).Returns("红领巾");

是不是很简单,但是,重点来了,我们还能在API中看到有一个SetupSet这个方法。

此时,有了经验的童鞋们会说,这不是很简单么,伪造属性的Set方法。

大错特错

思考下,我们如果伪造了一个属性的Set方法后,能够干什么呢?只能是验证这个伪对象的属性是否被赋值了。

此时,我们的伪对象作用发生了变化,由Stub变成了Mock ,

因此,这个命名是非常失败的命名,正确的叫法应该是VerifySet ,当然Moq也有VerifySet ,他们做的事情也“几乎”一样。

代码语言:javascript
复制
//使用VerifySet验证
fakeFoo.VerifySet(fake => fake.Name="红领巾");
//使用SetupSet验证
fakeFoo.SetupSet(fake => fake.Name="红领巾");
fakeFoo.VerifyAll();

ok,说了不好的,再说点Moq厉害的地方——递归伪造

举例说明,你现在期望伪造IFoo接口的属性Bar的子属性BazName

是不是听都听晕了?不急,我们试着写下

代码语言:javascript
复制
//伪造对象
var fakeFoo = new Mock<IFoo>();
var fakeBar = new Mock<Bar>();
var fakeBaz = new Mock<Baz>();
//组装
fakeBaz.Setup(fake => fake.Name).Returns("红领巾");
fakeBar.Setup(fake => fake.Baz).Returns(fakeBaz.Object);
fakeFoo.Setup(fake => fake.Bar).Returns(fakeBar.Object);

可累了是吧,没事有更加简单的写法

代码语言:javascript
复制
var fakeFoo = new Mock<IFoo>();
fakeFoo.Setup(fake => fake.Bar.Baz.Name).Returns("红领巾");

一步到位。递归伪造会将调用路径上的所有对象自动伪造。

因此,这也是区别普通框架和框架的标准之一。

当然,我们有时候也仅希望伪造一个属性实现,使这个伪造对象可用,

那么就可以使用SetupProperty添加自动实现

代码语言:javascript
复制
fakeFoo.SetupProperty(fake => fake.Name);

当然也可以设置初始值

代码语言:javascript
复制
fakeFoo.SetupProperty(fake => fake.Name,"红领巾");

好总结下伪造属性的方法。

代码语言:javascript
复制
//伪造属性返回值
fakeFoo.Setup(fake => fake.Name).Returns("红领巾");
//递归伪造
fakeFoo.Setup(fake => fake.Bar.Baz.Name).Returns("红领巾");
//自动属性实现
fakeFoo.SetupProperty(fake => fake.Name,"红领巾");

当然还有要重点区分的

代码语言:javascript
复制
//使用VerifySet验证
fakeFoo.VerifySet(fake => fake.Name="红领巾");
//使用SetupSet验证
fakeFoo.SetupSet(fake => fake.Name="红领巾");
fakeFoo.VerifyAll();

Raise:伪造事件

事件也是一种常见的依赖,我们常常需要验证在发生某些事件时,被测对象能否顺利响应。

这里的行为偏向于Act,而之前的那些属于Arrange

至于Arrange-Act-Assert的三A结构,可以参考其他的单元测试书籍。

代码语言:javascript
复制
fakeFoo.Object.MyEvent += OnMyEvent;
fakeFoo.Raise(fack => fack.MyEvent += null, new EventArgs());

很简单,第一个参数请保持为null,因为这个事件永远不会触发,应该监听的是fakeFoo.Object.MyEvent

另外Moq也支持自定义的EventHandler类,

而针对泛型版本的EventHandler<T>,格式会稍稍不同,需要添加sender

代码语言:javascript
复制
fakeFoo.Raise(fack => fack.MyEvent += null, fack, new EventArgs());


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

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

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Setup:伪造属性
  • 大错特错
  • Raise:伪造事件
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档