这段日子的开发一直使用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. Windows7环境下Excel2010中图片超链接默认打开程序修改

    在Windows7的环境下,打开Excel2010超链接图片,都是默认用IE打开.搜索了所有的中文网络,没有找到解决方案,且发现受此困扰的人不少.后来用纯英文搜索,终于找到解决方案并尝试成功. 1,操 ...

  2. DApp demo之pet-shop

    注意: 这里使用的truffle版本为4.1.4,貌似使用高版本在truffle test时候会出问题,提示 truffle/Assert.sol is not found等错误 使用Truffle ...

  3. JavaScript最后的课程笔记

    一.快捷位置和尺寸 DOM已经提供给我们计算后的样式,但是还觉得不方便,所以DOM又提供给我们一些API: ele.offsetLeft ele.offsetTop ele.offsetWidth e ...

  4. iptables和netfilter

    1.iptables和netfilter说明 [1]netfilter/iptables组成Linux平台下的包过滤防火墙,iptables是用户空间的管理工具,netfilter是内核空间的包处理框 ...

  5. 生产者消费者synchronized wait notify

    package ProduceQueueProduce; import java.util.Queue; public class ProducerThread extends Thread { pu ...

  6. 淘宝App直播宝贝数据采集

    淘宝App直播宝贝数据采集   前段时间,有人问我关于淘宝app直播频道宝贝如何采集?我尝试了下可以获取的到,模拟器登录不了淘宝,这里有一个坑就是,模拟器有时候会跳到登录页面,登录不了淘宝: 一.用A ...

  7. Mock Server

    下载地址:https://repo1.maven.org/maven2/com/github/dreamhead/moco-runner/ 此处使用standalone的方式,不使用api用法 启动方 ...

  8. GNU C和C99标准中的可变参数宏(variadic macros)

    用可变参数宏(variadic macros)传递可变参数表你可能很熟悉在函数中使用可变参数表,如: void printf(const char* format, …); 直到最近,可变参数表还是只 ...

  9. postgre索引

    1.创建一般索引 单字段索引: CREATE INDEX index_name ON table_name (field1); 联合索引: CREATE INDEX index_name ON tab ...

  10. DeprecationWarning

    当我在导入sklearn这个库的时候,程序抛出了一个丢弃警告,它的意思是在版本更新后imp库已经不用了,用importlib来代替这个库 Warning (from warnings module): ...