(此文章同时发表在本人微信公众号“dotNET每日精华文章”,欢迎右边二维码来关注。)

题记:虽然ABP为大家提供了测试的脚手架了,不过有些小技巧还是需要自己探索的。

ASP.NET Boilerplate(ABP)默认使用的单元测试的框架是xUnit,并且引入了NSubstitute这个便捷的Mock框架。但是有些具体的用法和技巧还是需要自己探索的。下面介绍两个小技巧。

为AppService注入Mock接口

假设我有一个和钉钉相关的AppService(接口名称为IDingtalkAppService),这个服务中会调用钉钉的sdk,为了在单元测试的时候避免真实的网络调用,所以我需要把这部分代码抽象为一个接口(比如名称为IDingtalkSdkService)。那么如何把IDingtalkSdkService 模拟注入到IDingtalkAppService中呢?

首先,在TestModule的PreInitialize中添加如下代码:

//Registering fake services
IocManager.IocContainer.Register(
Component.For<IAbpZeroDbMigrator>()
.UsingFactoryMethod(() => Substitute.For<IAbpZeroDbMigrator>())
.LifestyleSingleton(),
Component.For<IDingtalkSdkService>()
.UsingFactoryMethod(() => Substitute.For<IDingtalkSdkService>())
.LifestyleSingleton()
);

上面的代码通过NSubstitute为IDingtalkSdkService注册一个Mock。在测试类中,还是如ABP的惯例那样,通过Resolve来获取IDingtalkAppService的实现。只是在需要给Mock接口的方法设置Returns数据的时候,在测试方法中通过Resolve来现时获取到此接口的实例。如下:

var sdkService = Resolve<IDingtalkSdkService>();
sdkService.GetAllUserList(null, enterprise).Returns(

这种方式虽然最简单但有个缺陷,就是必须注册的时候要求注册为LifestyleSingleton(单例)。那么如果你依赖的外部接口无法以单例模式运行(这种情况应该极少),那么只有给IDingtalkAppService添加一个IDingtalkSdkService的属性SdkService,然后把上面的代码替换为appService.SdkService.GetAllUserList。

NSubstitute使用的更多帮助,请参考其官网:http://nsubstitute.github.io/

数据驱动的单元测试

准确说这不属于ABP的技巧是xUnit的技巧,只是ABP用到了xUnit,就一并提及。我们的业务逻辑可能会涉及到多个场景或者判断条件,为了测试每种情况,是为每种情况写一个测试方法并包含大量的重复代码,还是使用数据驱动注入测试数据到一个测试方法中,显然最好的方式是后者。

常见的单元测试框架都提供了数据驱动的支持:

就我的感受而言,xUnit处理数据驱动的方式更为自然。我采用了MemberData的方式来提供数据,就是写一个返回值为IEnumerable<object[]>的静态公共方法。

“不废话,直接上代码”,大家更能一目了然。示例代码见:http://git.oschina.net/ike/xbonmpl9wav062rsj71y872.code.git

通过这种方式,我检查出了一个判断错误,如下图:

ABP中单元测试的技巧:Mock和数据驱动的更多相关文章

  1. 在eclipse中使用JUnit4,以及使用JUnit4进行单元测试的技巧

    一 在eclipse中使用JUnit4 首先在工程上右键,选择属性,找到Java Builder Path,添加JUnit4的lib,如下图:   在要测试的类上右键新建 Junit test cas ...

  2. ABP中的依赖注入思想

    在充分理解整个ABP系统架构之前首先必须充分了解ABP中最重要的依赖注入思想,在后面会具体举出一些实例来帮助你充分了解ABP中的依赖注入思想,在了解这个之前我们首先来看看什么是依赖注入?来看看维基百科 ...

  3. ABP中使用Redis Cache(2)

    上一篇讲解了如何在ABP中使用Redis Cache,虽然能够正常的访问Redis,但是Redis里的信息无法同步更新.本文将讲解如何实现Redis Cache与实体同步更新.要实现数据的同步更新,我 ...

  4. 原!!关于java 单元测试Junit4和Mock的一些总结

    最近项目有在写java代码的单元测试,然后在思考一个问题,为什么要写单元测试??单元测试写了有什么用??百度了一圈,如下: 软件质量最简单.最有效的保证: 是目标代码最清晰.最有效的文档: 可以优化目 ...

  5. ABP源码分析二:ABP中配置的注册和初始化

    一般来说,ASP.NET Web应用程序的第一个执行的方法是Global.asax下定义的Start方法.执行这个方法前HttpApplication 实例必须存在,也就是说其构造函数的执行必然是完成 ...

  6. ABP源码分析三十五:ABP中动态WebAPI原理解析

    动态WebAPI应该算是ABP中最Magic的功能之一了吧.开发人员无须定义继承自ApiController的类,只须重用Application Service中的类就可以对外提供WebAPI的功能, ...

  7. ABP源码分析四十七:ABP中的异常处理

    ABP 中异常处理的思路是很清晰的.一共五种类型的异常类. AbpInitializationException用于封装ABP初始化过程中出现的异常,只要抛出AbpInitializationExce ...

  8. ios开发中的小技巧

    在这里总结一些iOS开发中的小技巧,能大大方便我们的开发,持续更新. UITableView的Group样式下顶部空白处理 //分组列表头部空白处理 UIView *view = [[UIViewal ...

  9. 背水一战 Windows 10 (21) - 绑定: x:Bind 绑定, x:Bind 绑定之 x:Phase, 使用绑定过程中的一些技巧

    [源码下载] 背水一战 Windows 10 (21) - 绑定: x:Bind 绑定, x:Bind 绑定之 x:Phase, 使用绑定过程中的一些技巧 作者:webabcd 介绍背水一战 Wind ...

随机推荐

  1. Eclipse中的搜索快捷键

    Ctrl+H 全文搜索Ctrl+F 当前文件Ctrl+Shift+T 类文件Ctrl+Shift+R 资源文件

  2. php扩展memcached和memcache的安装配置方法:转载

    本文转载:http://www.jb51.net/article/56999.htm php连接memcached缓存服务器的客户端有两个,一个是memcache是比较底层的开发库,memcached ...

  3. SQL 实用函数

    CREATE FUNCTION [dbo].[varcharmax2table] ( @value VARCHAR(MAX) , @separator VARCHAR(255) ) RETURNS T ...

  4. linux查看端口占用情况

    今天要使用python写一个端口探测的小程序,以检测一些特定的服务端口有没有被占用,突然发现自己居然不知道在linux中如何查询端口被占用的情况,天呐,赶快学习一下.

  5. 2.2、Hibernate用注解方式实现一对多、多对多关系

    一.一对多关系 1.在上一篇日志中用.xml配置文件项目基础上,再往lib目录先添加一个包-hibernate-jpa-2.0-api-1.0.0.Final.jar 2.新建一个com.st.bea ...

  6. IP分片详解

    IP分片是网络上传输IP报文的一种技术手段.IP协议在传输数据包时,将数据报文分为若干分片进行传输,并在目标系统中进行重组.不同的链路类型规定有不同最大长度的链路层数据帧,称为链路层MTU(最大传输单 ...

  7. hdu 4481 Time travel(高斯求期望)(转)

    (转)http://blog.csdn.net/u013081425/article/details/39240021 http://acm.hdu.edu.cn/showproblem.php?pi ...

  8. Redis 缓存过期(maxmemory) 配置/算法 详解

    LRU(Least Recently Used) 最近最少使用算法是众多置换算法中的一种. Redis中有一个 maxmemory 概念,主要是为了将使用的内存限定在一个固定的大小.Redis 用到的 ...

  9. C++程序设计基础

    01 1 预编译常用的有,宏定义和包含库.2 库:是实用工具的集和,由程序员编写,可以完成一些特定的功能.3 <> 系统库 ""用户自定义库.4 宏定义:定义符号常量, ...

  10. PHP延迟静态绑定

    类可以自下往上调用父类方法,如果需要在父类中根据不同的子类,来调用子类的方法,那么就需要延迟静态绑定.延迟静态绑定用的是保留关键词static. 所谓延迟静态绑定,顾名思义,静态调用时::符号左侧的部 ...