HTML5技术

ASP.NET 系列:单元测试 - #王刚(2)

字号+ 作者:H5之家 来源:博客园 2016-02-20 11:00 我要评论( )

伪对象可以解决要测试的代码中使用了无法测试的外部依赖问题,更重要的是通过接口抽象实现了低耦合。例如通过抽象IConfigurationManager接口来使用ConfigurationManager对象,看起来似乎只是为了单元测试而增加更多

伪对象可以解决要测试的代码中使用了无法测试的外部依赖问题,更重要的是通过接口抽象实现了低耦合。例如通过抽象IConfigurationManager接口来使用ConfigurationManager对象,看起来似乎只是为了单元测试而增加更多的代码,实际上我们通常不关心后去的配置是否是通过ConfigurationManager静态类读取的config文件,我们只关心配置的取值,此时使用IConfigurationManager既可以不依赖具体的ConfigurationManager类型,又可以在系统需要扩展时使用其他实现了IConfigurationManager接口的实现类。

使用伪对象解决外部依赖的主要步骤:

(1)使用接口依赖取代原始类型依赖。

(2)通过对原始类型的适配实现上述接口。

(3)手动创建用于单元测试的接口实现类或在单元测试时使用Mock框架生成接口的实例

手动创建的实现类完整的实现了接口,这样的实现类可以在多个测试中使用。可以选择使用Mock框架生成对应接口的实例,只需要对当前测试需要调用的方法进行模拟,通常需要根据参数进行逻辑判断,返回不同的结果。无论是手动实现的模拟类对象还是Mock生成的伪对象都称为桩对象,即Stub对象。Stub对象的本质是被测试类依赖接口的伪对象,它保证了被测试类可以被测试代码正常调用。

解决了被测试类的依赖问题,还需要解决无法直接在被测试方法上使用Assert断言的情况。此时我们需要在另一类伪对象上使用Assert,通常我们把Assert使用的模拟对象称为模拟对象,即Mock对象。Mock对象的本质是用来提供给Assert进行验证的,它保证了在无法直接使用断言时可以正常验证被测试类。

Stub和Mock对象都是伪对象,即Fake对象

Stub或Mock对象的区分明白了就很简单,从被测试类的角度讲Stub对象,从Assert的角度讲Mock对象。然而,即使不了解相关的含义和区别也不会在使用时产生问题。比如测试邮件发送,我们通常不能直接在被测试代码上应用Assert,我们会在模拟的STMP服务器对象上应用Assert判断是否成功接收到邮件,这个SMTPServer模拟对象就是Mock对象而不是Stub对象。比如写日志,我们通常可以直接在ILogger接口的相关方法上应用Assert判断是否成功,此时的Logger对象即是Stub对象也是Mock对象。

5.单元测试常用框架和组件

(1)单元测试框架。

XUnit是目前最为流行的.NET单元测试框架。NUnit出现的较早被广泛使用,如nopCommerce、Orchard等项目从开始就一直使用的是NUnit。XUnit目前是比NUnit更好的选择,从github上可以看到asp.net mvc等一系列的微软项目使用的就是XUnit框架。

(2)Mock框架

Moq是目前最为流行的Mock框架。Orchard、asp.net mvc等微软项目使用Moq。nopCommerce使用Rhino MocksNSubstitute和FakeItEasy是其他两种应用广泛的Mock框架。

(3)邮件发送的Mock组件netDumbster

可以通过nuget获取netDumbster组件,该组件提供了SimpleSmtpServer对象用于模拟邮件发送环境。

通常我们无法直接对邮件发送使用Assert,使用netDumbster我们可以对模拟服务器接收的邮件应用Assert。

public void SendMailTest() { SimpleSmtpServer server = SimpleSmtpServer.Start(25); IEmailSender sender = new SMTPAdapter(); sender.SendMail(, , , ); Assert.Equal(1, server.ReceivedEmailCount); SmtpMessage mail = (SmtpMessage)server.ReceivedEmail[0]; Assert.Equal(, mail.Headers[]); Assert.Equal(, mail.Headers[]); Assert.Equal(, mail.Headers[]); Assert.Equal(, mail.MessageParts[0].BodyData); server.Stop(); }

(4)HttpContext的Mock组件HttpSimulator

同样可以通过nuget获取,通过使用HttpSimulator对象发起Http请求,在其生命周期内HttContext对象为可用状态。

由于HttpContext是封闭的无法使用Moq模拟,通常我们使用如下代码片断:

private HttpContext SetHttpContext() { HttpRequest httpRequest = , ""); StringWriter stringWriter = new StringWriter(); HttpResponse httpResponse = new HttpResponse(stringWriter); HttpContext httpContextMock = new HttpContext(httpRequest, httpResponse); HttpContext.Current = httpContextMock; return HttpContext.Current; }

使用HttpSimulator后我们可以简化代码为:

using (HttpSimulator simulator = new HttpSimulator()) { }

这对使用IoC容器和EntityFramework的程序的DbContext生命周期的测试十分重要,DbContext的生命周期必须和HttpRequest一致,因此对IoC容器进行生命周期的测试是必须的。

6.使用单元测试的难处

(1)不愿意付出学习成本和改变现有开发习惯。

(2)没有思考的习惯,错误的把单元测试当框架学。

(3)在项目后期才应用单元测试,即获取不到单元测试的好处又因为代码的测试不友好对单元测试产生误解。

(4)拒绝考虑效率、扩展性和解耦,只考虑数据和功能的实现。

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • HTML5 进阶系列:拖放 API 实现拖放排序 - _林鑫

    HTML5 进阶系列:拖放 API 实现拖放排序 - _林鑫

    2017-05-02 11:02

  • 如何在 ASP.NET Core 中发送邮件 - Savorboard

    如何在 ASP.NET Core 中发送邮件 - Savorboard

    2017-05-02 08:02

  • JS组件系列——自己动手封装bootstrap-treegrid组件 - 懒得安分

    JS组件系列——自己动手封装bootstrap-treegrid组件 - 懒得安分

    2017-04-28 14:02

  • 十二个 ASP.NET Core 例子 - Savorboard

    十二个 ASP.NET Core 例子 - Savorboard

    2017-04-27 16:01

网友点评
e