• 系列教程
  • 开发文档
C# linq如何使用,无法识别方法等问题专场
C# linq如何使用,无法识别方法等问题专场
vs code 编辑器基础使用专题
vs code 编辑器基础使用专题
.NET/.NET Core面试题
.NET/.NET Core面试题
abp+vue-element-admin搭建个人网站
abp+vue-element-admin搭建个人网站
网站SEO优化专题,让搜索引擎对网站更有亲和力
网站SEO优化专题,让搜索引擎对网站更有亲和力
.NET Core基于abp vnext 开发个人网站【专题】
.NET Core基于abp vnext 开发个人网站【专题】
MySQL常见面试题
MySQL常见面试题
  • .NET Core FTP CoreFtp使用方法及示例(demo)代码

    本文主要介绍.NETCore中操作ftp的库CoreFtp的使用方法,CoreFTP是一个完全用C#编写的简单开源.NETFTP库,它针对netstandard1.6,这意味着它将在.NETCore(也就是它的名称)和完整的.NET框架下运行。这个软件包的启发是由于缺少提供FTP功能的软件包,并且支持netstandardAPI。

  • ABP编写单元测试

    首先来看下[Fact]的简单示例:public>Class1{[Fact]publicvoidPassingTest(){Assert.Equal(4,Add(2,2));}[Fact]publicvoidFailingTest(){Assert.Equal(5,Add(2,2));}intAdd(intx,inty){returnx+y;}}其中xUnit.Net提供了三种继承于DataAttribute的特性([InlineData]、[ClassData]、[PropertyData])用于为[Theory]标记的参数化测试方法传参。下面是使用这三种特性传参的实例:InlineDataExamplepublic>StringTests1{[Theory,InlineData("goodnightmoon","moon",true),InlineData("helloworld","hi",false)]publicvoidContains(stringinput,stringsub,boolexpected){varactual=input.Contains(sub);Assert.Equal(expected,actual);}}PropertyDataExamplepublic>StringTests2{[Theory,PropertyData("SplitCountData")]publicvoidSplitCount(stringinput,intexpectedCount){varactualCount=input.Split('').Count();Assert.Equal(expectedCount,actualCount);}publicstaticIEnumerable<object[]>SplitCountData{get{//Orthiscouldreadfromafile.:)returnnew[]{newobject[]{"xUnit",1},newobject[]{"isfun",2},newobject[]{"totestwith",3}};}}}ClassDataExamplepublic>{[Theory,ClassData(typeof(IndexOfData))]publicvoidIndexOf(stringinput,charletter,intexpected){varactual=input.IndexOf(letter);Assert.Equal(expected,actual);}}public>:IEnumerable<object[]>{privatereadonlyList<object[]>_data=newList<object[]>{newobject[]{"helloworld",'w',6},newobject[]{"goodnightmoon",'w',-1}};publicIEnumerator<object[]>GetEnumerator(){return_data.GetEnumerator();}IEnumeratorIEnumerable.GetEnumerator(){returnGetEnumerator();}}2.4.Shouldly(断言框架)Shouldly提供的断言方式与传统的Assert相比更实用易懂。对比一下就明白了:Assert.That(contestant.Points,Is.EqualTo(1337));//Expected1337butwas0contestant.Points.ShouldBe(1337);//contestant.Pointsshouldbe1337butwas0首先上写法上更清晰易懂,第二当测试失败时,提示消息也更清楚直接。同样,想对Shouldly有更对了解,请直接访问Shouldly官方链接。2.5.测试基类XxxTestBase首先来看看代码:publicabstract>LearningMpaAbpTestBase:AbpIntegratedTestBase<LearningMpaAbpTestModule>{privateDbConnection_hostDb;privateDictionary<int,DbConnection>_tenantDbs;//onlyusedfordbpertenantarchitectureprotectedLearningMpaAbpTestBase(){//SeedinitialdataforhostAbpSession.TenantId=null;UsingDbContext(context=>{newInitialHostDbBuilder(context).Create();newDefaultTenantCreator(context).Create();});//SeedinitialdatafordefaulttenantAbpSession.TenantId=1;UsingDbContext(context=>{newTenantRoleAndUserBuilder(context,1).Create();});LoginAsDefaultTenantAdmin();UsingDbContext(context=>newInitialDataBuilder().Build(context));}protectedoverridevoidPreInitialize(){base.PreInitialize();UseSingleDatabase();//UseDatabasePerTenant();}privatevoidUseSingleDatabase(){_hostDb=DbConnectionFactory.CreateTransient();LocalIocManager.IocContainer.Register(Component.For<DbConnection>().UsingFactoryMethod(()=>_hostDb).Life>从该段代码中我们可以看出该测试基类继承自AbpIntegratedTestBase<T>。在PreInitialize()方法中指定了为租户创建单一数据库还是多个数据库。_hostDb=DbConnectionFactory.CreateTransient();是Effort提供的方法用来创建的DbConnection(数据库连接)。然后将其使用单例的模式注册到IOC容器中,这样在测试中,所有的数据库连接都将使用Effort为我们创建的数据库连接。在构造函数中主要做了两件事,预置了初始数据和种子数据,并以默认租户Admin登录。至此我们对abp为我们默认创建的测试项目有了一个大概的认识。下面我们就开始实战阶段。3.单元测试实战3.1.理清要测试的方法逻辑我们以应用服务层的TaskAppService的CreateTask方法为例,创建单元测试。先来看看该方法的代码:publicintCreateTask(CreateTaskInputinput){//WecanuseLogger,it'sdefinedinApplicationService>.Info("Creatingataskforinput:"+input);//判断用户是否有权限if(input.AssignedPersonId.HasValue&&input.AssignedPersonId.Value!=AbpSession.GetUserId())PermissionChecker.Authorize(PermissionNames.Pages_Tasks_AssignPerson);vartask=Mapper.Map<Task>(input);intresult=_taskRepository.InsertAndGetId(task);//只有创建成功才发送邮件和通知if(result>0){task.CreationTime=Clock.Now;if(input.AssignedPersonId.HasValue){task.AssignedPerson=_userRepository.Load(input.AssignedPersonId.Value);varmessage="Youhavabeenassignedonetaskintoyourtodolist.";//TODO:需要重新配置QQ邮箱密码//SmtpEmailSenderemailSender=newSmtpEmailSender(_smtpEmialSenderConfig);//emailSender.Send("ysjshengjie@qq.com",task.AssignedPerson.EmailAddress,"NewTodoitem",message);_notificationPublisher.Publish("NewTask",newMessageNotificationData(message),null,NotificationSeverity.Info,new[]{task.AssignedPerson.ToUserIdentifier()});}}该方法主要有三步,第一步判断权限,第二步保存数据库并返回Id,第三步发送通知。3.2.创建单元测试类并注入依赖创建TaskAppSerice_Tests类并继承自XxxTestBase类,并注入需要的依赖。public>TaskAppService_Tests:LearningMpaAbpTestBase{privatereadonlyITaskAppService_taskAppService;publicTaskAppService_Tests(){_taskAppService=Resolve<TaskAppService>();}}3.3.创建单元测试方法第一个方法我们应该测试Happypath(即测试方法的默认场景,没有异常和错误信息)。[Fact]publicvoidShould_Create_New_Task_WithPermission(){//Arrange//LoginAsDefaultTenantAdmin();//基类的构造函数中已经以默认租户Admin登录。varinitalCount=UsingDbContext(ctx=>ctx.Tasks.Count());vartask1=newCreateTaskInput(){Title="TestTask",Description="TestTask",State=TaskState.Open};vartask2=newCreateTaskInput(){Title="TestTask2",Description="TestTask2",State=TaskState.Open};//ActinttaskResult1=_taskAppService.CreateTask(task1);inttaskResult2=_taskAppService.CreateTask(task2);//AssertUsingDbContext(ctx=>{taskResult1.ShouldBeGreaterThan(0);taskResult2.ShouldBeGreaterThan(0);ctx.Tasks.Count().ShouldBe(initalCount+2);ctx.Tasks.FirstOrDefault(t=>t.Title=="TestTask").ShouldNotBe(null);vartask=ctx.Tasks.FirstOrDefault(t=>t.Title=="TestTask2");task.ShouldNotBe(null);task.State.ShouldBe(TaskState.Open);});}在这里啰嗦一下单元测试的AAA原则:Arrange:为测试做准备工作Act:运行实际测试的代码Assert:断言,校验结果再说明一下单元测试的方法推荐命名规则:some_result_occurs_when_doing...回到我们这个测试方法。Arrange阶段我们先以Admin登录(Admin具有所有权限),然后获取数据库中初始Task的数量,再准备了两条测试数据。Act阶段,直接调用TaskAppService的CreateTask方法。Assert阶段:首先判断CreateTask的返回值大于0;再判断现在数据库的数量是否增加了2条;再校验数据库中是否包含创建的Task,并核对Task的状态。3.4.预置数据在进行测试的时候,我们肯定需要一些测试数据,以便我们进行合理的测试。在基础设施层,我们有专门的SeedData目录用来预置种子数据。但是进行单元测试的测试数据不应该污染实体数据库,所以直接在SeedData目录预置数据就不太现实。3.4.1.创建TestDataBuilder所以,我们就直接在测试项目中,新建一个TestDatas文件夹来管理测试种子数据。然后创建TestDataBuilder类,通过该类来统一创建所需的测试数据。(注意,需要修改下类中的_context类型为你自己项目对应的DbContext)namespaceLearningMpaAbp.Tests.TestDatas{public>TestDataBuilder{privatereadonlyLearningMpaAbpDbContext_context;privatereadonlyint_tenantId;publicTestDataBuilder(LearningMpaAbpDbContextcontext,inttenantId){_context=context;_tenantId=tenantId;}publicvoidCreate(){_context.DisableAllFilters();//newTestUserBuilder(_context,_tenantId).Create();//newTestTasksBuilder(_context,_tenantId).Create();_context.SaveChanges();}}}然后修改我们的测试基类XxxTestBase,在构造函数调用我们新建的TestDataBuilder的Create()方法。newTestDataBuilder(context,1).Create();,如下图:3.4.2.创建Task测试数据创建TestTasksBuilder,如下:(注意,需要修改下类中的_context类型为你自己项目对应的DbContext)namespaceLearningMpaAbp.Tests.TestDatas{public>TestTasksBuilder{privatereadonlyLearningMpaAbpDbContext_context;privatereadonlyint_tenantId;publicTestTasksBuilder(LearningMpaAbpDbContextcontext,inttenantId){_context=context;_tenantId=tenantId;}publicvoidCreate(){for(inti=0;i<8;i++){vartask=newTask(){Title="TestTask"+i,Description="TestTask"+i,CreationTime=DateTime.Now,State=(TaskState)newRandom().Next(0,1)};_context.Tasks.Add(task);}}}}然后再在TestDataBuild中调用该类的Create()的方法即可。newTestTasksBuilder(_context,_tenantId).Create();3.5.Runthetest(单元测试跑起来)UTPassed喜闻乐见的绿色,单元测试通过。3.6.完善测试用例单元测试中我们仅仅测试HappyPath是远远不够的。因为毕竟我们只是测试了正常的正确场景。为了提高单元测试的覆盖度,我们应该针对代码可能出现的异常问题进行测试。还拿我们刚刚的CreateTask方法为例,其中第二步有一个验证权限操作,当用户没有权限的时候,Task应该不能创建并抛出异常。那我们就针对无权限的场景补充一个单元测试吧。3.6.1.预置数据无权限简单,直接创建一个新用户登录就ok了。但为了用户复用,我们还是在种子数据中预置测试用户吧。回到我们的TestDatas目录,创建TestUserBuilder,来预置测试用户。namespaceLearningMpaAbp.Tests.TestDatas{///<summary>///预置测试用户(无权限)///</summary>public>TestUserBuilder{privatereadonlyLearningMpaAbpDbContext_context;privatereadonlyint_tenantId;publicTestUserBuilder(LearningMpaAbpDbContextcontext,inttenantId){_context=context;_tenantId=tenantId;}publicvoidCreate(){vartestUser=_context.Users.FirstOrDefault(u=>u.TenantId==_tenantId&&u.UserName=="TestUser");if(testUser==null){testUser=newUser{TenantId=_tenantId,UserName="TestUser",Name="TestUser",Surname="Test",EmailAddress="test@defaulttenant.com",Password=User.DefaultPassword,IsEmailConfirmed=true,IsActive=true};_context.Users.Add(testUser);}}}}然后再在TestDataBuild中调用该类的Create()的方法即可。newTestUserBuilder(_context,_tenantId).Create();3.6.2.完善单元测试///<summary>///若没有分配任务给他人的权限,创建的任务指定给他人,则任务创建不成功。///</summary>[Fact]publicvoidShould_Not_Create_New_Order_AssignToOrther_WithoutPermission(){//ArrangeLoginAsTenant(Tenant.DefaultTenantName,"TestUser");//获取admin用户varadminUser=UsingDbContext(ctx=>ctx.Users.FirstOrDefault(u=>u.UserName==User.AdminUserName));varnewTask=newCreateTaskInput(){Title="TestTask",Description="TestTask",State=TaskState.Open,AssignedPersonId=adminUser.Id//TestUser创建Task并分配给Admin};//Act,AssertAssert.Throws<AbpAuthorizationException>(()=>_taskAppService.CreateTask(newTask));}当用户无权限时,将抛出Abp封装的AbpAuthorizationException(未授权异常)。UTPassed单元测试用例,就讲这两个,剩下的自己动手完善吧。源码中已经覆盖测试,可供参考。4.总结这篇文章中主要梳理了Abp中如何进行单元测试,以及依赖的xUnit、Effort、Shouldly框架的用法。并基于以上内容的总结,进行了单元测试的实战演练。相信看完此篇文章的总结,对你在Abp中进行单元测试,有所裨益

  • .NET Core Autofac 4.0的配置和使用示例代码

    本文主要介绍.NETCore中依赖注入框架(DI)Autofac4.0配置和使用示例。

  • Java DocumentBuilderFactory( javax.xml)使用示例(demo)代码

    本文主要介绍Java中操作xml文件的DocumentBuilderFactory(javax.xml),包括一些使用的示例(demo)代码。

  • .NET(C#) CefSharp 下载获取页面中指定的文件图片视频等内容(.jpg、.js等)

    CefSharp访问和操纵页面上的内容,可以以编程方式执行JavaScript并将其嵌入到页面中,并在触发JavaScript事件时接收回调。您可以使用CefSharp显示使用HTML5构建的嵌入式UI,或显示远程Web内容和Web应用程序。GoogleChrome浏览器可以使用很多命令行(CommandLine)配置,有些更改功能的行为,而另一些则用于调试或试验。本文主要介绍.NET(C#)中,使用CefSharp时,下载获取网页中地址的文件图片视频等内容(.jpg、.js等)的方法,以及实现的示例代码。

  • .NET Core(C#)使用NPOI给Excel添加设置批注(注解comment)

    NPOI是POI项目的.NET版本。POI是一个开源的Java读写Excel、WORD等微软OLE2组件文档的项目,使用NPOI你就可以在没有安装Office或者相应环境的机器上对WORD/EXCEL文档进行读写。NPOI是构建在POI3.x版本之上的,它可以在没有安装Office的情况下对Word/Excel文档进行读写操作。本文主要介绍.NETCore(C#)中,使用NPOI将Excel(.xls,.xlsx)文件添加批注的方法,以及相关的示例代码。

  • ABP如何升级Abp并调试源码

    1.升级Abp本系列教程是基于AbpV1.0版本,现在Abp版本已经升级至V1.4.2,其中新增了NewFeature,并对Abp做了相应的Enhancements,以及Bugfixs。现在我们就把它升级至最新版本,那如何升级呢?下面就请按我的步骤来将Abp由V1.0升级至V1.4.2。1.1.过滤AbpNuget包VS打开解决方案文件,右键解决方案(不是某个项目),选中【管理解决方案的Nuget程序包(N)...】,如下图1.1。图1.1从图中可以看到,VS智能提示有42个Nuget包可升级,其中有2个Nuget程序包可合并。看到这个,不要犯了强迫症,就全部更新合并。要知道,Nuget程序包是相互依赖的,不一定最新的就能相互兼容。所以这一次,我们保险起见,只升级Abp相关Nuget程序包。选中【更新】,在搜索框中录入Abp进行筛选Abp相关Nuget程序包(一共16个)。1.2.更新Abp相关Nuget包勾选【选择所有的包】,并点击【更新】。VS会去分析解决方案下每个工程的Nuge包的依赖项,如下图1.2。图1.2分析完毕后,弹出分析结果,即每个工程将要更新哪些Nuget包,如图1.3。图1.3从图中可以发现,不仅仅是更新了Nuget包,依赖的相关包也将自动更新。毫无疑问,点击【确定】,紧接着会弹出一个【接受许可证】,如图1.4,点击【我接受】。图1.4观察输出窗口,发现VS已经开始下载要更新的Nuget包并安装,如图1.5。图1.5因为AbpV1.4.2已经支持TypeScript,VS解析到需要安装TypeScript,弹出图1.6所示对话框。图1.6点【是】进入下一步。稍等2分钟,即可成功安装,如图1.7。图1.71.3.编译项目编译项目,报了一堆错误,如图1.8。图1.8第一个错误好解决,是我们扩展AbpSesion出的错误。定位一看,原来是Abp修改了默认IAbpSession的实现类ClaimsAbpSession。我们只需要删除报错的构造方法,按下面方式更改即可:publicAbpSessionExtension(IPrincipalAccessorprincipalAccessor,IMultiTenancyConfigmultiTenancy,ITenantResolvertenantResolver,IAmbientScopeProvider<SessionOverride>sessionOverrideScopeProvider):base(principalAccessor,multiTenancy,tenantResolver,sessionOverrideScopeProvider){}接下来的错误都是Typescript报的错,需要安装下TypeScript。1.4.安装TypeScript依次点击【工具-->扩展和更新-->联机】,在右边搜索框中搜索typescript,并按【最新】排序,搜索结果如图1.9。选择最新版本下载后,关闭VS,安装即可。图1.91.5.运行Web项目重新编译下,Ctrl+F5运行web项目,报错如图2.0。图2.0按照图示所言,修改web.config中的customErrors节点为Off,<customErrorsmode="Off"/>。重新运行Web项目,报错如图2.1。图2.1一看是EntityFramework.DynamicFilters相关错误,这个是一个第三方Nuget包,用来支持EF进行Linq动态过滤的。猜到一种可能是升级后的DynamicFilters删除了图中的扩展方法,导致出错。到abp官方github上的项目上根据关键字搜索Issue,如图2.2。图2.2果然大家跟我们报的一样的错,其中已经给出了解决方案,需要将DynamicFilterNuget包降级到1.4.11。右键解决方案,选择【管理解决方案的Nuget程序包(N)...】,在搜索框中输入【EntityFramework.DynamicFilters】过滤,并选中依赖的项目,在版本下拉框中选择1.4.11,点击安装,如图2.3。图2.3重新编译,再次启动web项目,还是报错,如图2.4。图2.4是不是快崩溃了,别怕,跟着我做,让你气死回生。分别定位到依赖EntityFramework.DynamicFilters组件的项目,修改App.Config或Web.Config,找到以下节点:<dependentAssembly><assemblyIdentityname="EntityFramework.DynamicFilters"publicKeyToken="146423a1b8d60775"culture="neutral"/><bindingRedirectoldVersion="0.0.0.0-2.3.0.0"newVersion="2.3.0.0"/></dependentAssembly>是不是吐血,降级后,VS没有更改依赖组件的版本。修改如下:<dependentAssembly><assemblyIdentityname="EntityFramework.DynamicFilters"publicKeyToken="146423a1b8d60775"culture="neutral"/><bindingRedirectoldVersion="0.0.0.0-1.4.11"newVersion="1.4.11"/></dependentAssembly>修改完毕后,重新编译,启动web项目,这一次终于显示久违的登陆界面,预示着这次升级折腾结束了。有了这次升级折腾经验,下次我想咱就不怕了。2.调试源码按照作者的官方如何调试的文档介绍Debuging,所有官方ASP.NETBoilerplatenuget包都启用了GitLink。这意味着您可以轻松地在项目中调试Abp.*nuget包。但是由于GitLink暂不支持xproj/project.json格式,所以我们暂时用不了GitLink进行调试。这里另外提供一种调试的方式:2.1.下载与本地模板项目版本一致的Abp源码首先去看看Abp的Releases目录,找到对应版本的Sourcecode.zip,下载即可。2.2.还原Nuget包打开下载下来的源码解决方案,右键解决方案,选择还原Nuget包。还原成功后,重新编译项目。然后把需要调试的dll文件拷贝到自己的模板项目中的web项目的Bin目录下。2.3.附加进程调试Ctrl+F5运行web项目,然后在源码对应解决方案,选择【调试-->附加到进程】,从进程列表中,选择【iisexpress.exe】进程附加即可。打个断点,就可以调试了

  • 毕业第一份工作总结

    毕业第一份工作是做.net方向的工作,进行公司第一个项目负责的是一个新闻站点的网站以及小程序开发。那时候小程

CSS|HTML   小程序开发   运维部署  开发技巧 推荐阅读

  • .Net(C#) 实现replace字符串替换只替换一次的方法 .Net(C#) 实现replace字符串替换只替换一次的方法 本文主要介绍.Net(C#)替换字符串时,实现replace替换字符串只替换一次的方法代码。分别通过StringBuilder、正则表达式(Regex)、IndexOf和Substring实现,并且可以通过扩展方法简化代码方便调用。 文章阅读
  • .NET Core(C#) 使用AngleSharp生成自动缩进格式化的html方法 .NET Core(C#) 使用AngleSharp生成自动缩进格式化的html方法 本文主要介绍.NETCore(C#)中,使用AngleSharp生成自动缩进格式化的html代码方法,和下载获取网页html代码的方法,以及相关的示例代码。 文章阅读
  • MySQL JSON_CONTAINS() 函数 MySQL JSON_CONTAINS() 函数 MySQLJSON_CONTAINS()函数检查一个JSON文档中是否包含另一个JSON文档。如果您需要检查JSON文档中指定的路径下的是否存在数据,请使用JSON_CONTAINS_PATH()函数。JSON_CONTAINS()语法这里是MySQLJSON_CONTAINS()的语法:JSON_ 文章阅读

文章|阅读

2024年 04月26日

周五