step_by_step_xUnit_Net_ABP
这段日子的开发一直使用Asp.net Boilerplate ,称之为项目模板自然就有开发中常用的功能,测试框架也在其中,土牛的ABP源代码都有通过测试,很遗憾的是我之前没有写过测试,不会就要去找资料查找一下测试开发的概念。
这篇随笔就是要记录一下发生在自己身上的Getting Started with Testing。
软件测试 (software testing) 描绘一种用来促进鉴定软件的正确性、完整性、安全性和质量的过程,软件测试永远不可能完整的确立任意电脑软件的正确性。然而,在可计算理论(计算机科学的一个支派) 一个简单的数学证明推断出下列结果:不可能完全解决所谓“死机”,指任意计算机程序是否会进入死循环,或者罢工并产生输出问题。换句话说,软件测试是一种实际输出与预期输出间的审核或者比较过程。软件测试的经典定义是:在规定的条件下对程序进行操作,以发现程序错误,衡量软件质量,并对其是否能满足设计要求进行评估的过程。想想其实编程中测试无处不在,没有测试我们无法相信代码就一定可以正常执行。之前就遇到过这样的一些事如果代码写的多了,一个业务的执行操作要执行很多个方法,而且最后要去第三方接口拿回来数据在操作数据库,这样如果我要验证数据和仓储方法就要走完整个流程,有了单元测试这个问题就变得很好处理,单元测试 又称模块测试 是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。
既然测试如此的重要,.NET平台下也自然有针对测试开发的组件,XUNIT,NUNIT 这些都是用于.NET 平台下的测试工具,ABP项目模板中使用了XUNIT ,于是我也先看看XUNIT的介绍 ,中文的以后发出来...
XUNIT 的这篇介绍写的很简单,它有Fact,Theory的注解对方法测试,接下来的ABP项目中我便使用了它们。
在ABP中我将这部分的实现放到了单独的模块中
Application , Core ,EntityFramework ,Web ,WebApi , SACSLibrary
下边的图是具体改写的地方:
在SACSLibrary中我对SS(GDS)的最佳实践进行了改写,去除了一些对当前账号没有用处的服务,暂时性的把REST API 查询的这部分拿过来改写,它的REST 查询功能需要一个 SESSION LESS ,而且每次获取一个SESSION 它的生命周期长达一周,这就意味着我这一周的时间内只要是去做查询操作都可以用这个相同的SESSION。这就存在一个问题如何维护SESSION从而保证每次查询操作都能正常完成?自己写服务感觉有点麻烦,早早听说ABP有后台工作者这个便捷的功能,看来这次可以用上了
[UnitOfWork]
protected async override void DoWork()
{
Logger.Debug("------backgroundworker begin"); using (CurrentUnitOfWork.DisableFilter(AbpDataFilters.MayHaveTenant))
{
var validtokens = _tokenDetailsRepository.FirstOrDefault(t => t.IsValid); if (validtokens == null || System.DateTime.Now >= validtokens.ExpirationDate)
{
if (validtokens != null)
{
validtokens.IsValid = false;
}
string clientid = _authorizationManager.CreateCredentialsString(_authorizationManager.CurrenConfig.UserId, _authorizationManager.CurrenConfig.Group, _authorizationManager.CurrenConfig.ClientSecret);
var response = await _authorizationManager.AuthorizeAsync(clientid);
TokenHolder tokenHolder;
if (response.IsSuccess)
{
var value = response.Value;
tokenHolder = TokenHolder.Valid(value.AccessToken, value.ExpiresIn);
TokenDetail _td = new TokenDetail()
{
IsValid = true,
Token = tokenHolder.Token,
ExpirationDate = tokenHolder.ExpirationDate
};
_tokenDetailsRepository.Insert(_td);
Timer.Period =(int)(_td.ExpirationDate - System.DateTime.Now).TotalMilliseconds;
Logger.Debug(Timer.Period.ToString()+"之后执行");
}
else
{
tokenHolder = TokenHolder.Invalid(response.StatusCode, response.Message);
_tokenDetailsRepository.Insert(new TokenDetail()
{
ErrorMessage = tokenHolder.ErrorMessage,
ErrorStatusCode = tokenHolder.ErrorStatusCode
});
Timer.Period = ;
}
}
else
{
Timer.Period = (int)(validtokens.ExpirationDate - System.DateTime.Now).TotalMilliseconds;
Logger.Debug($"下次执行更新在 {Timer.Period} 毫秒之后");
} } Logger.Debug("------backgroundworker end");
}
这样目前测试我将执行时间调的小一些可以通过,不过不知道有没有使用不当的地方。
这里边是调用获取SESSION LESS的方法,这个方法我在写单元测试的项目里边测试通过。因为里边用到了仓储,但是数据库里边的数据我又没有办法用于测试,Effort(Entity Framework Fake ObjectContext Realization Tool) 这个工具我目前只是知道他可以MOCK,可以用来模拟操作数据库其他的并不了解了。虽然我不知道怎么使用原始的Effort,但是ABP封装了它这很方便我们去使用。
测试SESSION LESS
[Fact]
public async void BFM_Session_LESS_Test_Create_token()
{
var _config = new SACS.Library.Configuration.SampleConfigProvider();
var obj = Resolve<IAuthorizationManager>(new
{
config = _config
});
string clientid = obj.CreateCredentialsString(_config.UserId, _config.Group, _config.ClientSecret);
var response = await obj.AuthorizeAsync(clientid);
TokenHolder tokenHolder;
if (response.IsSuccess)
{
var value = response.Value;
tokenHolder = TokenHolder.Valid(value.AccessToken, value.ExpiresIn);
}
else
{
tokenHolder = TokenHolder.Invalid(response.StatusCode, response.Message);
}
response.IsSuccess.ShouldBe<bool>(true);
}
测试这个MOCK Repository
[Fact]
public async void BFM_Session_LESS_Test_InsertToken_Reporitory()
{
UsingDbContext((context) =>
{
context.DisableAllFilters();
context.TokenDetails.Add(new TokenDetail()
{
IsValid = true,
ExpirationDate = System.DateTime.Now.AddDays(),
Token = "session_less"
}); });
var _repository = Resolve<IRepository<TokenDetail>>();
_repository.ShouldNotBeNull();
var backid = await _repository.InsertAndGetIdAsync(new TokenDetail()
{
Token = "sdsdsdsdsdsdsdsdsdsdsd",
IsValid = true,
ExpirationDate = System.DateTime.Now.AddDays()
});
backid.ShouldBe();
}
测试改写之前的RestClient
[Fact]
public async void BFM_Query_Test_RestClient_Test()
{
UsingDbContext((context) =>
{
context.DisableAllFilters();
context.TokenDetails.Add(new TokenDetail()
{
IsValid = true,
ExpirationDate = System.DateTime.Now.AddDays(),
Token = "T1RLAQIQMgZTCKXi+NCWBKaZ0S48I4QxAKw3ZVQyGyXazuIBNnAACQJq5rbfyr1AvNa0Y/7nf+YgPh8QKen+BTOJOwB6SFs9JsvjQpeXAfZlBvvXc3Qi4amQ8SqK7DATQCDiNWcXurfd77naZwwAczgjGc1LPF1XK3AXpV7N8Z2OtN3COZIyK4vAu+SK6IdHU3p/"
}); });
var configs = Resolve<SACS.Library.Configuration.IConfigProvider>();
configs.ShouldNotBeNull();
var _tokendetail = Resolve<IRepository<TokenDetail>>();
_tokendetail.ShouldNotBeNull();
_tokendetail.Count().ShouldBe();
var _tokenmangager = Resolve<IAuthorizationManager>(new
{
config = configs }); _tokenmangager.ShouldNotBeNull(); var _restclient = Resolve<RestClient>(new
{
config = configs,
tokendetailrepository = _tokendetail,
restAuthorizationManager = _tokenmangager }); BargainFinderMaxPostRQ _bfmpostrq = new BargainFinderMaxPostRQ()
{
//......略
};
IActivity activity = new BargainFinderMaxActivity(_restclient, _bfmpostrq);
Workflow workflow = new Workflow(activity);
SharedContext sharedContext = await workflow.RunAsync();
BargainFinderMaxVM model = ViewModelFactory.CreateBargainFinderMaxVM(sharedContext);
model.ErrorMessage.ShouldBeEmpty();
model.ResponseJson.ShouldNotBeNullOrEmpty();
}
测试改写之后的RestClient ,用Theory 特性标注并指定了多组测试数据
public class BFM_Test_Data
{
public static IEnumerable<object[]> BargainFinderMaxPostRQCs {
get {
return new[] {
new object[] {
BFM_Query_Test_RestClient_LoadCpData1() // 略
},new object[] {
BFM_Query_Test_RestClient_LoadCpData2() //略
},
new object[] {
BFM_Query_Test_RestClient_LoadCpData3() //略
}
};
} }
}
测试方法:
[Theory]
[MemberData("BargainFinderMaxPostRQCs",MemberType = typeof(BFM_Test_Data))]
public async void BFM_Query_Test_RestClient_TestCP(BargainFinderMaxPostRQCP cp)
{
/// ......略
}
好了,今天就记录到这里了。╰( ̄▽ ̄)╭
相关的文档 :
:Using Effort -Entity Framework Unit Testing Tool
:Getting Started With XUnit.net(Destop)
:Unit Testing in C# using XUnit,Entity Framework,Effort and ASP.NET Boilerplate
:xUnit Theory,the Data Driven Unit Test
step_by_step_xUnit_Net_ABP的更多相关文章
随机推荐
- iOS9.3描述文件怎么安装
iOS9.3 beta描述文件安装教程:1.复制以下地址:http://bbs.feng.com/plugin.php?id=attachment_download:tongji&aid=11 ...
- DataGridView导出数据到Excel
//传入DataGridView /// <summary> /// 输出数据到Excel /// </summary> /// <param name="da ...
- Redis深入学习笔记(三)RDB及AOF流程
RDB是Redis持久化数据的一种方式,是执行时间点的Redis内存快照,redis数据还原时加载rdb文件,Redis的主从数据同步也是基于RDB实现的. RDB流程: 1)执行bgsave命令,R ...
- 记录1-更换mac pro内存,硬盘及恢复系统
我的mac pro是2012年初买的,4G/500G HDD在服役了六年多后速度堪比老牛,以前装的虚拟机压根不敢打开.这几天把内存更换为8G,硬盘升级为samsung的1T SSD,感觉像起死回生一样 ...
- C#求一组数的众数
private int GetModeNum(List<int> listValue) { List<int> listName = new List<int>() ...
- jenkins部署web项目(不包含前后端分离)
本次部署的是非常非常传统的web项目, jsp页面那种, 一 首先给tomact设置管理员用户和管理员密码,这类的教程网上有很多,在<tomcat-users><tomcat-use ...
- Solr中的group与facet的区别
Solr中的group与facet的区别 如果是简单的使用的话,那么Facet与group都可以用来进行数据的聚合查询,但是他们还是有很大的区别的. 首先上facet跟group的操作: Facet的 ...
- Java高级框架------Spring(二)
五.如何给Bean的属性赋值(注入) 1. 通过构造方法来赋值 2. 设置注入(通过set方法) 2.1 如果属性是基本类型或String等简单 <bean id="peo" ...
- oracle填坑之PLSQL中文显示为问号
刚入坑oracle就遇到个坑. 坑描述: 系统:Windows7 oracle:同时安装,11g和12c(安装顺序,先装的12c然后装的11g) 坑:开始安装的12c用SQL Developer使用本 ...
- 使用JavaScript制作页面效果3
一. 1.下拉列表:select对象 属性: option[ ]:选项数组 selectedIndex:被选中选项的索引号 length:选项总数 方法: add(option对象,添加位置):增加选 ...