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

    Axure RP 7.0 用户名:axureuser 序列号:8wFfIX7a8hHq6yAy6T8zCz5R0NBKeVxo9IKu+kgKh79FL6IyPD6lK7G6+tqEV4LG Axur ...

  2. android SDK 安装

      Android SDK在线更新镜像服务器 参见:http://www.androiddevtools.cn/   1. 启动 Android SDK Manager ,打开主界面,依次选择『Too ...

  3. E3Upload项目总结

    项目需求:读取阿里云数据库数据,通过webservice接口上传给第三方. 概要设计,项目满足以下几点: 1.动态接口调用 2.给多平台上传 3.数据保持(减轻数据库压力) 4.上传任务管理 5.扩展 ...

  4. 通过 phpmyadmin getshell

    通过 phpmyadmin  getshell general_log默认为关闭的,root权限开启后,general_log_file会保存所有的查询语句 可以开启general_log,然后设置g ...

  5. Webpack 学习总结

    1.Webpack的特性 webpack 模块打包机,分析你的项目结构,找到JavaScript模块以及其他一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),将其打包为合适的格式以 ...

  6. 最近想学Json,请问大家有没有什么好的Json教程介绍一下?

    最近想学json,请问大家有没有什么好的Json教程介绍一下? 最近学完java的框架了,想了解一下json,可是找不到相关视频,请大家有这方面的Json教程好资料就介绍下啦,最后有网址链接啦. {} ...

  7. python 模拟百度搜索

    import urllib.request def Url(url): flag = input("请输入要搜索的关键字:") headers_ = { "User-Ag ...

  8. [java 2019-04-09] 代码生成word文档中的表格嵌套问题

    public static void createContent3(Date adtStart, Date adtEnd, Map<String, Object> aMap,Map< ...

  9. jQuery人民币转大写,C#人命币转大写

    jQuery人民币转大写 function convertCurrency(money) { //汉字的数字 var cnNums = new Array('零', '壹', '贰', '叁', '肆 ...

  10. leetcode每日刷题计划-简单篇day13

    Num 169 先码,回头再说,摩尔算法... tle了 class Solution { public: int majorityElement(vector<int>& num ...