这段日子的开发一直使用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

最新文章

  1. Linux实战教学笔记02:计算机系统硬件核心知识
  2. eclipse提高效率 MAC
  3. css之首字母大写 | 全部大写 | 全部小写 | text-transform
  4. 使django与数据库保持长连接
  5. [python]实现单机版一行wordcount
  6. tarjan算法 POJ3177-Redundant Paths
  7. (转)从工程中删除Cocoapods
  8. [转]利用vertical-align:middle实现在整个页面居中
  9. Bzoj 2662: [BeiJing wc2012]冻结 dijkstra,堆,分层图,最短路
  10. 新一代 PHP 加速插件 Zend Opcache &lt;转&gt;
  11. JS打印、预览(IE,Chrome)
  12. 华为G520联通版刷机包 基于MIUI CM11新 平稳 稳定
  13. NSMutableDictionary
  14. python基础2 数据类型、数据拼接、数据转换
  15. 小谈对Python的认知与期望
  16. js判断字段是否为空 isNull
  17. (未完结)“文远知行杯”GDET第十四届竞赛(网络赛共10题,仅整理出6题)
  18. php integer
  19. mfc CProgressCtrl
  20. JavaScript学习笔记系列2:Dom操作(一)

热门文章

  1. 【springboot】之自动配置原理
  2. canvas一些属性
  3. mvc中让路由忽略带后缀的路径文件
  4. Webpack 学习总结
  5. C/C++中指针和java的引用区别
  6. sqlserver查找使用了某个字段的所有存储过程
  7. 五、Python-字典与集合
  8. mysql 动态行转列
  9. 【学习】数据处理基础知识(缺失值处理)【pandas】
  10. orcal - 增删改