.net测试篇之Moq框架简单使用 (2)

我们看以上代码,我们我们让数据访问接口的代理对象返回一个MyDto类型集合,一共四个元素,由我们的业务可知,我们只要年龄大于20的元素,并且名字按正序排列.因此以上测试应该返回成功,实际上也是测试通过了.

带参数的方法设置

以上的GetAll是不带参数的,带参数的方法我们可以显式的指定一个参数,我们也可以使用Moq框架提供的方法来模糊指定参数,比如我们可以指定方法是任意字符,任意数字,任意范围的数字等.

我们再看前面的一个方法

public MyDto GetADto(string id) { if (string.IsNullOrWhiteSpace(id)) return null; return _dataBaseContext.GetElementById(id); }

这个方法接收一个类型为字符串的id,只要字符串不是空字符串或者null时我们都返回一个MyDto对象.

测试方法如下

[Test] public void ShouldReturn_A_Dto_If_QueryBy_Id_With_Valid_Parameter() { var moq = new Mock<IDataBaseContext<MyDto>>(); moq.Setup(a => a.GetElementById(It.IsAny<string>())).Returns(new MyDto()); MyBll bll = new MyBll(moq.Object); var dto = bll.GetADto("afakeid"); dto.Should().NotBeNull(); }

这里我们使用到了Moq里的It.Is方法,这个方法接受一个Func<T,bool>类型的委托,我们的条件是不管它是一个什么样的string,总是返回一个new MyDto();

[warning]注意这里配置的是Moq对象(即moq.Object)的方法返回值,而不是bll对象的方法的返回值,如果我们传入的字符串是空字符串,则GetADto直接返回了null,数据访问对象就没机会执行了.

It里面还有很多静态方法,用于指定数字是否是否在某一范围,对象是否是列表中的对象,字符串是否满足正则等.语义都非常明确,大家可以自己研究一下.

指定参数的配置

以上使用到了It.IsAny方法.It里面还有一个Is方法,接受一个Func<T,bool>类型委托,用于指定对象为满足特定条件的对象,而不是任意对象.

Bll层新增以下方法

public bool IsVip(string id) { if (string.IsNullOrWhiteSpace(id)) return false; var dto = _dataBaseContext.GetElementById(id); if (dto?.Name?.Contains("sto")) return true; return false; }

我们判断一个dto是否是vip,如果传入id为null返回false,如果不是则获取一个对象,如果对象的名字包含sto关键字则返回true

比如我们知道id为9527的对象为sto,因此它是个vip,我们的测试方法如下

[Test] public void ShouldReturn_True_If_Id_Is_9527() { var moq = new Mock<IDataBaseContext<MyDto>>(); moq.Setup(a => a.GetElementById(It.Is<string>(t => t.Trim() == "9527"))).Returns(new MyDto { Name = "sto", Age = 24 }); MyBll bll = new MyBll(moq.Object); bool isVip = bll.IsVip("9527"); Assert.True(isVip); }

以上测试通过.

MOCk.Of

我们以上仅配置了接口代表的一个方法,有时候需要配置多个,这样需要多个Setup,这时候我们可以使用Mock.Of,注意Mock.Of创建出来的是一个代理对象,而不是一个mock对象.

[Test] public void MockOf_Test() { var obj = Mock.Of<IDataBaseContext<MyDto>>(a =>a.GetAll()==new List<MyDto>(){new MyDto()} &&a.GetElementById(It.IsAny<string>())==new MyDto() &&a.GetElementsByName(It.IsAny<string>())==new MyDto[3]); var all = obj.GetAll(); var one = obj.GetElementById("s"); var some = obj.GetElementsByName("somename"); Assert.Multiple(() => { Assert.AreEqual(1, all.Count()); Assert.NotNull(one); Assert.AreEqual(3, some.Count()); }); }

以上测试会通过.

注意以上的xxx==xxx并不是比较两个对象,Mock利用它进行赋值

很多初接触单元测试的朋友看完以上代码后可能感觉一脸懵,完全不理解利用moq在dao层生成一些看似无意义的假数据有什么意义,其实大家要明白单元测试的目的是什么,单元测试是以代码块为基础(通常是一个方法),测试这一个单元逻辑的正确性,在dao层,我们只关心这一层拿到数据后的处理逻辑.很多朋友可能知道ef可以搭建内存服务器来模拟真实数据库,这样也同样不依赖于外部的数据库.其实大家也可以这样做,也可以不这样而使用moq来模拟一个数据库连接上下文对象.因为在单元测试里,真实的数据是什么样的并不是首要关心的问题,而是这个代码单元逻辑的正确性.如果是做集成测试,我们则需要模拟一个真实环境,这个时候我们就需要使用内存服务器甚至使用外部服务器.当然,如果要做压力测试,我们还需要模拟产品运行时真实的物理环境,网络环境等条件(当然,很多时候直接在真实的运行环境进行测试了).总之我们要搞清楚不同的测试要解决什么样的问题,要达到什么样的目的,剩下的才是工具框架的使用.

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsxxpw.html