这段日子的开发一直使用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的更多相关文章

随机推荐

  1. spring boot项目中处理Schedule定时任务

    项目中,因为使用了第三方支付(支付宝和微信支付),支付完毕后,第三方支付平台一般会采用异步回调通知的方式,通知商户支付结果,然后商户根据通知内容,变更商户项目支付订单的状态.一般来说,为了防止商户项目 ...

  2. python3学习笔记12(变量作用域)

    变量作用域 参考http://www.runoob.com/python3/python3-function.html Python 中,程序的变量并不是在哪个位置都可以访问的,访问权限决定于这个变量 ...

  3. Linux常见企业面试题

    1:只查看test.txt (100行)文件中第20行到30行的数据(企业常见面试题) 答: seq (序列) 第一种方法:head -30 test1.txt | tail -11 第二种方法:se ...

  4. Mybatis常见疑问

    1.在连接数据库时候,mysql是否支持fetchsize分页获取? 满足以下几个条件,可以使用fetchsize,根据游标获得记录 ①MySQL 从5.0.2开始支持分页获得. ②同时需要在jdbc ...

  5. angular4中引入quill editor

    1. npm install --save-dev @types/quill  安装types 2.npm install ng2-quill-editor --save 安装quill 3.配置ts ...

  6. vue-cli 发布部署IIS

    有些时候我们的服务器不用的是node,也许是IIS,这样就需要把工程构建出来,与IIS集成. 构建的命令如下 cnpm run build 将其中的dist文件夹拷贝出来,放到IIS的发布目录,在浏览 ...

  7. 如何解决button,a,input标签自带蓝色边框

    通常我们会设置该标签outline:0;但是我在使用iview自带的button组件的时候,设置无效,经过测试只要设置 :focus{      outline:0; }  即可,方便有效

  8. 微信小程序学习 一

    1. 目录结构 app.js  —— 必须配置Page({})  在新版本中 app.json  —— 注册,路由不用加后缀,是将整个文件里面的四个文件都注册进去,并且做关联,所以在页面中就不需要引用 ...

  9. (Python基础)最Low三级菜单

    #-*-coding:utf-8-*- #_author_: Keep #三级菜单 menu = { '中国':{ '广东省':{ '广州市':{ '海珠区':{}, '荔湾区':{}, '越秀区': ...

  10. djangorestframework-jwt自带的认证视图进行用户登录验证源代码学习

    Django REST framework JWT djangorestframework-jwt自带的认证视图进行用户登录验证源代码学习 SECRET_KEY = '1)q(f8jrz^edwtr2 ...