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

    要想使用MySQL数据库服务器,您首先应该知道如何启动MySQL服务器。Linux启动/停止MySQL在Linux上完成MySQL安装后,mysql一般会作为服务安装在。根据Linux发行版的不同,服务的名称可能是mysqld也可能是mysql。早期的Linux版本中提供了service命令管理服务

  • 微信小程序中wxs文件的用法

    微信小程序中的wxs文件,大家或多或少都有见过,但怎么使用呢?在项目开发中又能给我们带来什么便捷和解决什么问题呢?借助一个案例为大家介绍具体用法。一、什么是wxs文件及wxs文件有什么作用wxs相当于一个独立模块,相当于一个独立出来的module对象,通过module.exports向外暴露,在文件中引入即可使用。解决了在微信小程序中{{method(a,b)}}方法传值不触发的问题,在vue这样传值是可以的。可以用来解决多次if判断,利于代码优化提高复用性。二、代码展示(.wx...

  • .NET Core Orleans中Grains的介绍

    Grains是Orleans编程模型的关键原语。Grains是Orleans应用程序的基石,它们是隔离,分发和持久性的原子单元。Grains是表示应用程序实体的对象。就像在经典的面向对象编程中一样,grain封装了实体的状态,并在代码逻辑中对其行为进行编码。Grains可以通过调用彼此通过接口公开的方法,来保持彼此的引用并进行交互。

  • 分享一个asp.net(ashx) 生成验证码图片

    CodeImg.ashx%@WebHandlerLanguage=“C#”Class=“Enterprise

  • MySQL DENSE_RANK() 函数

    MySQLDENSE_RANK()函数返回当前行所在的分区内的排名,从1开始,但没有间隔。也就是说,相同的值具有相同的排名,但是下一个不同的值的排名按顺序增加。比如,如果有2个第一名,那么第三位的排名是2。这与rank()函数是不同的。DENSE_RANK()语法这里是MySQLDENSE_RANK

  • .NET(C#) CefSharp 处理设置读取网站页面请求中的Cookie

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

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

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

  • MongoDB

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

  • .NET Core 使用 DotnetSpider 抓取页面教程 .NET Core 使用 DotnetSpider 抓取页面教程 本文主要介绍通过DotnetSpider写少量代码快速的实现网页的抓取。 文章阅读
  • .NET Core轻量级进程间通信框架IpcServiceFramework的使用 .NET Core轻量级进程间通信框架IpcServiceFramework的使用 本文主要介绍.NETCore中轻量级进程间通信框架IpcServiceFramework的介绍和使用方法代码,.NETCore轻量级进程间通信框架,允许通过命名管道和/或TCP调用服务(与WCF类似,目前.NETCore不可用)。支持通过SSL进行安全通信。支持在服务契约中使用原始或复杂类型。支持服务器端的多线程,具有可配置的线程数(仅限命名管道端点) 文章阅读
  • 微信小程序的图片上传及图片预览功能 微信小程序的图片上传及图片预览功能 本文为大家分享微信小程序的图片上传及图片预览功能,如下图所示:需求分析:图片上传可以从本地图库选择也可调用相机进行拍照上传上传完成之后图片可以进行删除、预览等功能图片上传至服务器进行后台调用代码实现:wxml文件<viewclass="recovery_other_line"><viewclass="other_text">上传图片</view><viewwx:if="{{imageList.length}}"class="c 文章阅读

文章|阅读

  • 首先来看下[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

  • 标签是文档中必不可少的组成部分,在html代码中,每个标签都有它特定的含义。那么哪些标签可以做seo优化呢?下面就为大家介绍一下如何使用和优化。

    Web

  • 微信小程序实现将图片保存到手机相册

    前言图片保存到手机相册的功能相信大家一定都用过吧,今天教你用微信小程序实现这个好玩的小功能。实现效果如下:实现思路:首先我们需要调用wx.downloadFile方法下载文件资源到本地,然后利用wx.saveImageToPhotosAlbum方法保存图片到系统相册,需要注意的是这样写很可能会因为没有权限而导致下载不了图片,所以我们最后还需要给接口一个调用失败的回调函数,以此来获取权限,最后这个小功能就实现啦。源码如下:wxml文件<!--按钮触发事件--><bu

    小程序

  • 2021目标期望没达到预期,今天过后所有的期待与努力无最爱、无例外、往事清零,一起跨入2022,续上昨日的期

    Life

  • vscode使用技巧

    1技巧1:右键菜单中“通过code打开”安装vscode后,可以选中任何任何文件或者文件夹,点击右键选择“通过code打开”,可以方便的用vscode打开文件或者查看文件夹下的所有文件2技巧2:在命令行窗口使用code命令打开文件在cmd,powershell,bash中输入“code.”会用vscode打开当前目录下的文件3技巧3:多文件编辑框,同时查看或者编辑多个文件点击右上角的“spliteditor”图标把文件分为多个编辑框4技巧4:vscode命令行框(CommandPalette)commandpalette可以说是vscode的控制中心,vscode的各种功能都可以使用在commandpalette输入命令来执行和实现,输入快捷键可以打开Ctrl+Shift+P5技巧5:查看vscode的快捷键列表使用快捷键可以让vscode的操作变得高效且简单,vscode支持哪些快捷键呢,可以在如下菜单打开查看“File”->"Preference"->"KeyboardShortcuts"6技巧6:安装插件丰富和高质量的插件是让vscode的功能强大的重要原因,点击vscode界面的插件按钮,可以查询,安装,更新自己想要的插件7技巧7:vscode显示中文vscode默认是英文,如何显示中文呢,在插件中输入@category:"languagepacks"(如图所示),然后选择中文,然后在vscode命令框中输入“display”来配置语言8技巧8:使用gitvscode很好的集成了git的功能,先从git代码库(比如github)克隆到本电脑,在vscode打开这个代码库所在的文件夹,就可以在vscode中通过界面化的方式执行git操作,比如commit,diff,push,pull等操作9技巧9:vscodeterminal(vscode命令终端)在“File”->"Terminal"->"NewTerminal"中打开终端,可以像powershell一样在vscode中执行操作系统级别的命令10技巧10:格式化代码快捷键Shift+Alt+F(对文件中所有代码格式化)快捷键Ctrl+KCtrl+F(对选中的代码格式化)也可以在右键菜单中选择对应功能EN

    开发技巧

2024年 06月25日

周二