ASP.NET MVC之单元测试分分钟的事

发表于:2014-8-07 10:29

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:王威    来源:51Testing软件测试网采编

  这里其实已经以假乱真了,因为真实的接口IStudentRepository里边的方法GetStudentById在实际中肯定要要访问数据库的,那么我们这里压根都么有访问什么数据库,直接用IStudentRepository接口模拟了一个对象,根本不用实现,这样瞬间就提高了单元测试的可行性。不过这里也要提个醒,就是在写代码的时候,别让代码产生过度的依赖,方可在进行单元测试时顺利进行!
  说说常用的Moq成员:
  1、Mock<T>:通过这个类我们能够得到一个Mock<T>对象,T可以是接口和类。它有一个公开的Object属性,这个就是我们Moq为我们模拟出的对象。
  var mo = new Mock<IStudentRepository>();
  mo.Object //其实就是模拟实现IStudentRepository接口的对象
  2、It:这是一个静态类,用于过滤参数。
  It很适合用来匹配数字,字符串参数,它提供了如下几个静态方法:
  Is<TValue> :参数为Expression<Predict<TValue>>类型,当你需要某种类型并且这种类型要通过代码来判断的话可以使用它。
  IsAny<TValue> :没有参数,只要是TValue类型的就能匹配成功。
  IsInRange<TValue> :用来匹配两个的TValue类型值之间的参数。(Range参数可以设定开闭区间)
  IsRegex:用正则表达式匹配。(仅限于字符串类型参数)
  var customer = new Mock<ICustomer>();
  customer.Setup(x => x.SelfMatch(It.Is<int>(i => i % 2 == 0))).Returns("1");//方法SelfMatch接受int型参数,当参数为偶数时,才返回字符串1。
  customer.Setup(p => p.SelfMatch(It.IsAny<int>())).Returns((int k) => "任何数:" + k);//方法SelfMatch接受int型,且任何int型参数都可以,然后返回:"任何数:" + k。
  customer.Setup(p => p.SelfMatch(It.IsInRange<int>(0, 10, Range.Inclusive))).Returns("10以内的数");//方法SelfMatch接受int型,且当范围在[0,10]时,才返回10以内的数
  customer.Setup(p => p.ShowException(It.IsRegex(@"^\d+$"))).Throws(new Exception("不能是数字"));//用正则表达式过滤参数不能是数字
  3、MockBehavior:用于配置MockObject的行为,比如是否自动mock。
  Moq有个枚举类型MockBehavior,有三个值Strict,Loose,Default。
  Strict表示Mock对象在调用一个方法前这个方法必须被Mock掉,否则就会引发MockException。而Loose与之相反,如果调用没有Mock的方法也不会出错。Default默认为Loose。例如:
[TestMethod]
public void MoqTest()
{
var mo = new Mock<ICustomer>(MockBehavior.Strict);
mo.Object.Method();//在MockBehavior.Strict设置下,一切调用未填充的方法/属性/事件时会抛出异常
}
  4、MockFactory:Mock对象工厂,能够批量生产统一自定义配置的Mock对象,也能批量的进行Mock对象测试。
  这是一个模拟对象的工厂,我们不可以成批Mock它们,例如:
var factory = new MockFactory(MockBehavior.Strict) { DefaultValue = DefaultValue.Mock };
// Create a mock using the factory settings
var aMock = factory.Create<IStudent>();
// Create a mock overriding the factory settings
var bMock = factory.Create<ITeacher>(MockBehavior.Loose);
// Verify all verifiable expectations on all mocks created through the factory
factory.Verify();
  5、Match<T>:如果你先觉得It不够用就用Match<T>,通过它能够完全自定义规则。
  还是举个栗子比较能说明问题
[TestMethod()]
public void MoqTest()
{
var mo = new Mock<IRepository>();
mo.Setup(p => p.Method(MatchHelper.ParamMatcher("wang"))).Returns("success");
Assert.AreEqual(mo.Object.("wang"), “success);
}
//此处就实现了自定义的参数匹配
public static class MatchHelper
{
public static string ParamMatcher(string name)
{
return Match<string>.Create(
p => p.Equals(name));
}
}
  6、Verify和VerifyAll
  用于测试mock对象的方法或属性是否被调用执行,Verify必须要先调用Verifiable()方法才能用,而VerifyAll不用这样就可以对所有的mock对象进行验证,例如:
public void TestVerify()
{
var customer = new Mock<ICustomer>();
customer.Setup(p => p.GetCall(It.IsAny<string>()))
.Returns("方法调用").Verifiable();//必须调用Verifiable()方法才可以
customer.Object.GetCall("调用了!");
customer.Verify();
}
public void TestVerifyAll()
{
var customer = new Mock<ICustomer>();
customer.Setup(p => p.GetCall(It.IsAny<string>()))
.Returns("方法调用"); //没有显式调用Verifiable()方法也可以
customer.Object.GetCall("调用了!");
customer.VerifyAll();
}
  7、Callback
  其实就是回调,使用Callback可以使我们在某个使用特定参数匹配的方法在被调用时得到通知。当执行某方法时,调用其内部输入的(Action)委托,例如:
public void TestCallback()
{
var customer = new Mock<ICustomer>();
customer.Setup(p => p.GetCall(It.IsAny<string>()))
.Returns("方法调用")
.Callback((string s)=>Console.WriteLine("ok"+s));
customer.Object.GetCall("x");
}
  五、ASP.NET MVC单元测试应用
  几点建议:
  1、每当你向controller、service、repository层中添加一系列的新函数时,从你开始修改代码的那一刻开始,你就必须得承担有可能破坏原本正常工作的那部分功能的风险。言外之意,你必须进行单元测试才行。
  2、单元测试必须是可以快速执行的。因此对于耗时的数据库交互来说,你必须对其进行mock,然后编写代码与mock的数据库进行交互
  3、你不必为view进行单元测试。因为要想对view进行测试,你就不得不搭建web服务器。因为搭建web服务器相对来说很耗时,因此并不推荐针对view进行单元测试。 如果你的view包含大量复杂的逻辑,则你应当考虑将这些逻辑转移到Helper方法中。你可以针对Helper方法编写单元测试且无需搭建web服务器。
  4、对于涉及到http的东东,你也必须mock一下
32/3<123>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号