关于单元测试:理解这八大优势才算精通单元测试

什么是单元测试在计算机编程中,单元测试是一种软件测试办法,通过该办法能够测试源代码的各个单元以确定它们是否适宜应用。 单元是最小的可测试软件组件, 它通常执行单个内聚性能。单元测试就是是指对这个最小可测试组件——即单元进行检查和验证。 单元体量小,因而比大块代码更容易设计、执行、记录和分析测试后果。 通过单元测试发现的缺点很容易定位,并且绝对容易修复。单元测试的指标是将程序拆散成各自独立的局部,并测试各个局部是否失常工作。它将可测试软件的最小局部与代码的其余部分隔离开来,并确定其行为是否与预期的完全一致。单元测试能在应用过程中发现很多缺点,在这种过程中证实本身价值。它实现了测试过程的自动化,缩小了发现应用程序中更简单局部中蕴含的谬误的艰难,并且因为能够关注到每一个单元而进步测试覆盖率。 单元测试工具 (图为禅道项目管理软件界面) 常见单元测试框架有JUnit, TestNG, PHPUnit, PyTest, Jest, CppUnit, GTest, QTest 等八种,目前国产支流项目管理软件禅道全面集成这八种单元测试框架,买通继续集成闭环,将测试用例细分了单元测试用例和性能测试用例,能够间接在禅道页面上导入各种各样的单元测试框架的执行后果。这八种单元测试框架通过禅道ZTF与Jenkins继续集成性能买通。用户发动工作后,通过ZTF主动执行测试脚本,把单元测试的后果回传给禅道,二者单干买通了继续集成闭环,买通了项目管理工具和继续集成工具之间的沟壑。 为何单元测试是麻利方法论在Apiumhub,咱们采纳麻利办法,并且大量利用单元测试。单元测试是极限编程(Extreme Programming,XP)的一个特色,极限编程是麻利软件开发办法之一,它能带来疾速的测试驱动开发。咱们深信麻利就要做继续集成和测试驱动开发。通过测试驱动开发,开发人员在开发代码时会创立单元测试,以便每个单元测试通常在编写代码之前就测试一小段软件代码。 单元测试的劣势单元测试提供了许多益处,包含及早发现软件谬误、促成变动、简化集成、提供文档起源以及许多其余长处,接下来将对其进行具体介绍。 1、使流程更灵便单元测试的次要益处之一是它使编码过程更加灵便,更遵循麻利开发方法论。 当向软件中增加越来越多的性能时,个别须要更改旧的设计和代码。 然而,更改曾经测试过的代码既冒险又高老本。 如果此时采纳单元测试,那么就能够释怀地进行重构。 单元测试实际上与各种类型的麻利编程紧密结合,因为测试被内置在其中,让程序员能够更轻松地进行更改。 换句话说,单元测试有助于平安重构。 2、保障代码品质单元测试能够进步代码的品质。 它可能确定在进一步发送代码进行集成测试之前可能呈现的每个缺点,在理论编码之前编写测试让人更难以思考到这种问题。 而单元测试能够暴露出极其状况,让人编写出品质更高的代码。 3、尽早发现软件Bug应用单元测试会让问题在晚期就被辨认发现。因为单元测试是由在集成之前测试单个代码的开发人员执行的,这样能够很早地发现问题,并在不影响其余代码片段的状况下解决问题。这既包含施行中的Bug,也包含单元标准中的缺点或缺失局部。 4、促成变动并简化集成单元测试容许在未来重构代码或降级零碎库,并确保该模块依然失常工作。单元测试能监测到可能违反设计合同的变动,有助于保护和更改代码。单元测试还能够缩小新开发性能中的缺点,缩小现有性能更改时呈现的谬误。而后通过单元测试对应用程序的各个局部进行测试,验证每个单元的准确性,再将单元集成到应用程序中。因为曾经对各个单元进行了验证,在之后的集成过程中对应用程序进行测试就变得更容易。 5、提供文档单元测试提供零碎的文档。心愿理解单元提供了哪些性能以及如何应用这些性能的开发人员能够查看单元测试,以取得对单元接口(API)的根本了解。 6、简化调试过程单元测试有助于简化调试过程。 如果测试失败,则仅须要调试代码中最新的更改,这样以往的简短的调试过程将被大大缩减。 7、设计率先编写测试会迫使程序员在编写代码之前就认真思考设计和其余必须实现的工作。 这不仅能够让人专一,还能够创立更好的设计。 测试一段代码会迫使程序员定义该代码的责任。如果能够轻松做到这一点,则意味着代码的职责是被明确定义的,因而将具备很高的凝聚力。 8、降低成本单元测试会更早地发现错误,有助于升高谬误修复的老本。设想一下在开发的前期阶段(比方在零碎测试或验收测试中)才发现Bug的老本将有多高。当然,后期检测到的谬误也更容易修复,因为前期检测到的谬误通常是许多更改的后果,测试人员可能就不会真正晓得是哪一个导致了谬误。 单元测试是针对代码单元的独立测试,外围是“独立”,劣势起源也是这种独立性,而所面临的有余也正是因为其独立性:既然是“独立”,就难以测试与其余代码和依赖环境的互相关系。 单元测试与零碎测试是互补而非代替关系。单元测试的劣势,正是零碎测试的有余,单元测试的有余,又恰是零碎测试的劣势。不能将单元测试当做解决所有问题的万金油,而需了解其劣势与有余,取长补短,与零碎测试相辅相成,实现测试的最大效益。

February 26, 2024 · 1 min · jiezi

关于单元测试:为什么单元测试不是持续交付的唯一答案

为了让继续集成和继续交付(CI/CD)成为事实,企业必须审查其外部流程,并从新思考如何处理软件交付生命周期。过来的清单和评论基本不是后退的方向。残暴的事实是,大多数企业在继续交付的路线上相当落后。对软件交付过程自身进行根本性的扭转与从货架上取下一些工具这样的半个步骤是齐全不一样的。 如果指标是对客户和用户做出更好的响应,软件团队须要专一于软件交付周期的更快迭代,并围绕疾速响应用户反馈进行组织。尽管可能有如每月公布数量这种代理指标,但采纳继续交付的最佳衡量标准是跟踪从反馈到更新软件的工夫。然而如果只是拼凑性地进行继续交付,将无奈达成指标。 人们很容易从渐进的角度来对待一个组织如何从现状倒退到它想驻足的地位。尽管渐进永远是正确的办法,但目前仅仅迈出第一步的企业不应自欺欺人地认为本人曾经走得足够远。 不要依赖于CI/CD工具通常,团队履行继续交付都是从一些自动化的单元测试来自动化构建过程开始。这是一个很好的开始,然而不要花太多的工夫去关注单元测试笼罩的代码行数。相同,企业应该将自动化测试的注意力集中在验证外围业务流程、用户事务和用户交互上,以确保它们依然依照预期和业务无效运行所需的形式运行。 CI/CD策略的下一个简单档次是偏向于将打算每季度进行的大量变动打包在一起(如果企业在这一步停留也是一种谬误)。实际上,CI成为了企业暂停致力的一个点。另一方面,CD则是尽可能频繁地通过管道和生产进行更改。一旦企业理解了代码更改对用户的影响以及主动实现这些更改的实现形式,它就须要鼓起勇气和付出财力来推动这些更改。 一般来说,即便是正在谋求CI/CD的组织,也会存在着将改革视为危险的心态。这就不可避免地导致了这样一种信念:更改的频率应该升高。这与继续交付正好相同,它会对企业齐全承受CI/CD造成妨碍。 较小的变更实质上会带来更小的危险,这意味着高生产率的软件组织应可能更快地迁徙。继续交付的概念和前景取决于企业一直部署渺小变更的能力。有必要冀望进行频繁的公布。 范畴软件相应更改那些单纯应用传统思维形式(CI工具、单元测试和验收测试)进行这项工作的企业依然没有取得任何真正的益处。企业正在部署的变更范畴应该作为它在软件开发生命周期中能够接受的品质问题级别的指导方针。 另一个常见的问题是,当一个组织决定将事件合成为一些小的变更,然而依然须要开一系列的会议,变更管制委员会或者开发团队必须通过的严格的安全检查。如果您的组织的指标是通过部署较小的变更堆栈来加快进度,那么在全面重新考虑外部正式的公布周期办法之前,它不会有任何停顿。 在政府机构等严格监管部门工作的组织,必须通过对其公布的产品进行批改和必要的文档化来克服这些挑战。政府部门以外的组织能够效仿他们的例子,通过对软件进行更改并形容这些更改将如何影响标记版本内的用户来克服文档需要。一个很好的例子就是美国政府的cloud.gov团队如何通过编程生成文档,比方他们的零碎图。 想要在CI/CD畛域取得成功的企业必须找到一种办法,将这种意见编入某种能够疾速实现的自动化测试中,而不是从任何人那里获取关于软件是否应该公布的意见。否则,这条路线上的每一个手动步骤只会进一步造成交付的提早。 组织如何解决这个问题许多企业陷入推广CI/CD至一半的地步——他们有各种各样的工具来容许一些这样的实际,然而外部流程、检查表或管理权限下的决定阻止了组织以失常的节奏公布更新。 大量的开发人员被困在传统的软件开发周期中,他们甚至不尝试CI/CD,或者通过专一于工具、测试和自动化来承受CI/CD的人工版本。有两种办法能够解决这个问题。一种办法是首先应用CI/CD工具,并受权各种开发团队开始在公司范畴内应用公共构建服务。另一种办法是确定将从较高的开发速度、较小的变更集中获益最多的开发团队,并容许从该实际中取得的教训渗透到整个业务中。 后一种模型在大多数状况下会工作得更好,因为所波及的人员数量被放弃在最低限度,而IT组织中更关怀听从性和审计的局部将有更大的灵活性来了解单个应用程序范畴内产生的事件。企业应该更违心在单个应用程序和团队中推广试验,而不是试图推动整个公司一起进行转变。 CI/CD的指标始终是一直变动的,这是无意设计的。然而请释怀,当所有可能从更快交付中获益的团队都实现了这些后果时,组织将分明本身曾经开始实现CI/CD的指标。 *该文为翻译文章,原文链接:https://thenewstack.io/how-to-avoid-pit-stops-on-the-road-to-...

February 19, 2024 · 1 min · jiezi

关于单元测试:谈谈如何使用好单元测试这把武器

前言如《Unit Testing》书里提到, 学习单元测试不应该仅仅停留在技术层面,比方你喜爱的测试框架,mocking 库等等,单元测试远远不止「写测试」这件事,你须要始终致力在单元测试中投入的工夫回报最大化,尽量减少你在测试中投入的精力,并最大化测试提供的益处,实现这两点并不容易。和咱们在日常开发中遇到的问题一样,学会一门语言,把握一种办法并不艰难,艰难的是把投入的工夫回报最大化。unit test有很多基础知识和框架,在google上一搜就一大堆,最佳实际的方法论也十分多,本文不筹备探讨这些问题,而是联合在咱们日常的工作,探讨如何应用好单元测试这把武器。 单元测试的定义什么是单元测试?来自百度 单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。至于【单元】的含意,一般来说,要依据理论状况断定具体含意,如Java里单元指一个类等。讲人话,单元测试就是为了验证一个类的准确性的测试。区别于集成测试和零碎测试。他是前置的,由开发人员主导的最小规模的测试。 一些学者们通过统计,还绘制出了下图: 85%的缺点都在代码设计阶段产生;发现bug的阶段越靠后,消耗老本就越高,呈指数级别的增长。由此看来,单测代码的编写对于交付品质以及人工消耗老本都有极其重要的影响 常见的误区浪费时间,影响开发速度不同我的项目的开发测试工夫曲线不同,你要综合思考你的代码的生命周期,你debug的能力,你平时花多少工夫review有问题的代码。随着我的项目的进行,这些工夫会递增,如果你想你所写的代码可能始终用上来,不让起初人吐槽这写的什么玩意,单元测试十分有必要。 测试应该是测试的工作开发是代码的第一责任人,最相熟代码的人,在设计阶段编辑单元测试,岂但能够让你更自信的交付,还能够缩小测试问题的产生。同时你本人的全栈能力也有所晋升。代码不是我写的,我不懂咱们常常埋怨老代码有坑难懂,或者是不足CR。其实在编写单元测试的过程中,也是CR和学习的一个过程,对于代码的主流程,边界,异样等有了深刻的了解。同时也是自我扫视代码标准、逻辑、设计的过程。我倡议在重构中写单测,在写单测中重构,相辅相成。 如何写出好的单测方法论上,有AIR 准则 ,像空气一样不会被感触到即 Automatic(自动化)、Independent(独立性)、Repeatable(可反复)。我集体的了解就是1、主动运行,通过CI集成的形式,保障单测可能主动运行,通过assert保障单元测试的验证后果,而不是print输入。确保单元测试可能自动化运行,不须要人工染指测试。 2、单元测试必须独立,不能相互调用,也不能有依赖的程序。每个测试用例之间包保障独立。3、不能够受运行的环境、数据库、中间件等影响。在编写单测的时候,须要把内部的依赖mock掉。从覆盖率的标准上来讲,不论是阿里外部还是业界,都有很多规范。 语句覆盖率达到70%;外围模块的语句覆盖率和分支覆盖率都要达到100%。 --- 《阿里巴巴Java开发手册》单测覆盖度分级参考Level1:失常流程可用,即一个函数在输出正确的参数时,会有正确的输入Level2:异样流程可抛出逻辑异样,即输出参数有误时,不能抛出零碎异样,而是用本人定义的逻辑异样告诉下层调用代码其谬误之处Level3:极其状况和边界数据可用,对输出参数的边界状况也要独自测试,确保输入是正确无效的Level4:所有分支、循环的逻辑走通,不能有任何流程是测试不到的Level5:输入数据的所有字段验证,对有简单数据结构的输入,确保每个字段都是正确的从下面的摘录看,语句覆盖率和分支覆盖率都有数值上和方法论上的要求,那在理论工作中,实际状况如何呢?笔者曾在一个季度,工作中提交的代码综合增量覆盖率简直达到了100%。我能够谈谈我的教训和实际。60%左右的单测覆盖率能够十分轻松达到,但达到95%以上的覆盖率,须要笼罩各种代码分支和异常情况等,甚至是配置和bean的初始化办法,所投入的工夫十分微小,但边际效应递加。我想测试toString, getter/setter这样的办法也没有意义。多少适合,我认为没有一个固定的规范。高代码覆盖率百分比不示意胜利,也不意味着高代码品质。该舍弃测试的局部就大胆的ignore掉。 最佳实际这个题目未免有些题目党。单元测试相干的书籍、ata文章,不可胜数,我的所谓“最佳实际”是在理论阿里工作中的一些本人踩过的坑,或者我集体认为一些重要的点,班门弄斧,如有谬误,欢送探讨。 1、暗藏的测试边界值public ApiResponse<List<Long>> getInitingSolution() { List<Long> solutionIdList = new ArrayList<>(); SolutionListParam solutionListParam = new SolutionListParam(); solutionListParam.setSolutionType(SolutionType.GRAPH); solutionListParam.setStatus(SolutionStatus.INIT_PENDING); solutionListParam.setStartId(0L); solutionListParam.setPageSize(100); List<OperatingPlan> operatingPlanList = operatingPlanMapper.queryOperatingPlanListByType(solutionListParam); for(; !CollectionUtils.isEmpty(operatingPlanList);){ /* do something */ solutionListParam.setStartId(operatingPlanList.get(operatingPlanList.size() - 1).getId()); operatingPlanList = operatingPlanMapper.queryOperatingPlanListByType(solutionListParam); } return ResponsePackUtils.packSuccessResult(solutionIdList);}下面这段代码,如何写单元测试? 很天然的,咱们写单测的时候会mock掉数据库查问,并且查出信息。然而如果查问的内容超过100,因为for循环进入一次,无奈通过jacoco的主动覆盖率发现。实际上没有笼罩这个边界case,只能通过开发者的习惯来解决这些边界状况。如何解决这些暗藏的边界值,开发者不能依赖集成测试或者代码CR,必须要在本人写单元测试的时候思考到这一状况,能防止起初保护的人掉坑。 2、不要在springboot测试中应用@Transactional以及操作实在数据库单元测试的上下文应该是洁净的,设计transactional的初衷是为了集成测试(如spring官网介绍): 尽管间接操作DB能更容易验证DAO层的正确性,然而也容易被线下数据库的脏数据净化,导致单测无奈通过的问题。笔者以前遇到直连数据库的单测代码,常常改个5分钟代码,数据库里脏数据清一个小时。第二就是集成测试须要启动整个利用的容器,违反了提高效率的初衷。如果切实要测DAO层的正确性,能够整合H2嵌入式数据库。这个网上教程十分多,不再赘述。 3、单测里工夫相干的内容笔者已经在工作中遇到过一个极其case,一个CI平时都失常运行,有一次深夜公布, CI跑不过,起初通过第二天check才发现有前人在单测中取了以后工夫,在业务逻辑中含有夜间逻辑(夜间音讯不发),导致了CI无奈通过。那么工夫在单测中要如何解决呢?在应用Mockito时,能够应用mock(Date.class)来模仿日期对象,而后应用when(date.getTime()).thenReturn(time)来设置日期对象的工夫。如果你应用了calendar.getInstance(),如何获取以后工夫?Calendar.getInstance()是static办法,无奈通过Mockito进行mock。须要引入powerMock,或者降级到mockito 4.x能力反对: @RunWith(PowerMockRunner.class) @PrepareForTest({Calendar.class, ImpServiceTest.class}) public class ImpServiceTest { @InjectMocks private ImpService impService = new ImpServiceImpl(); @Before public void setup(){ MockitoAnnotations.initMocks(this); Calendar now = Calendar.getInstance(); now.set(2022, Calendar.JULY, 2 ,0,0,0); PowerMockito.mockStatic(Calendar.class); PowerMockito.when(Calendar.getInstance()).thenReturn(now); }}4、final类,static类等的单元测试如第3点提到的calendar的例子,static类的mock须要mockito4.x的版本。否则就要引入powermock,powermock不兼容mockito3.x版本,不兼容mockito 4.x版本。因为老的利用引入了十分多的mockito3.x的版本,间接应用mockito4.x对final和static类进行mock须要排包。实际中看,JUnit、Mockito、Powermock三者之间的版本号有兼容性问题,可能会呈现java.lang.NoSuchMethodError,须要依据理论的状况抉择版本进行mock。然而在新我的项目立项的时候,要确定好应用的mockito和junit版本,是否引入powermock等框架,确保环境稳固可用。老我的项目倡议不要大规模改变mockito和powermock的版本,容易排包排到狐疑人生。 ...

June 12, 2023 · 2 min · jiezi

关于单元测试:禅道结合ZTF驱动单元测试执行

ZTF是禅道开源的一款自动化测试工具,反对两种模式的脚本: ZTF自治理脚本。它通过在脚本顶部的正文中退出用例的编号、题目、步骤和期待后果等信息,实现和禅道手工用例的同步,用于同执行时输入的理论后果进行比对,以实现检查点的断言。具体可参考这里的一个例子;其余单元测试或自动化测试工具的脚本。测试人员可依照原来的形式编写测试脚本,ZTF对他们并没有侵入,只是负责驱动这些工具脚本或我的项目的执行调度工作,剖析后果、并提交到禅道。这里有一个PyTest的例子,供大家参考。ZTF和市面上已有的自动化测试工具相比,更聚焦于自动化测试的治理性能,包含脚本的组织和调度、同测试管理系统的集成等。应用ZTF驱动组织的自动化或单元测试工作,可一改以前自动化测试同研发管理系统相割裂的状况。自动化测试的需要、设计和执行产生和源自于管理系统;自动化测试的执行后果(包含在继续集成流水线构建过程中的)通过ZTF再反馈到管理系统中。这样,有利于在同一个零碎中,实现软件交付品质的对立度量和集中展现,提供治理上的决策反对。 接下来,咱们介绍一下ZTF对目前市场上支流的单元测试框架的反对,并提供相应的示例我的项目,供大家参考。这些单元测试框架提供了数据驱动、用户并发、指定调度、报告剖析等一些优良的个性,不仅能够用来做单元测试,在其余类型的测试,如UI性能自动化测试、手机APP测试、接口和性能测试都能够应用。 编号框架名称应用介绍示例我的项目1JUnithttps://ztf.im/book/ztf/junit-33.htmlhttps://gitee.com/ngtesting/ci_test_junit2TestNGhttps://ztf.im/book/ztf/testng-34.htmlhttps://gitee.com/ngtesting/ci_test_testng3PHPUnithttps://ztf.im/book/ztf/phpunit-35.htmlhttps://gitee.com/ngtesting/ci_test_phpunit4PyTesthttps://ztf.im/book/ztf/pytest-36.htmlhttps://gitee.com/ngtesting/ci_test_pytest5Jesthttps://ztf.im/book/ztf/jest-37.htmlhttps://gitee.com/ngtesting/ci_test_jest6GTesthttps://ztf.im/book/ztf/gtest-39.htmlhttps://gitee.com/ngtesting/ci_test_gtest.git7QTesthttps://ztf.im/book/ztf/qtest-40.htmlhttps://gitee.com/ngtesting/ci_test_qtest8CppUnithttps://ztf.im/book/ztf/cppunit-38.htmlhttps://gitee.com/ngtesting/ci_test_cppunit9GoTesthttps://ztf.im/book/ztf/gotest-184.htmlhttps://gitee.com/ngtesting/ci_test_allure_gotest10Allurehttps://ztf.im/book/ztf/allure-183.htmlhttps://gitee.com/ngtesting/ci_test_allure_testng专题目录

May 7, 2023 · 1 min · jiezi

关于单元测试:云原生引擎单元测试实践

作者:京东批发 王雷 单元测试概念单元测试是用来对一个模块、一个函数或者一个类来进行正确性测验的测试工作。单元测试是一种白盒测试技术,个别都是由开发人员在编码阶段实现,目标就是验证软件代码中的每个单元(办法或类等)是否合乎预期,即尽早在尽量小的范畴内裸露问题。 疾速迭代的开发工作中如何进步代码品质始终是团队痛点,特地是没有测试反对的开发团队。正当的应用单元测试,并关注单元测试通过率、代码覆盖率能够无效进步代码品质。 云原生引擎服务,实际了单元测试,并在研发自测、预发、上线等阶段施行了相应的策略。在肯定水平上进步了代码的品质。 单元测试的目标单元测试的目标在于发现各模块外部可能存在的各种谬误,次要包含以下几个方面: (1) 验证代码是与设计相符合的。 (2) 发现设计和需要中存在的谬误。 (3) 发现在编码过程中引入的谬误。 在开发阶段尽可能发现代码中的问题;在预发集成阶段尽可能发现各个业务代码之间的问题;在上线阶段做最初的确认保障上线代码品质。 单元测试除了可能在较早阶段辨认软件中的谬误,它还有如下价值。 •反馈速度快:单元测试通常以自动化模式运行,执行速度十分快,能够疾速反馈后果,跟继续集成联合起来,造成无效的反馈环。 •重构的无力保障:零碎须要大规模重构时,单测能够确保对已有逻辑的兼容,如果单元测试都通过,基本上能够保障重构没有毁坏原来代码逻辑的正确性。 •使更相熟代码:写单元测试的过程自身就是一个扫视代码的过程,能够发现一些设计上的问题(代码设计的不可测试)、代码编写方面的问题(边界条件的处理不当)等。 云原生引擎单测实际整体单测率引擎在进行开发过程中,会重点关注外围模块代码和底层代码,针对重要的业务逻辑代码,通用组件类等,波及到重要的性能开发,对应的每一个办法咱们都要编写对应的单元测试代码。在提交代码之前,在本地进行单测回归,跑通单测之后,提交代码,分支合并。 单元测试重点引擎的单测重点次要体现在以下五个方面 1、输入输出测试这里次要是针对数据的输出和输入进行测试。 调用所测模块时的输出参数与模块的形式参数在个数、属性、程序上是否匹配。所测模块调用子模块时,它输出给子模块的参数与子模块中的形式参数在个数、属性、程序上是否匹配。是否批改了只用作输出的形式参数。2、门路测试在单元测试中,最次要的测试是针对门路的测试;测试用例必须可能发现因为计算错误、不正确的断定或不失常的控制流而产生的谬误。 常见的谬误有:误会的或不正确的算术优先级,混合模式的运算,谬误的初始化,精确度不够准确和表达式的不正确符号示意。 3、出错解决比较完善的单元设计要求能预感出错的条件,并设置适当的出错解决,以便在程序出错时,能对出错程序从新做安顿,保障其逻辑上的正确性。 4、边界条件次要测试方法对循环条件,管制条件,数据流等临界值的解决状况 比方针对一个办法中的不同分支进行单测的编写 5、部分数据结构在模块工作过程中,必须测试模块外部的数据是否放弃完整性,包含外部数据的内容、模式及互相关系不产生谬误。 对于部分数据结构,应该在单元测试中留神发现以下几类谬误: 1)不正确的或不统一的类型阐明 2)谬误的初始化或默认值 3)谬误的变量名,如拼写错误或书写谬误 4)下溢、上溢或者地址谬误 最佳实际如何写好单测1.代码设计:代码设计上要低耦合、可测试 2.度量指标:正当的单元测试用例数量以及正当的覆盖率 3.应用场景:要融入软件开发中,在开发过程中常常运行 4.测试指标:要专一于代码中重要的逻辑 5.保障独立性:应用mock形式搁置依赖系统对单元测试后果的影响 6.用例粒度:单元测试用例应该是对独自的性能的有意义的形容,通过用例能够理解改性能的逻辑 继续集成、继续卡点代码自测通过后提交MR让团队成员进行review,当review通过时咱们会通过webhook触发预发部署流水线执行单元测试和部署 上线前查看当代码验收通过后,进行线上部署时再次跑单元测试确保上线代码品质,不达标将不能部署

March 22, 2023 · 1 min · jiezi

关于单元测试:Golang-单元测试-其他小技

单元测试有很多技巧和科技,我都会缓缓汇总在这里打桩测试当咱们在编写单元测试的时候,有时咱们十分想 mock 掉其中一个办法,然而这个办法又没有接口去定义和实现(无奈用 github.com/golang/mock 来实现),这时就能够尝试看看咱们的打桩黑科技。 代码这里咱们应用 github.com/agiledragon/gomonkey 来实现。理论中,常常在代码中会遇到一些随机值的状况,比方验证码。为了不便测试,咱们会想要 mock 掉随机值办法,让每次产生的值固定不便后续的测试。 package mainimport ( "fmt" "testing" "github.com/agiledragon/gomonkey/v2" "go-demo/m/unit-test/other/rand")func init() { gomonkey.ApplyFunc(rand.Number, func() int { return 666 })}func TestRand(t *testing.T) { fmt.Println(rand.Number())}其中 rand.Number() 是咱们在另一个包中实现的办法。咱们应用 gomonkey.ApplyFunc 相当于间接替换了原有办法的实现,强制返回了 mock 的数据 666。 注意事项应用 gomonkey 时,留神肯定要应用 -gcflags=all=-l 来禁止内联优化,否则容易导致打桩不失效。如:go test -gcflags=all=-l -v在 Mac 的 M1 下打桩不失效,能够应用环境变量 GOARCH=amd64 来进行测试,只不过这样就无奈进行断点调试。https://github.com/agiledragon/gomonkey/issues/77毕竟是黑科技,理论应用环境对于测试还是有影响的。压测这里的压测通常不是对接口的压测,而是对于某些办法的压测。Golang 提供 十分好用的 b *testing.B 来专门进行压测。 代码非常容易上手,让咱们间接来看代码 var numbers = []int{ 100, 1000, 77777, 666666,}func BenchmarkPrimeNumbers(b *testing.B) { for _, v := range numbers { b.Run(fmt.Sprintf("calc_num_%d", v), func(b *testing.B) { for i := 0; i < b.N; i++ { primeNumbers(v) } }) }}应用应用 -bench=. 即可 ...

March 11, 2023 · 2 min · jiezi

关于单元测试:Golang-单元测试-接口层

上次咱们曾经搞定了逻辑层的单元测试,这次咱们来康康接口层的单元测试。接口层次要负责的就是申请的解决,最常见的就是 HTTP 申请的解决。 但针对 接口层 的单元测试其实是能够形形色色的。它并不像逻辑层和数据层一样的通用,对于它的测试往往有很多路能够走。 因为应用的 HTTP 框架不同,单元测试的实现形式则不同。 既能够通过程序来模仿 HTTP 申请,也能够通过实在的 HTTP 申请来测试,通过借助内部的一些测试工具来实现。 所以本文只能给出一种思路,具体的实现形式还是要依据理论的框架来实现。 环境本文以罕用的 gin 框架为例,应用一种集体比拟喜爱也非常简单的形式来实现单元测试。特点次要有: 不须要启动路由服务复用已有的我的项目内的申请构造代码因为之前曾经贴过,所以 service 层的 代码这里就不赘述了base casepackage controllerimport ( "context" "github.com/gin-gonic/gin" "go-demo/m/unit-test/entity")//go:generate mockgen -source=./user.go -destination=../mock/user_service_mock.go -package=mocktype UserService interface { AddUser(ctx context.Context, username string) (err error) GetUser(ctx context.Context, userID int) (user *entity.User, err error)}type AddUserRequest struct { Username string `json:"username" binding:"required"`}type GetUserRequest struct { UserID int `form:"user_id" binding:"required"`}type GetUserResponse struct { Username string `json:"username"`}type UserController struct { UserService UserService}func NewUserController(userService UserService) *UserController { return &UserController{UserService: userService}}func (uc *UserController) AddUser(ctx *gin.Context) { req := &AddUserRequest{} if err := ctx.BindJSON(req); err != nil { return } if err := uc.UserService.AddUser(ctx, req.Username); err != nil { ctx.JSON(400, gin.H{"error": err.Error()}) return } ctx.JSON(200, gin.H{"message": "success"})}func (uc *UserController) GetUser(ctx *gin.Context) { req := &GetUserRequest{} if err := ctx.BindQuery(req); err != nil { return } user, err := uc.UserService.GetUser(ctx, req.UserID) if err != nil { ctx.JSON(400, gin.H{"error": err.Error()}) return } ctx.JSON(200, &GetUserResponse{Username: user.Username})}既然之前咱们 service 的单元测试曾经通过,这次咱们就须要 mock 的是 service 层的接口 mockgen -source=./user.go -destination=../mock/user_service_mock.go -package=mock这里我将申请和返回的构造 如:GetUserRequest、GetUserResponse 放在了这里仅仅是为了不便展现代码单元测试根底代码非常简单,就是咱们常见的,最重要的让咱们来看看单元测试应该怎么写 ...

March 10, 2023 · 2 min · jiezi

关于单元测试:Golang-单元测试-逻辑层

后面咱们实现了最麻烦的数据层的单元测试,明天咱们来看看单元测试中最容易做的一层,数据逻辑层,也就是咱们通常说的 service 或者 biz 等,是形容具体业务逻辑的中央,这一层蕴含咱们业务最重要的逻辑。 所以它的测试十分重要,通常它测试的通过就意味着你的业务逻辑能失常运行了。 而如何对它做单元测试呢? 因为,这一层的依赖次要来源于数据层,通常这一层会调用数据层的接口来获取或操作数据。 因为咱们之前对于数据层曾经做了单元测试,所以这一次,咱们须要 mock 的不是数据库了,而是数据层。 Golang 提供了 github.com/golang/mock 来实现 mock 接口的操作,本文就是应用它来实现咱们的单元测试。 筹备工作装置 go install github.com/golang/mock/mockgen@v1.6.0 根本 case 代码首先咱们还是基于上一次的例子,这里给出上一次例子中所用到的接口 package serviceimport ( "context" "fmt" "go-demo/m/unit-test/entity")type UserRepo interface { AddUser(ctx context.Context, user *entity.User) (err error) DelUser(ctx context.Context, userID int) (err error) GetUser(ctx context.Context, userID int) (user *entity.User, exist bool, err error)}type UserService struct { userRepo UserRepo}func NewUserService(userRepo UserRepo) *UserService { return &UserService{userRepo: userRepo}}func (us *UserService) AddUser(ctx context.Context, username string) (err error) { if len(username) == 0 { return fmt.Errorf("username not specified") } return us.userRepo.AddUser(ctx, &entity.User{Username: username})}func (us *UserService) GetUser(ctx context.Context, userID int) (user *entity.User, err error) { userInfo, exist, err := us.userRepo.GetUser(ctx, userID) if err != nil { return nil, err } if !exist { return nil, fmt.Errorf("user %d not found", userID) } return userInfo, nil}能够看到咱们的指标很明确,就是须要 mock 掉 UserRepo 接口的几个办法,就能够测试咱们 AddUser 和 GetUser 办法了 ...

March 9, 2023 · 3 min · jiezi

关于单元测试:Golang-单元测试-数据层

前言明天咱们先来看看无关数据层(repo)的单元测试应该如何实际。 数据层,就是咱们经常说的 repo/dao,其性能就是和数据库、缓存或者其余数据源打交道。它须要从数据源中获取数据,并返回给上一层。在这一层通常没有简单业务的逻辑,所以最重要的就是测试各个数据字段的编写是否正确,以及 SQL 等查问条件是否失常能被筛选。 当然,数据层也基本上是最底层了,通常这一层的单元测试更加的重要,因为如果一个字段名称和数据库不统一下层所有依赖这个办法的中央全副都会报错。 因为数据层和数据源打交道,那么测试的麻烦点就在于,通常咱们不能要求外接肯定能提供一个数据源供咱们测试:一方面是因为咱们不可能随时都能连上测试服务器的数据库,另一方面咱们也不能要求单元测试运行的时候只有你一个人在应用这个数据库,而且数据库数据洁净。退一步讲,咱们也没方法 mock,如果 mock 了 sql,那么测试的意义就不大了。 上面咱们就以咱们常见的 mysql 数据库为例,看看在 golang 中如何进行单元测试的编写。 筹备工作的阐明数据源首先,咱们须要一个洁净的数据源,因为咱们没有方法依赖于内部服务器的数据库,那么咱们就利用最常应用的 docker 来帮忙咱们构建一个所须要应用的数据源。 咱们这里应用 github.com/ory/dockertest 来帮忙咱们构建测试的环境,它能帮忙咱们启动一个所须要的环境,当然你也能够抉择手动应用 docker 或者 docker-compose 来创立。 初始数据有了数据库之后,咱们还须要表构造和初始数据,这部分也有两种计划: 应用 orm 提供的 sync/migration 相似的性能,将构造体间接映射生成表字段,通过 go 代码创立初始数据间接应用 sql 语句,通过执行 sql 语句来创立对应的表构造和字段数据本案例应用第一种形式进行,第二种也相似根本 case 代码咱们首先来疾速搞定一下默认的 case 代码,也就是咱们经常搬砖的 CRUD。(这里仅给出最根本的实现,重点次要关注在单元测试上) package repoimport ( "context" "go-demo/m/unit-test/entity" "xorm.io/xorm")type UserRepo interface { AddUser(ctx context.Context, user *entity.User) (err error) DelUser(ctx context.Context, userID int) (err error) GetUser(ctx context.Context, userID int) (user *entity.User, exist bool, err error)}type userRepo struct { db *xorm.Engine}func NewUserRepo(db *xorm.Engine) UserRepo { return &userRepo{db: db}}func (ur userRepo) AddUser(ctx context.Context, user *entity.User) error { _, err := ur.db.Insert(user) return err}func (ur userRepo) DelUser(ctx context.Context, userID int) error { _, err := ur.db.Delete(&entity.User{ID: userID}) return err}func (ur userRepo) GetUser(ctx context.Context, userID int) (user *entity.User, exist bool, err error) { user = &entity.User{ID: userID} exist, err = ur.db.Get(user) return user, exist, err}初始化测试环境首先创立 repo_main_test.go 文件 ...

March 7, 2023 · 3 min · jiezi

关于单元测试:Golang-单元测试-前言

在测试上难以自动化的软件,很难成为好的软件。 -- 《Google软件测试之道》对于单元测试的想法对于单元测试,开发者总是有着十分矛盾的思维。 单元测试很好,它能帮忙咱们找到很多暗藏的bug但写单元测试,比搬砖还累,我真的不想写~没错,单元的确是一个磨炼意志的货色,如果不是在大公司,人力也不够,而因为单元测试往往是没有 KPI 的,所以常常在做完功能测试之后就疾速上线一直迭代了。 但,如果想要成为一个杰出的软件,或者说是作品,单元测试是保障可继续倒退的地基。比方,很多的开源软件,为了保障牢靠,单元测试覆盖率往往都有着很高的规范。 于是,从 JAVA 的 JUnitTest 的坑爬出来之后,我筹备来写写,在 Golang 中咱们如何做单元测试。不肯定是最佳实际,但相对算是不错的参考。本文先来说说单元测试的要求和留神点。 什么是单元测试笔者从书中总结了一句话:自动化验证一个独立模块的代码是否能满足预期要求的测试。 所以单元测试是一个最最底层的一个测试,思路就是保障最小的模块没有问题,只有底子稳了,下面的业务才不容易呈现问题。 要求总结自《代码整洁之道》自动化自动化是一个最根底的要求,你不能说单元测试是通过你手动点击某个按钮,输出一个用户名明码,这样进行测试。单元测试应该就是启动之后主动实现的,并且对于测试后果应该做到自动化验证,而不是通过人的眼睛去判断输入的内容是否合乎产品需要。 疾速单元测试应该测试的够快,如果单元测试跑的太慢会导致的一个问题就是人们很少去运行它。如果一个单元测试要跑 10 秒钟,那么开发者就会想着反正 10 秒钟,跑就跑一下。频繁的跑单元测试更容易提前发现未知的问题。 环境统一测试的环境应该是和应用环境统一的,这也是很多测试的一个根本保障。应用环境是 mysql8 你用 mysql5.7 进行测试就会可能脱漏问题。并且这个测试环境应该是包含在单元测试外面的。 独立单元测试应该是独立存在的,也就是对于执行程序应该是没有要求的。A 模块先测试而后 B 模块再测试就没有问题;然而 B 模块先测试 A 模块再测试就会报错,这样是不行的。这也是一个最根本的要求,一个单元测试运行的前后,要么数据现场复原,要么你能保障以后的测试数据肯定不会影响前面的测试。在你通常无奈保障的时候,原则上都要进行数据恢复。比方你测试减少1条数据,那么测试实现之后就须要将数据删除。 注意事项不要为了谋求覆盖率而忘本拿数据谈话,在很多中央都实用,数据往往能给人们很大的安全感,没错,单元测试覆盖率 99% 那么能够给人十分大的安全感。然而!这是不太事实的。 对于绝大多数的软件来说,只有软件我的项目够大,你要反对的覆盖率越大,你的开发成本也就越大。 最重要的是:即便你的代码覆盖率是 100% 也不是状况 100% 笼罩。代码尽管这部分跑过了,然而因为数据的不同,一个边界条件就能让你雷同的代码报错。打算法较量的人都晓得,同样的性能,只有测试数据全过能力 AC。所以与其去测试一个十分偶尔的数据库连贯异样,不如多测一组 '-1' 数据会不会报错。 单元测试既有开发成本也有保护老本《单元测试的艺术》中说到单元测试的老本:个别残缺的单元测试和开发成本是统一的(开发一天;测试一天,这件事其实很难掂量性价比)。而且单元测试写的越多,保护老本也就开始一直减少,当我的项目的性能一直变动,单元测试也要跟着调整,也就是说,你的麻利开发和疾速迭代会被单元测试所连累,你须要掂量老本。 并不举荐一开始就写在国内(拥抱变动),特地是中小型公司,往往业务性能是不稳固的,需要始终在扭转,所以其实我并不举荐一开始就写单元测试。有工夫不如将功能测试全副通过,这样能更快上线,更快有反馈。尤其是像国内这种以产品为导向的开发方式,需要变动往往只须要一个小时,前一秒是产品经理认为能够,下一秒老板就说不行的状况太多了。在业务稳固之后,缓缓补,我集体真的感觉并不是一件错事。当然,大公司为了保障业务牢靠,也有测试左移等等思路,并且一些有着残缺布局并且实施方案的我的项目,TDD(测试驱动开发)也未尝不可,总之也是须要具体情况具体分析的。 PS:我也已经有一个我的项目领会过测试驱动开发,写了一大堆测试用例和单元测试之后,当理论在开发性能的时候还再回过头来批改测试用例 Golang web 根本分层测试思路前面,我将会从一个最根底的 web 开发的思路,分层进行阐明(如下所示),如何编写 Golang 在 Web 开发中的单元测试,以及其中能够应用哪些工具来帮忙咱们疾速实现和测试。 repo 数据层:间接拜访数据库或者缓存这一层的单元测试service 逻辑层:针对业务逻辑层的单元测试API 接口层:http 的接口层如何进行正当的测试其余测试相干:如何做表格驱动测试,bentchmack 测试,测试覆盖率单元测试是一场辛苦的修行,来让咱们开启一个 Golang 单测之旅 ~

March 6, 2023 · 1 min · jiezi

关于单元测试:一台不容错过的Java单元测试代码永动机

作者:京东批发 陈志良 作为一名京东的软件匠人,咱们开发的软件撑持着数亿的用户,责任是重大的,因而咱们深深地敬畏每一行代码,那如何将咱们的失误降到最低呢?那就是单元测试,它会让咱们建立对代码的自信心。为此咱们冀望能打造一台生产Java单元测试代码的“永动机”,源源不断地为开发者生产代码,辅助大家高效地做好单元测试,节俭精力能投入到更多的业务翻新中去。一、开发者对代码的自信心来自哪里?京东随着业务高速倒退,咱们缔造的、承载着数亿用户的、功能强大的零碎,在通过十多年的打磨,也变得日益简单。作为JD软件开发者,咱们是骄傲的,但咱们承当的责任也是重大的。咱们每一次的翻新,就像打造一座下图这样的过山车。咱们在为客户带来如此顶级体验的同时,更重要的是保障每一次的旅行都能够平安地着陆。所以咱们深深敬畏每一行代码,致力将咱们的失误降到最低,为业务保驾护航。 然而,业务的迭代速度之快,交付压力之大,作为“过山车”的缔造者,你是否有以下的经验? 1)每一次上线也像坐了一次过山车呢? 2)你亲手打造的“过山车”,本人是否亲自体验过呢? 3)你是否曾对测试同学说,“你们先上去坐坐看,遇到了问题再下来找我”? 如果你的答案是:每一次上线也像坐了一次过山车,咱们本人打造的“过山车”本人不敢坐,咱们的代码要靠测试同学兜底,那么就阐明咱们对本人的代码是不足信念的,咱们的工作还有待晋升的空间;反之则阐明,作为一个开发者你曾经相当优良了。 那么如何让咱们开发者建设对本人代码的信念呢,一般来说有两种形式: 1)对“过山车”的每个整机都进行充沛的测试,保障每一部分在各种场景下都能够失常工作,对所有的异样也可能解决切当,这即是单元测试。 2)对“过山车”启动前做好充沛“查看”,这即是代码评审,咱们邀请其余大佬帮咱们把关,及时发现问题。 这两局部工作在开发阶段都是必要的工作,二者缺一不可。 代码评审是借助了外力,单元测试则是内功,靠本人,靠开发者自测来加强对代码的信念。 本文次要和大家一起探讨单元测试,如何把这单元测试的内功练好。 二、做好单测,慢即是快对于单元测试的认识,业界同仁了解多有不同,尤其是在业务变动疾速的互联网行业,通常的问题次要有,必须要做吗?做到多少适合?当初没做不也挺好的吗?甚至一些大佬们也是存在不同的认识。咱们如下先看一组数字: “在 STICKYMINDS 网站上的一篇名为 《 The Shift-Left Approach to Software Testing 》 的文章中提到,如果在编码阶段发现的缺点只须要 1 分钟就能解决,那么单元测试阶段须要 4 分钟,功能测试阶段须要 10 分钟,零碎测试阶段须要 40 分钟,而到了公布之后可能就须要 640 分钟来修复。”——来自知乎网站节选 对于这些数字的准确性咱们暂且持保留意见。大家能够想想咱们理论中遇到的线上问题大略须要耗费多少工时,除了要疾速找到bug,修复bug上线,还要修复因为bug引发的数据问题,最初还要复盘,看后续如何能防止线上问题,这样下来激进预计应该不止几人日吧。所以这篇文章作者所做的调研数据可信度还是很高的, 缺点发现越到交付流程的后端,其修复老本就越高。 有人说写单测太消耗工夫了,会缩短交付工夫,其实不然: 1)研测同学大量的往返交互比编写单测的工夫要长的多,集成测试的工夫被拖长。 2)没通过单测的代码bug会多,开发同学忙于修复各种bug,对代码debug跟踪调试找问题,也要耗费很多精力。 3)前期的线上问题也会须要大量的精力去补救。 如果有了单元测试的代码,且能实现一个较高的行覆盖率,则能够将问题尽可能毁灭在开发阶段。同时有了单测代码的积攒,每次代码改变后能够提前发现这次改变引发的其余关联问题,上线也更加释怀。单测尽管使提测变慢了一些,软件品质更加有保障,从而节俭了后续同学的精力,从整体看其实效率更高。 所以做好单测,慢即是快。 咱们团体技术委员会大佬们从去年开始也在倡导大家做单元测试, 做为一名开发者咱们须要对本人的代码品质负责, 也更能体现咱们大厂开发者的工匠精力。 三、如何编写单元测试1、单元测试的支流框架及核心思想以下咱们先通过一个案例介绍下支流框架的思维。下图为一个简略的函数执行逻辑,在函数体内间接调用了函数1、函数2、函数3,间接调用了函数2.1,其中1和2别离是一般函数,2.1和3波及到内部零碎调用,例如JSF、Redis、MySQL等操作,最初返回后果。 代码大抵如下: public class MyObject { @Autowired private RedisHelper redisHelper; public MyResult myFunction(InputParam inputParam){ MyResult myResult = new MyResult();//一般代码块 if(inputParam.isFlag()) { //如果标记flag为true,则执行函数1 String f1 = invokeFunction1(); //调用函数3,函数3封装了redis中间件操作 String f3 = redisHelper.get(f1); myResult.setResult(f3); } else { //调用函数2,在函数2外部又调用近程服务接口2.1 String f2 = invokeFunction2(); myResult.setResult(f2); } return myResult; } 在当下微服务时代,零碎间的交互变得更加日益简单,以上图例只是简化的例子,理论零碎中的上下游内部依赖多达十几个,甚至几十个。 ...

February 21, 2023 · 1 min · jiezi

关于单元测试:mockito入门

前言最近在我的项目中跑单元测试发现间接应用springboot自带的测试,一整套跑起来破费数十分钟,这是无法忍受的,思考到性能的特殊性,想到了Spring测试包自带的mockito单元测试,所以进行首次尝试应用。 测试代码pom包 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-inline</artifactId> <version>4.5.1</version> <scope>test</scope> </dependency> import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * @author Steven * @Date 2023/1/30 15:45 */ @Service public class OrderA { @Autowired private OrderC orderC; public int print() { System.out.println("D = "+ OrderD.getResult()); System.out.println(orderC.print(2)); System.out.println("hello world"); return -1; } } import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * @author Steven * @Date 2023/1/30 15:46 */ @Service public class OrderB { @Autowired private OrderA order; public boolean test() { System.out.println("order B test()"); System.out.println("order value = " + order.print()); System.out.println("order B hello world"); return true; } } import org.springframework.stereotype.Service; /** * @author Steven * @Date 2023/1/30 16:43 */ @Service public class OrderC { public int print(int a) { System.out.println("hello"+ a); return -1; } } import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * @author Steven * @Date 2023/1/30 17:32 */ @Component public class OrderD { private static OrderC orderC; @Autowired public OrderD(OrderC orderCa) { System.out.println("=================="); orderC = orderCa; } public static int getResult(){ System.out.println("hhhhh====" + OrderE.print()); return orderC.print(3); } } /** * @author Steven * @Date 2023/1/31 14:04 */ public class OrderE { public static int print() { System.out.println("ahhahahahahhaha"); return 1111111; } }次要测试类 ...

February 1, 2023 · 2 min · jiezi

关于单元测试:基于Unittest框架使用PythonSeleniumWebdriver的WebUI自动化测试项目应用实例附源码

@TOC 1、我的项目背景测试背景:在业务零碎的web页面,有一个分辨率设置性能,而这个性能是自定义的一个区间,用户能够设置分辨率800600到20482048, 共计1809801个分辨率,如果人工去进行遍历的话,预计得用半年工夫,十分吃力解决方案:应用webUI自动化管制分辨率性能的输出,其中每次输出都不反复,遍历所有的分辨率遍历数据解决:如果在脚本中惟一取值,间接由代码生成须要的数据的话,效率十分慢;所以把1809801个分辨率数据间接在txt文本中写入,只须要关上一次,而后每次从txt取值,直到取完为止业务UI图: 2、框架环境Python 3.5Python的sendmail、xlrd、HTMLtestRuner、CSV、ConfigParser、Json模块SeleniumPycharm 3、业务实现思路设置界面,批改输出源的分辨率的高和宽,以及刷新率,进行利用设施界面,查看对应输出源的分辨率信息把设置界面输出的分辨率信息和设施界面的显卡返回的分辨率信息进行比照,判断设置是否OK4、业务后果判断把设置界面输出的分辨率信息和设施界面的显卡返回的分辨率信息进行比照,判断设置是否OK,次要有两种状况: 超出带宽:在脚本中退出判断信息,如果输出的值依照计算公式大于165M带宽,才判断为超出带宽返回异样:输出的和返回的值不统一,这种状况个别保留数据,具体分析,如下示例: 5、数据处理对于运行的后果数据处理,目前反对三种形式: 把测试用例后果,通过HtmlTestRunner.py库封装成测试用例集,而后通过SendMail.py库,发送邮件给我的项目组成员。示例: 应用Eclipse开发平台,把测试后果的Console,保留到log中,实时抓取运行过程和后果数据(这个能够疏忽,后续间接在代码中加log) 把测试后果,间接保留到config的配置文件中,间接查看 6、框架阐明 7、操作阐明关上all_test,py批改接管邮箱地址和保留保留门路关上tools中的sendMail.py批改发送者的邮箱地址在Utils中的Settings3写业务模块的性能(Settings1和Settings2是多余的)在test_case中test_Settings_Custom_Resolution.py写测试用例执行all_test.py 8、数据存储成果 9、源码地址https://github.com/NoamaNelson/UnittestWebUIFour

January 11, 2023 · 1 min · jiezi

关于单元测试:unittest中使用ddt后生成的测试报告名称如何修改如testapi0修改成testapi0titile

批改前:Unittest应用ddt后生成的测试报告用例名称为:即就是,以“test_xx_数字”为格局的用例名称,感觉满足不了咱们的测试需要,不够直观。那么怎么批改呢? 查看ddt源码def mk_test_name(name, value, index=0): """ Generate a new name for a test case. It will take the original test name and append an ordinal index and a string representation of the value, and convert the result into a valid python identifier by replacing extraneous characters with ``_``. We avoid doing str(value) if dealing with non-trivial values. The problem is possible different names with different runs, e.g. different order of dictionary keys (see PYTHONHASHSEED) or dealing with mock objects. Trivial scalar values are passed as is. A "trivial" value is a plain scalar, or a tuple or list consisting only of trivial values. """ # Add zeros before index to keep order index = "{0:0{1}}".format(index + 1, index_len, ) if not is_trivial(value): return "{0}_{1}".format(name, index) try: value = str(value) except UnicodeEncodeError: # fallback for python2 value = value.encode('ascii', 'backslashreplace') test_name = "{0}_{1}_{2}".format(name, index, value) return re.sub(r'\W|^(?=\d)', '_', test_name) 从办法mk_test_name中,咱们看到该办法的形容是“Generate a new name for a test case.”,即就是为测试用例创立一个名称,那么改这个办法就行了办法中返回的是name和index,即"{0}_{1}".format(name, index)那么就明确了,咱们改返回的内容就行了批改后def mk_test_name(name, value, index=0): """ Generate a new name for a test case. It will take the original test name and append an ordinal index and a string representation of the value, and convert the result into a valid python identifier by replacing extraneous characters with ``_``. We avoid doing str(value) if dealing with non-trivial values. The problem is possible different names with different runs, e.g. different order of dictionary keys (see PYTHONHASHSEED) or dealing with mock objects. Trivial scalar values are passed as is. A "trivial" value is a plain scalar, or a tuple or list consisting only of trivial values. """ # Add zeros before index to keep order index = "{0:0{1}}".format(index + 1, index_len, ) if not is_trivial(value) and type(value) is not dict: # 减少的中央,减少value的字典判断 return "{0}_{1}_{2}".format(name, index, value.name) # 批改的中央,减少返回的值 if type(value) is dict: # 减少的中央 try: # 减少的中央 value = value["name"] + "_" + value["function"] # 减少的中央,name和function必须是execl用例中整正存在的表头,这里我是把两个表头合并了(name是我表格中接口的名称,function是表格中接口的性能形容) except: # 减少的中央 return "{0}_{1}".format(name.index) # 减少的中央 try: value = str(value) except UnicodeEncodeError: # fallback for python2 value = value.encode('ascii', 'backslashreplace') test_name = "{0}_{1}_{2}".format(name, index, value) # 批改的中央 return re.sub(r'\W|^(?=\d)', '_', test_name) ...

January 10, 2023 · 2 min · jiezi

关于单元测试:unittest使用parameterized参数化后如何调用添加到测试套件中

写了一个Unittest+Python+execl的一个接口自动化,在参数化的时候遇到了一个问题。具体的“坑”如下 要实现的需要在execl中波及或写接口测试用例,而后读取execl中每一行的数据,每一行数据就相当于一条用例 需要实现path = "F:\InterFace_JIA1\dataconfig\source_user_case.xlsx"params_list = TestRunCase(path).get_params()print("params_list:",params_list)class TestRun(unittest.TestCase): #params_list = [(2, 100000, 100001),(1, 100000, 100003)] @parameterized.expand(params_list) # 这里参数化了params_list def test_run(self, name, expect_res, actual_res): self.assertEqual(expect_res, actual_res)if __name__ == '__main__': unittest.main()用例为:后果为:先不论接口是不是有问题,从这个运行看,流程是OK的参数化后调用退出测试条件中if __name__ == '__main__': suite = unittest.TestSuite() now = datetime.datetime.now().strftime('%Y-%m-%d_%H_%M_%S') filename = "./report/" + now + '_result.html' fp = open(filename, 'wb') suite.addTest(TestRun('test_run')) runner = HTMLTestRunner.HTMLTestRunner( stream=fp, title=u'测试后果', description=u'全副测试用例') runner.run(suite) fp.close() time.sleep(2) print("sdasdasdasdasdasdsa")后果出错TypeError: 'NoneType' object is not callable 排查剖析应用unittest.defaultTestLoader.discover,打印所有的case,发现用例格局是“test_run_0” <unittest.suite.TestSuite tests=[<unittest.suite.TestSuite tests=[<main.run.TestRun testMethod=test_run_0>, <main.run.TestRun testMethod=test_run_1>]>]>if __name__ == '__main__': suite = unittest.defaultTestLoader.discover('./', pattern='run.py') for case in suite: print (case)从新调用把test_run改成test_run_0 ...

January 10, 2023 · 1 min · jiezi

关于单元测试:Go-test-单元测试用起来

什么是单元测试(unit testing)单元测试,是指对软件中的最小可测试单元进行检查和验证 单元就是人为规定的最小的被测功能模块 一般来说,要依据理论状况去断定其具体含意,如 C 语言中单元指一个函数,Go 外面也单元也是一个函数 单元测试是在软件开发过程中要进行的最低级别的测试流动,软件的独立单元将在与程序的其余局部相隔离的状况下进行测试。 单元测试,咱们平时也叫它单测,平时开发的时候,也须要写一些 demo 来测试咱们的我的项目中的函数或者某个小性能 go test 单元测试GO 语言外面的单元测试,是应用规范库 testing 有如下简略规定: 导入 test 规范库单测文件名,前面跟上_test单测文件中的函数名为 Test结尾,且参数必须是 t *testing.T简略例子:写一个简略的例子,增加后缀和前缀 .├── cal.go├── cal_test.go├── lll└── sub.gocal.go package mainfunc Addprefix(str string) string { return "hello_"+str}func Addsuffix(str string) string { return str+"_good"}cal_test.go package mainimport "testing"func TestAddprefix(t *testing.T) { Addprefix("xiaomotong")}func TestAddsuffix(t *testing.T) { Addsuffix("xiaomotong")}sub.go package mainfunc MyAdd(a int, b int) int { if a+b > 10{ return 10 } return a+b}func MySub(one int, two int) int{ if one - two < 0{ return 1 } return one - two}sub_test.go ...

October 29, 2022 · 2 min · jiezi

关于单元测试:golang单元测试一简单函数测试

0.1、索引https://blog.waterflow.link/articles/1663688140724 1、简介单元测试是测试代码、组件和模块的单元函数。单元测试的目标是革除代码中的谬误,减少代码的稳定性,在更改代码时提供正确性。单元测试是软件测试的第一级,而后是集成测试和 ui 测试。 2、编写测试代码首先测试文件的命名必须以_test.go结尾,测试方法必须以Test结尾 咱们创立一个testexample我的项目,执行go mod init初始化我的项目。 而后创立一个uri.go的文件,外面的代码是我摘抄自golang的amqp包中的一段解析ampq url的代码,具体链接 package uriimport ( "errors" "net" "net/url" "strconv" "strings")var errURIScheme = errors.New("AMQP scheme must be either 'amqp://' or 'amqps://'")var errURIWhitespace = errors.New("URI must not contain whitespace")var schemePorts = map[string]int{ "amqp": 5672, "amqps": 5671,}var defaultURI = URI{ Scheme: "amqp", Host: "localhost", Port: 5672, Username: "guest", Password: "guest", Vhost: "/",}// URI represents a parsed AMQP URI string.type URI struct { Scheme string Host string Port int Username string Password string Vhost string}// ParseURI attempts to parse the given AMQP URI according to the spec.// See http://www.rabbitmq.com/uri-spec.html.//// Default values for the fields are://// Scheme: amqp// Host: localhost// Port: 5672// Username: guest// Password: guest// Vhost: ///func ParseURI(uri string) (URI, error) { builder := defaultURI // 如果链接中有空字符串,返回默认值和谬误 if strings.Contains(uri, " ") { return builder, errURIWhitespace } // 解析url为构造体,解析失败返回默认值和谬误 u, err := url.Parse(uri) if err != nil { return builder, err } // 依据scheme获取默认端口 defaultPort, okScheme := schemePorts[u.Scheme] if okScheme { builder.Scheme = u.Scheme } else { // 获取不到就返回默认值和谬误 return builder, errURIScheme } host := u.Hostname() port := u.Port() if host != "" { builder.Host = host } if port != "" { port32, err := strconv.ParseInt(port, 10, 32) if err != nil { // 解析进去的端口转整型失败,返回最新的URI和谬误 return builder, err } builder.Port = int(port32) } else { builder.Port = defaultPort } if u.User != nil { builder.Username = u.User.Username() if password, ok := u.User.Password(); ok { builder.Password = password } } if u.Path != "" { if strings.HasPrefix(u.Path, "/") { if u.Host == "" && strings.HasPrefix(u.Path, "///") { // net/url doesn't handle local context authorities and leaves that up // to the scheme handler. In our case, we translate amqp:/// into the // default host and whatever the vhost should be if len(u.Path) > 3 { builder.Vhost = u.Path[3:] } } else if len(u.Path) > 1 { builder.Vhost = u.Path[1:] } } else { builder.Vhost = u.Path } } return builder, nil}func (uri URI) String() string { authority, err := url.Parse("") if err != nil { return err.Error() } authority.Scheme = uri.Scheme if uri.Username != defaultURI.Username || uri.Password != defaultURI.Password { authority.User = url.User(uri.Username) if uri.Password != defaultURI.Password { authority.User = url.UserPassword(uri.Username, uri.Password) } } authority.Host = net.JoinHostPort(uri.Host, strconv.Itoa(uri.Port)) if defaultPort, found := schemePorts[uri.Scheme]; !found || defaultPort != uri.Port { authority.Host = net.JoinHostPort(uri.Host, strconv.Itoa(uri.Port)) } else { // JoinHostPort() automatically add brackets to the host if it's // an IPv6 address. // // If not port is specified, JoinHostPort() return an IP address in the // form of "[::1]:", so we use TrimSuffix() to remove the extra ":". authority.Host = strings.TrimSuffix(net.JoinHostPort(uri.Host, ""), ":") } if uri.Vhost != defaultURI.Vhost { // Make sure net/url does not double escape, e.g. // "%2F" does not become "%252F". authority.Path = uri.Vhost authority.RawPath = url.QueryEscape(uri.Vhost) } else { authority.Path = "/" } return authority.String()}先不必思考下面函数的复杂性,咱们的目标很简略,就是要测试ParseURI函数。那如何测试呢?首先咱们须要创立一个uri_test.go文件,个别和须要测试的uri.go在同一个目录下。其次文件的包名也须要和uri.go 统一。 ...

September 20, 2022 · 11 min · jiezi

关于单元测试:淘系用户平台技术团队单元测试建设

简介:单元测试是工程交付前品质保障的第一环,也无疑是软件工程品质保障的重要基石,无效的单元测试可能提前发现90%以上的代码Bug问题,同时也能避免代码的腐化,在工程重构演进时起到至关重要的作用。 作者 | 问元起源 | 阿里开发者公众号 为什么须要单元测试纵观优良的开源工程,齐备的单元测试总是必须的条件。通过这些单元测试,咱们能够充沛理解代码中相干类和办法的作用和外围逻辑,相熟各种场景的运行状况。同时也因为有了单元测试,开源作者在承受各种feature的代码提交时才有稳固平安的保障。其实单元测试的重要性所有开发同学应该都了然于胸,同样TDD(测试驱动开发)也不是一个新的概念,然而真当咱们落地实际时,又总会找出各种各样的理由来劝服本人下次肯定好好写单元测试,这一次先放过本人。这些理由无外乎,开发周期太紧了; 测试同学能保障性能正确性;写单元测试代码量比业务代码还大; 又不是不能跑。所以尽管咱们总是在追赶工程师文化,却又时不时放荡在放弃工程师底蕴的路上。 单元测试是工程交付前品质保障的第一环,也无疑是软件工程品质保障的重要基石,无效的单元测试可能提前发现90%以上的代码Bug问题,同时也能避免代码的腐化,在工程重构演进时起到至关重要的作用。 怎么写单元测试好的单元测试的几个要点摘自阿里巴巴开发规约 单元测试必须恪守AIR准则,单元测试必须具备Automatic(自动化),Independent(独立性),Repeatable(可反复)性;单元测试应该是全自动执行的,并且非交互式的。测试用例通常是被定期执行的,执行过程必须齐全自动化才有意义。输入后果须要人工查看的测试不是一个好的单元测试;单元测试要保障测试粒度足够小。单元测试测试粒度足够小,有助于精确定位问题。单测粒度至多是类级别,个别是办法级别;单元测试要恪守BCDE准则,Border,边界值测试,包含循环边界、非凡取值、非凡工夫点、数据程序等;Correct,正确的输出,并失去预期的后果;Design,与设计文档相结合,来编写单元测试;Error,强制错误信息输出(如:非法数据、异样流程、非业务容许输出等),并失去预期的后果;外围业务、外围利用、外围模块的增量代码要确保单元测试通过;单元测试编码范式这里次要以Mockito单元测试框架为模版 Mock : 通过when().thenReturn/thenAnswer/thenThrow 或者doReturn().when()等mock形式将依赖类办法进行模仿,模仿服务依赖或者两头后果DO : 调用被测试类办法,执行测试链路Verify : 校验执行后果正确性,通过Assert校验数据后果精确,通过Verify校验链路执行精确,通过expected=Exception.class校验异样链路public class Test { // 0. 依赖类 @Mock DependencyClass dependencyClass; // 0. 待测试类 @InjectMocks TestClass testClass; @Before public void setUp() { MockitoAnnotations.initMocks(this); } @Test public void testMethod() { // 1. Mock, 依赖办法,结构中间层数据 when(dependencyClass.someMehod(any())).thenReturn(mockData()); // 2. Do, 调用被测试类 Result result = testClass.testMehod(); // 3. Verify, 校验后果数据 Assert.assertEquals("some expected result string", result.getModel()); }}当然写单元测试用例尽管套路比拟模版化,然而咱们也要充分利用单元测试框架(Junit/Mockito/PowerMock/Spock),把握其中的一些技巧,能力写出快准狠的单元测试用例,这也是研发同学必须要把握的基本功。对于如何利用单元测试框架这里不再赘述(具体能够参考阿里技术《Java编程技巧之单元测试用例编写流程》)。 ...

May 16, 2022 · 1 min · jiezi

关于单元测试:项目里的UT越来越慢怎么办

我的项目里的UT越来越慢,怎么办?JUnit是一个Java语言的单元测试框架。它由Kent Beck和Erich Gamma建设,逐步成为源于Kent Beck的sUnit的xUnit家族中最为胜利的一个。 JUnit有它本人的JUnit扩大生态圈。少数Java的开发环境都曾经集成了JUnit作为单元测试的工具。它曾经倒退有20余年历史了当初咱们的我的项目在Jenkins流水线上每次部署时,随着code越来越多,UnitTest这部分Stage也每次都跑得最慢,怎么能够加快速度呢? 能够试着从code层面去尝试 refactor,比方将Junit4降级到更好效率更快的Junit5 JUnit5JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage JDK Version >= 8 (而 JUnit4是要求 JDK Version >= 5) JUnit平台它定义了TestEngine用于开发在平台上运行的新测试框架的APIJUnit Jupiter它具备所有新的junit正文和TestEngine实现,以运行应用这些正文编写的测试JUnit Vintage反对在JUnit 5平台上运行JUnit 3和JUnit 4编写的测试JUnit5的规范用法 集成Spring(The SpringJUnitConfig and SpringJUnitWebConfig Annotations in Spring 5 | Baeldung) 应用JUnit5的拓展模型个性,@ExtendWith(SpringExtension.class),能够应用Spring的上下文装载性能,而不必去应用重量级的@SpringBootTest集成Mockito (Mockito and JUnit 5 - Using ExtendWith | Baeldung) 引入JUnit5和Mockito的maven依赖配置Surefire Plugin,使得测试代码都运行在新的JUnit平台上有必要兼容JUnit4的测试代码的话,还需退出JUnit5 vintage-engine的maven依赖@ExtendWith(MockitoExtension.class), 集成Mockito,能够应用@Mock, @Spy, @InjectMocks等注解,不便咱们写UTJUnit 4 VS JUnit 5注解的区别注解的应用区别 罕用的//Exception@Test(expected = Exception.class) // JUnit4@Test(timeout = 1) // JUnit4//TimeOutAssertions.assertThrows(); // JUnit5Assertions.assertTimeout(1); //JUnit5@RunWith 和 @ExtendWith(最大个性差别) ...

April 16, 2022 · 1 min · jiezi

关于单元测试:适用于-androidjvm-的单测生成器-randunit

背景在继续交付越来越风行的明天,单测作为保障 CI 品质的重要一环也开始在国内被器重起来。 不过在单测上大家的态度还是比拟矛盾的,放心的事件次要有两个: 从 0 到 1 的第一步不晓得从何下手万一花大力量做了之后发现没什么用怎么办然而短少这一环,在整个 devops 流程中很多编译时重大问题会被延缓到运行时裸露,这对于我的项目效率妨碍也不小。。 于是就有了灵感起源: 主动生成一系列冒烟级别单测用例,并能发现重大问题接入成本低,能无痛与现有流程联合能对 android 失效(我司重挪动端 做了什么RandUnit 取义自 Random UnitTest,他会: 依据提供的包名或入口类,搜寻所有相干的待测试类与办法依据搜寻后果,为每个办法生成一系列 statements 用于测试像惯例单测流程个别,在 junit 上运行这些 statements,失去测试后果而这所有只须要一次简略的复制粘贴: import com.williamfzc.randunit.env.NormalTestEnvimport com.williamfzc.randunit.models.StatementModelimport com.williamfzc.randunit.scanner.ScannerConfigimport org.junit.Testimport org.junit.runner.RunWithimport org.junit.runners.Parameterized@RunWith(Parameterized::class)class MinExampleTest(private val statementModel: StatementModel) { companion object { private val testEnv = NormalTestEnv() private const val packageName = "com.your.package" private val cases by lazy { val scannerConfig = ScannerConfig() scannerConfig.includeFilter.add(packageName) RandUnit.collectStatementsWithPackage(packageName, scannerConfig) } @JvmStatic @user3ters(name = "{0}") fun data(): Collection<StatementModel> { return cases } } @Test fun runStatements() { testEnv.runStatementInSandbox(statementModel) }}因为它是非法的 junit 用例,所以你能够在 ide 里间接运行它。间接 run with coverage 的话: ...

January 20, 2022 · 1 min · jiezi

关于单元测试:基于链路思想的SpringBoot单元测试快速写法

简介:本文更偏差实际而非方法论,所提及的SpringBoot单元测试写法亦并非官网解,仅仅是笔者本身感觉比拟不便、效率较高的一种写法。每个团队甚至团队内的每位开发可能都有本人的写法习惯和格调,只有能实现单元测试的成果,就没必要纠结于写法的简略抑或简单。这里也欢送各位大佬们发表认识或分享本人的单测心得,帮忙像笔者这样的新人疾速成长。 作者 | 桃符起源 | 阿里技术公众号 引言: 本文更偏差实际而非方法论,所提及的SpringBoot单元测试写法亦并非官网解,仅仅是笔者本身感觉比拟不便、效率较高的一种写法。每个团队甚至团队内的每位开发可能都有本人的写法习惯和格调,只有能实现单元测试的成果,就没必要纠结于写法的简略抑或简单。这里也欢送各位大佬们发表认识或分享本人的单测心得,帮忙像笔者这样的新人疾速成长。 一 为什么要写单元测试?测试是Devops上极重要的一环,但大多数开发的眼光都停留在集成测试这一环——只有能联调胜利,那么我这次筹备上线的个性肯定是没问题的。 诚实抵赖,我已经是这样的可能当初也还是这样。作为非科班出身的笔者,研究生毕业后就立刻进入了同在杭州的xx厂,先后参加了外部Devops平台建设和xx云Paas我的项目垦荒,在这两个我的项目中,开发 > 测试是很失常的场景,甚至局部测试也是原开发情谊客串的:因为短少业余的测试人员,开发往往须要兼顾集成测试甚至是线上测试的活儿。为了提高效率,我将一部分罕用的测试用例保护在了外部的自动化测试平台上。即便如此,我仍能清晰地感觉到,测试所能笼罩的场景比比皆是,以至于每次自信地上线大个性后,都会因一些奇怪的问题而定位到大半夜。幸好前面遇到了一位资深大佬,在code review时,他间接点出我不写单元测试的坏习惯,并用本身惨痛的线上教训反复强调单测的重要性。 当然上述只是我的亲身经历,勉强作为日常闲聊的谈资。如果想要深刻了解单元测试的重要性,举荐Google上搜寻the importance of unit test关键字,能够感触下不同国家、不同畛域的程序员对单元测试的不同了解,想必能有更大的播种。 二 为什么举荐链路思维?深刻接触单元测试,开发难免会遇到以下场景: 应该如何设计测试用例?应该如何编写测试用例?测试用例的品质该如何断定?刚开始学习写单元测试,我也曾参考并尝试过网上形形色色的写法。这些写法可能用到了不同的单测框架,也可能偏重了不同的代码环节(例如特定的某个service办法)。一开始我为本人可能纯熟应用多种单测框架而沾沾自喜,但随着工作的推动,我逐步意识到,单元测试中重要的并不是框架选型,而是如何设计一套优良的用例。之所以用"一套"而不是"一个",是因为在咱们的业务代码中,逻辑往往并非"一帆风顺",有许多if-else会妆点咱们的业务代码。显然对于这类业务代码,"一个"测试用例无奈齐全满足所有可能呈现的场景。如果为了偷懒,尝试仅仅用"一个"用例去笼罩主流程,无异于给本人埋了个雷——线上场景可没"一个"用例这么简略! 我开始专一于测试用例的设计,从输入输出开始,从新扫视已经开发过的代码。我发现,如果将某个controller办法作为入口,那这一套业务流程能够当做一条链路,而上下文中所关联的service层、dao层、api层的各办法都能够作为链路上的各环节。通过绘制链路图,将各环节依据是否关联内部零碎大抵分成黑、白两类,整套业务流程和各环节的潜在分支便会变得清晰,测试用例便从"一个"自然而然地变成了"一套"。此处多提一嘴,链路思维设计用例的根底是构造清晰、圈复杂度可管制的代码格调,如果开发的时候仍然尊敬"论文式"、"一刀流",在单个办法内"简明扼要",那链路式将是一个微小的累赘。 编写测试用例其实不是一件吃力的事,对于深耕业务代码的开发而言,编写测试用例便像是做一盘小菜,举手可为。于我而言,现在写测试用例所破费的工夫甚至没有设计测试用例的工夫长(凸显用例设计的重要性但也有可能是我对测试用例的设计还不够纯熟)。在测试框架选型上,我更习惯于Junit+Mockito的组合,起因仅仅是相熟与简略,且参考文档亘古未有。如果各位曾经有本人习惯的框架和写法,也不用照搬本文所提及的货色,毕竟单测是为了better code,而不是自找麻烦。 但无论测试用例如何设计或是如何编写,我始终认为,在不思考测试代码的格调和标准的前提下,掂量测试用例品质的外围指标是分支覆盖率。这也是我举荐链路思维的一大起因——从入口登程,遍历链路上各个环节的各个分支,遇到妨碍就Mock;相比于别离单测各个独立办法,单测链路所须要的入参和出参更加清晰,更是大大节俭了编写测试代码所需的工夫老本!计算分支覆盖率的工具有很多,例如本地的JaCoCo或是各类云化测试工具。试想,每当看到单测完满地笼罩了本人所提交的个性代码时,心里是不是释怀了许多? 三 如何用链路思维设计/结构单测?作为程序员,大家更为相熟的链路概念应该是全链路压测。 全链路压测简略来说,就是基于理论的生产业务场景、零碎环境,模仿海量的用户申请和数据对整个业务链进行压力测试,并继续调优的过程,实质上也是性能测试的一种伎俩。... 通过这种办法,在生产环境上落地常态化稳固压测体系,实现IT零碎的长期性能稳固治理。 如果将残缺的业务流程视作全链路,那作为业务链上的一环,即某个后端服务,它其实也是一个微链路。这里以自上而下的开发流程为例,对于新增的性能接口,咱们会习惯性地由controller开始设计,而后构建service层、dao层、api层,最初再精益求精地加些aop。如果以链路思维,将简单的流程拆成各个链路的各个环节,那这样的代码性能清晰,保护起来也相当不便。我十分认同 限度单个办法行数<=50 的代码门禁,对于简明扼要的代码“论文”,想必没有哪位接手的同学脸上能露出笑容的;针对这类代码,我认为clean code的优先级比补充单测用例更高,连逻辑都无奈理清,即使硬着头皮写出单测用例,后续的调试和保护工作量也是不可意料的(试想,如果前面有位A同学接手了这块代码,他在“论文”中加了xx行导致ut失败了,他该如何去定位问题)。 简略画个图来强调一下我的观点。这是一张"用户买猪"的性能逻辑图。以链路思维,开发人员将整套流程拆分为相应的链路环节,涵盖了controller、service、dao、api各层;整条链路清晰明了,只有搭配欠缺的上下文日志,定位线上问题亦是轻而易举。 当然,基于链路思维的开发还远远不够,在补充单测用例时,咱们同样也能用链路思维来结构测试用例。测试用例的要求很简略,须要笼罩controller、service等自主编写的代码(多分支场景也须要齐全笼罩),对于周边关联的零碎能够采纳Mock进行屏蔽,对于Dao层的SQL能够视需要决定是否Mock。秉承这个思路,咱们能够对“用户买猪”图进行革新,将容许Mock的环节涂灰,从而变成咱们在编写单元测试用例时所须要的“虚构用户买猪”图。 四 疾速写法实际案例1 疾速写法的外围步骤有哪些?疾速写法的入口是controller层办法,这样对于controller层存在的大量逻辑代码也能做到笼罩。 设计测试用例的输出与预期输入 设计测试用例的目标不仅仅是跑通主流程,而是要跑通全副可能的流程,即所谓的分支全笼罩,因而设计用例的输出与输入尤为重要。即使是新增分支的增量批改(例如加了一行if-else),也须要补充相应的输出与预期输入。十分不倡议依据单测运行后果批改预期后果,这阐明原先的代码设计有问题。 确定链路上的全副Mock点 Mock点的判断根据是链路上该环节是否依赖第三方服务。强烈建议在设计前画出大略的性能流程图(如”用户买猪“图),这能够大大提高确定Mock点的速度和准确性。 收集Mock点的模仿返回数据 确定Mock点后,咱们就须要结构相应的模仿返回数据。Mock数据须要思考多个因素: a. 是否与api层对应办法的冀望返回值匹配: 不能把从猪厂返回的Mock数据用牛肉代替 b. 是否与模仿输出数据匹配:用户须要1斤猪肉,不能返回5斤猪肉的数据 c. 是否与api层的所有分支匹配:局部api层会对返回值进行响应码(2xx || 3xx || 4xx)校验,这类场景便须要结构不同响应码的Mock数据 2【开发篇】实在用户买猪该我的项目基于PandoraBoot构建,手动降级SpringBoot版本至2.5.1,应用Mybatis-plus组件简化Dao层开发过程。上面选取了上文图中所波及的重要办法进行展现,仅实现了简略的业务流程,零碎框架和工程构造能够参考代码仓。 业务对象 PorkStorage.java - 猪肉库存的数据库实体类/** * 猪肉库存的数据库实体类 */@Data@NoArgsConstructor@AllArgsConstructor@Builder@TableName(value = "pork_storage", autoResultMap = true)public class PorkStorage { @TableId(value = "id", type = IdType.AUTO) private Long id; private Long cnt;}PorkInst.java - 猪肉实例,由仓库打包后生成 ...

January 19, 2022 · 3 min · jiezi

关于单元测试:JUnit单元测试

JUnit单元测试一.JUnit介绍JUnit是Java中最有名的单元测试框架,用于编写和运行可反复的测试,少数Java的开发环境都曾经集成了JUnit作为单元测试的工具。好的单元测试能极大的进步开发效率和H5游戏。测试类命名规定:被测试类+Test,如UserServiceTest测试用例命名规定:test+用例办法,如testGetMaven导入junit、sprint-test  <dependencies> <!-- Test Unit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>4.3.10.RELEASE</version> <scope>test</scope> </dependency> <!-- Json断言测试 --> <dependency> <groupId>com.jayway.jsonpath</groupId> <artifactId>json-path</artifactId> <version>2.4.0</version> <scope>test</scope> </dependency></dependencies><build> <plugins> <!-- 单元测试插件 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.20</version> <dependencies> <dependency> <groupId>org.apache.maven.surefire</groupId> <artifactId>surefire-junit4</artifactId> <version>2.20</version> </dependency> </dependencies> <configuration> <!-- 是否跳过测试 --> <skipTests>false</skipTests> <!-- 排除测试类 --> <excludes> <exclude>**/Base*</exclude> </excludes> </configuration> </plugin> </plugins></build> 二.Service层测试示例创立Service层测试基类,新建BaseServiceTest.java // 配置Spring中的测试环境@RunWith(SpringJUnit4ClassRunner.class)// 指定Spring的配置文件门路@ContextConfiguration(locations = {"classpath*:/spring/applicationContext.xml"})// 测试类开启事务,须要指定事务管理器,默认测试实现后,数据库操作主动回滚@Transactional(transactionManager = "transactionManager")// 指定数据库操作不回滚,可选@Rollback(value = false)public class BaseServiceTest {}测试UserService类,新建测试类UserServiceTest.javapublic class UserServiceTest extends BaseServiceTest { ...

July 23, 2021 · 1 min · jiezi

关于单元测试:单元测试不规范事后运维两行泪

单元测试好的单元测试应该恪守AIR准则 单元测试在线上运行时,应该感觉像空气(AIR)一样,并不存在,但在测试品质的保障上,的确十分要害的好的单元测试宏观上来说,具备以下的特点: 自动化(A: Automatic)独立性(I: Independent)可反复(R: Repeatable)单元测试应该是全自动执行的,并且是非交互式的 测试用例通常是被定期执行的,执行过程必须齐全自动化才有意义输入后果须要人工查看的测试不是一个好的单元测试单元测试中不准应用System.out来进行人的验证,必须应用assert来验证放弃单元测试的独立性 为了保障单元测试稳固牢靠且便于保护: 单元测试用例之间决不能相互调用不能依赖执行的先后秩序单元测试是能够反复执行的,不能受到外界环境的影响 单元测试通常会被放到继续集成中,每次代码有check in时单元测试都会被执行 如果对外部环境(网络,服务,中间件等)有依赖,容易导致集成机制不可用为了不受外界环境的影响,要求设计代码时就把SUT的依赖改成注入在测试时用spring这样的DI框架注入一个本地(内存)实现或者Mock实现对于单元测试,要保障测试粒度足够小,有助于精确定位问题,单元测试粒度至多是类级别,通常是办法级别的 只有测试粒度小能力在出错时尽快定位到出错地位单元测试不负责查看跨类或者跨零碎的交互逻辑,那是集成测试的畛域外围业务,外围利用,外围模块的增量代码确保单元测试通过 新增代码及时补充单元测试如果新增代码影响了原有代码,确保及时修改单元测试代码必须写在如下工程目录中 :src/test/java, 不容许写在业务代码目录下 源码构建会跳过此目录,而单元测试框架默认扫描此目录单元测试的根本指标: 语句覆盖率达到70%外围模块语句覆盖率和分支覆盖率都要达到100%在工程规约的利用分层中提到的DAO层 ,Manager层,可重用度高的Service, 都应该进行单元测试编写单元测试代码要恪守BCDE规定,以确保被测试模块交付品质: B: Border ,边界值测试, 包含循环边界,非凡取值,非凡工夫点,数据程序等C: Correct ,正确的输出,并失去预期的后果D: Design ,与设计文档相结合, 来编写单元测试E: Error ,强制错误信息输出, 比方非法数据,异样流程,非业务容许输出,并失去预期的后果对于数据库的查问,更新,删除等操作: 不能够假如数据库里的数据是存在的不能够间接操作数据库将数据插入进去必须应用程序插入或者导入数据的形式来筹备数据和数据库相干的单元测试,能够设定主动回滚机制,不给数据库造成脏数据,或者对单元测试产生的数据有明确的前后缀标识 比方在RDC外部的单元测试中,应用RDC_UNIT_TEST_的前缀标识数据对于不可测的代码要做必要的重构,使代码变得可测,防止为了达到测试要求而书写不标准的测试代码在设计评审阶段,开发人员须要和测试人员一起确定单元测试范畴,单元测试最好笼罩所有测试用例单元测试作为一种品质保障伎俩,不要在我的项目公布后补充单元测试用例,须要在我的项目提测前实现单元测试为了更不便地进行单元测试,业务代码须要防止以下状况: 构造方法中做的事件过多存在过多的全局变量和静态方法存在过多的内部依赖存在过多的条件语句: 多层条件语句倡议应用卫语句,策略模式,状态模式重构不要对单元测试存在误会: 认为单元测试是测试的事件认为单元测试代码是多余的.零碎整体性能与各个单元部件的测试失常与否是强相干的认为单元测试代码不须要保护.这样会导致一段时间过后,单元测试简直处于废除的状态认为单元测试与线上故障没有辩证关系.好的单元测试能最大限度地躲避线上故障

June 30, 2021 · 1 min · jiezi

关于单元测试:前端面试每日-31-第800天

明天的知识点 (2021.06.24) —— 第800天 (我也要出题)[html] 应用HTML5实现窗户玻璃雨滴的真切成果[css] 应用CSS3实现响应式win8 metro格调的页面[js] js如何做单元测试?步骤是什么?[软技能] 你有做过基于地图的利用吗?《论语》,曾子曰:“吾日三省吾身”(我每天屡次检查本人)。前端面试每日3+1题,以面试题来驱动学习,每天提高一点!让致力成为一种习惯,让奋斗成为一种享受!置信 保持 的力量!!! 欢送在 Issues 和敌人们一起探讨学习! 我的项目地址:前端面试每日3+1【举荐】欢送跟 jsliang 一起折腾前端,零碎整顿前端常识,目前正在折腾 LeetCode,打算买通算法与数据结构的任督二脉。GitHub 地址 微信公众号欢送大家前来探讨,如果感觉对你的学习有肯定的帮忙,欢送点个Star, 同时欢送微信扫码关注 前端剑解 公众号,并退出 “前端学习每日3+1” 微信群互相交换(点击公众号的菜单:交换)。 学习不打烊,充电加油只为遇到更好的本人,365天无节假日,每天早上5点纯手工公布面试题(死磕本人,愉悦大家)。心愿大家在这虚夸的前端圈里,放弃沉着,保持每天花20分钟来学习与思考。在这变幻无穷,类库层出不穷的前端,倡议大家不要等到找工作时,才狂刷题,提倡每日学习!(不忘初心,html、css、javascript才是基石!)欢送大家到Issues交换,激励PR,感激Star,大家有啥好的倡议能够加我微信一起交换探讨! 心愿大家每日去学习与思考,这才达到来这里的目标!!!(不要为了谁而来,要为本人而来!)交换探讨欢送大家前来探讨,如果感觉对你的学习有肯定的帮忙,欢送点个[Star]

June 24, 2021 · 1 min · jiezi

关于单元测试:单元测试PowerMock

前言PowerMock是一个单元测试框架,能够模仿静态方法,公有办法和final办法等来简化单元测试的编写。本篇文章将联合简略例子对PowerMock的罕用办法进行阐明。 筹备工作一. 注解增加与应用场景在应用PowerMock时须要针对不同场景增加对应注解,次要是@RunWith和@PrepareForTest注解。注解增加和场景对应如下所示。 场景注解模仿final办法@PrepareForTest,@RunWith模仿静态方法@PrepareForTest,@RunWith模仿公有办法@PrepareForTest应用whenNew@PrepareForTest,@RunWith二. 应用PowerMock须要增加的依赖须要引入的依赖如下所示。 <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>2.23.0</version> <scope>test</scope></dependency><dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-mockito2</artifactId> <version>2.0.2</version> <scope>test</scope></dependency><dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <version>2.0.2</version> <scope>test</scope></dependency>引入mockito-core是为了提供Mockito性能,次要应用到org.mockito.ArgumentMatchers参数占位符,局部状况须要应用到org.mockito.BDDMockito。引入powermock-api-mockito2和powermock-module-junit4是为了提供PowerMock性能,其中powermock-module-junit4中还引入了hamcrest-core,次要是应用其提供的org.hamcrest.MatcherAssert.assertThat和org.hamcrest.Matchers.is进行断言判断。在引入依赖时,须要留神核查Mockito和PowerMock的版本对应关系,否则会报java.lang.ClassNotFoundException: org.mockito.exceptions.Reporter谬误。版本对应关系能够去PowerMock官网进行查问:PowerMock官网,通常状况下,如果引入的mockito-core版本为2.x,则PowerMock的api须要应用powermock-api-mockito2。 注释一. mock public办法public class Mock { public boolean isTrue_1() { return true; }}public class PowerMockTest { @Test public void mockPublic() { Mock mock = PowerMockito.mock(Mock.class); PowerMockito.when(mock.isTrue_1()).thenReturn(false); assertThat(mock.isTrue_1(), is(false)); }}mock public办法时须要应用PowerMockito.mock(办法所在类.class)获取mock进去的对象,这里称之为mock实例,mock实例的办法均为假办法,不对mock实例进行任何操作的状况下,调用mock实例的办法会返回(如果有返回值的话)返回值类型的默认值(零值,比方String返回null,Integer返回0)。如果想要调用mock实例的办法时使其执行实在办法,那么打桩时须要应用thenCallRealMethod(),如下所示。 public class Mock { public boolean isTrue_1() { return true; }}public class PowerMockTest { @Test public void mockPublicThenCallRealMethod() { Mock mock = PowerMockito.mock(Mock.class); PowerMockito.when(mock.isTrue_1()).thenCallRealMethod(); assertThat(mock.isTrue_1(), is(true)); }}同时能够应用whenNew()来实现在程序中new一个对象时失去一个mock实例,如下所示。 ...

June 8, 2021 · 4 min · jiezi

关于云原生:云原生应用的测试指南-IDCF

译者注:这是国外一篇介绍如何测试云原生利用的文章,云原生利用通常是基于微服务架构格调的分布式应用程序,传统的测试方法和技术已不能满足产品交付的品质要求,只有联合古代测试技术,既增强研发阶段的测试,又引入产品公布后的线上测试,能力有效应对云原生利用在性能、性能、平安、可靠性方面的挑战。这些新的技术包含契约测试,灰度公布,混沌工程,在线监控和日志剖析等。一、应用程序的“云原生化”越来越多的公司正将本地部署的利用迁徙(或打算迁徙)到云上,它们的指标是设计、架构并构建的应用程序能够很容易地扩大并部署到云上,并且能够充分利用云平台(如AWS、Azure,或GCP)提供的计算模式。 “云原生化”和开发云原生利用指的是设计、架构并构建的分布式软件应用可能齐全利用云服务商提供的PaaS(Platform-as-a-Service,平台即服务)和IaaS(Infrastructure-as-a-Server,基础设施即服务)的服务模式。这些利用通常是作为一组微服务(基于微服务架构格调)构建的。 这些松耦合的微服务运行在一个由私有云、公有云和混合云提供的动静环境中的容器化和动静编排平台上(基于Kubernets、Docker等技术)。促使企业进行利用的“云原生化”只管有不同方面的起因,但其中包含一些最重要的驱动因素,如:缩短重要的软件应用的宕机工夫、减少利用的弹性能力、依据业务须要动静扩容或缩容,进步利用开发速度、疾速响应用户需要、更专一于翻新从而减少更多的业务价值。 二、云原生利用的测试方法测试总是帮忙咱们更深刻地开掘问题,并向用户交付高质量的产品。软件测试在帮忙咱们收集产品的状态、可维护性、性能、健壮性和可靠性等大量有用信息方面施展了重要作用。通过对这些信息进行剖析,企业的决策者们能够更有信念地进行产品公布的决策。 相比其它软件应用(例如单体架构的利用)的传统测试方法,云原生利用的测试要更简单。这是因为云原生利用是动静、分布式构建的一组微服务(每个微服务能够独立公布),公布速度更快(通常采纳CI/CD和DevOps实际),而且存在难以预测和跟踪的故障模式。 这就要求咱们适应这些变动,从新扫视传统的测试技术,并采纳新的、古代的测试方法来预感、检测、响应、调试、剖析和报告问题。 这些测试技术将在许多方面帮忙咱们找到并揭示大量信息,这将有助于进步云原生利用的整体品质。对于这类利用,软件测试已成为软件开发生命周期的所有阶段中不可分割的一部分,并且促使业务剖析人员、开发人员、测试人员、架构师和软件设计人员等进行更多沟通和交换:提出疑难,共享信息,探讨并评估问题和危险。当初就让咱们一起看看针对云原生利用的无效的测试技术。 1)单元测试,集成测试,端到端的测试通过在微服务架构的云原生利用中测试单个服务组件中的最小可测试单元,能够在开发晚期阶段发现许多缺点。疾速、牢靠、自动化的单元测试不仅能确定服务组件的独立单元/模块是否能失常工作,也将有助于开发人员察看单元/模块状态的变动,查看对象之间的交互,以及对象之间的依赖,对于组件的状态取得疾速反馈,或者因为代码变更导致了回归缺点等。这些测试让软件代码更具备可测试性并有利于代码的重构。 软件应用的服务组件在集成之后,由继续集成服务器触发的集成测试将有助于测试各个服务组件之间或服务组件与内部服务、零碎、数据存储之间的通信门路和交互。只管测试所有的集成点是艰难的,但团队必须采纳基于危险的测试方法,依据制订的指标、范畴和优先级执行测试。 对于云原生利用来说,执行端到端测试是比拟艰难的,因为这波及到微服务架构中每个独立开发的局部,测试进度会比拟迟缓,而且有时候会十分不稳固,不得不思考到服务组件之间的异步调用和环境因素的影响。这都造成端到端的测试在测试筹备、运行和保护方面的老本较高。尽管如此,研发团队依然须要运行其中的一些端到端的测试,只管不那么频繁,但须要笼罩重要的业务门路,并验证残缺的利用是否满足业务需要。 2)契约测试既然会波及单个独立的微服务,研发团队也须要对微服务执行契约测试。微服务体系架构由“生产者”服务组件和“消费者”服务组件组成。当消费者组件试图与生产者组件联合并应用它的输入时,一个“服务契约”(由预期的输出和输入组成)就在它们之间造成。 由这些契约测试组成的自动化测试套件能够集成到流水线中,运行这些测试来验证生产者和消费者组件中的任何更改是否合乎二者之间的服务契约。开发和运行契约测试是测试云原生利用的一项重要内容。 3)非功能测试对于云原生利用来说,功能测试十分重要,能够验证产品是否满足业务需要。然而,当产品公布到生产环境中,功能测试可能提供产品将以预期的形式响应的信念吗?当忽然呈现服务器解体、服务组件宕机或某些依赖服务不可用时,服务是否可能平安降级?产品上线后是否足够平安?该产品是否应酬突发的大量用户申请? 非功能测试对于云原生利用十分重要。对于上述问题,任何缺点或者偏离预期行为的状况都要求咱们以起码的工作量和步骤尽快发现、剖析并修复问题,以防止这些问题再次发生。 为了确保这些问题产生的机率或影响很小,咱们须要借助有用的工具(许多工具是云提供商本人提供的)测试产品的性能(如提早、负载平衡的影响、缓存、产品性能中的危险因素、基于性能指标来比照和提供反馈后果的基准测试等)、可用性、负载(例如在靠近实在负载条件下对产品吞吐量的影响)和安全性(动态和动静),并事后解决任何潜在的危险。 4)混沌工程和生效模式测试说到品质工程,咱们大多数人都晓得像“FMEA”(生效模式和影响剖析)技术,它能够帮忙咱们辨认产品中的潜在生效模式及其起因和结果。对于单体利用,大多数潜在的故障模式是已知的,能够辨认的,因而能够在代码构造中解决。即便不解决,当缺点产生时也可能疾速修复。 然而对于微服务来说,产品在生产环境中失败的形式是难以计数、不可预测的,因为波及到大量的复杂性。在这些状况下,“混沌工程”会很有帮忙。它是一种辨认在生产环境中产品生效的办法,以建设对系统应答意外或未知操作能力的信念。 “混沌工程”和FMEA一起,通过注入可控的故障,帮忙咱们取得一个可靠性和弹性能力更高的产品,让咱们可能检测和剖析这些故障,从而预知产品在哪些方面会出故障。这将帮忙咱们调整现有的流程,以避免故障级联的结果,并提前打算如何缩短MTTR(Mean Time to Recovery/Restore,故障均匀复原工夫)。 5)可察看性、在线监控和日志剖析作为软件工程师,对云原生利用咱们既要在上线前进行测试也要在上线后进行测试。如果操作切当,线上测试能够为咱们提供许多有价值的信息,为打算下一个版本的弹性、可伸缩性和灵活性提供重要反馈信息。但必须记住,线上测试的设置和执行很简单,在执行这些测试时必须十分小心,并充分考虑到,如果线上测试没有正确和平安的执行,对业务和用户带来什么样的影响。 “可察看性”是帮忙咱们更好地了解产品中软件行为的办法之一,是指通过观察产品的输入来理解产品外部状态的办法。咱们能够应用一些监控技术和工具收集、存储、保护和查问利用的状态、行为,以及服务之间交互相干的信息。这些日志和指标能够被进一步剖析来获取有价值的发现,或者疾速评估和剖析缺点。一些云服务提供商会提供开箱即用的性能和工具帮忙咱们实现监控、信息收集和剖析。 三、论断咱们必须明确,无论打算和执行多少功能测试和非功能测试,无论咱们如何努力提高这些云原生利用的品质,最终用户依然会面临问题。咱们的指标是缩小意外事件的危险,疾速剖析和修复故障,从既往事件中学习并将这些常识用于下一个版本。 在生产环境中发现缺点的老本是十分高的,咱们应该在软件的开发生命周期中尽早发现缺点。在生产环境中,咱们能够利用金丝雀部署(把所有性能推送给局部用户),暗启动(把新性能/次要性能推送给局部用户),智能性能切换/标记/位/翻转器(容许特定性能的利用被激活或停用)等技术在生产环境中逐步裸露缺点。 但咱们也必须记住,因为各种限度因素,包含估算、团队承接能力、时间表、上市工夫、大量相互依赖/独立的服务、环境的可用性等,通过已知的测试策略做详尽的测试是不可能的。因而,团队须要采取基于危险的测试方法,也必须意识到和缺点无关的各种类型的老本,比方检测老本,剖析调试老本,机会成本,修复老本,验证老本和保护老本。 思考到所有本文中探讨的因素,能够必定的是,只管测试云原生利用是艰难和具备挑战性的,但咱们能够让新的测试方联合本身的专业知识、不同的测试技术和策略,向用户交付高质量的产品。 起源:软件品质报道 作者:Sumon Dey 4月每周四晚8点,【冬哥有话说】DevOps之庖丁解牛,拆解DevOps的工具及具体实战。公众号留言“解牛”可获取地址 0401《数据库继续交付流水线分享与演示(Azure DevOps+Flyway)》0408《继续交付中的版本治理与基于Azure DevOps扩大框架的插件开发》0415《微服务,多团队合作中的API测试怎么做 - Pact契约测试》0422《BoatHouse端到端流水线展现》

April 15, 2021 · 1 min · jiezi

关于react.js:那些年错过的React组件单元测试下

写在后面上篇文章咱们曾经理解了前端单元测试的背景和根底的jestapi,本篇文章我会先介绍一下Enzyme,而后联合我的项目中的一个实在组件,来为它编写测试用例。 Enzyme上一篇中咱们其实曾经简略介绍了enzyme,但这远远不够,在本篇的组件测试用例编写中,咱们有很多中央要用到它,因而这里专门来阐明一下。 Enzyme是由Airbnb开源的一个React的JavaScript测试工具,使React组件的输入更加容易。Enzyme的API和jQuery操作DOM一样灵便易用,因为它应用的是cheerio库来解析虚构DOM,而cheerio的指标则是做服务器端的jQuery。Enzyme兼容大多数断言库和测试框架,如chai、mocha、jasmine等。 对于装置和配置,上一大节曾经有过阐明,这里就不赘述了罕用函数enzyme中有几个比拟外围的函数,如下: simulate(event, mock):用来模仿事件触发,event为事件名称,mock为一个event object;instance():返回测试组件的实例;find(selector):依据选择器查找节点,selector能够是CSS中的选择器,也能够是组件的构造函数,以及组件的display name等;at(index):返回一个渲染过的对象;text():返回以后组件的文本内容;html(): 返回以后组件的HTML代码模式;props():返回根组件的所有属性;prop(key):返回根组件的指定属性;state():返回根组件的状态;setState(nextState):设置根组件的状态;setProps(nextProps):设置根组件的属性;渲染形式enzyme 反对三种形式的渲染: shallow:浅渲染,是对官网的Shallow Renderer的封装。将组件渲染成虚构DOM对象,只会渲染第一层,子组件将不会被渲染进去,因此效率十分高。不须要 DOM 环境, 并能够应用jQuery的形式拜访组件的信息;render:动态渲染,它将React组件渲染成动态的HTML字符串,而后应用Cheerio这个库解析这段字符串,并返回一个Cheerio的实例对象,能够用来剖析组件的html构造;mount:齐全渲染,它将组件渲染加载成一个实在的DOM节点,用来测试DOM API的交互和组件的生命周期,用到了jsdom来模仿浏览器环境。三种办法中,shallow和mount因为返回的是DOM对象,能够用simulate进行交互模仿,而render办法不能够。个别shallow办法就能够满足需要,如果须要对子组件进行判断,须要应用render,如果须要测试组件的生命周期,须要应用mount办法。 渲染形式局部参考的这篇文章 “踩坑之路”开启组件代码首先,来看下咱们须要对其进行测试的组件局部的代码: ⚠️ 因为牵扯到外部代码,所以很多中央都打码了。重在演示针对不同类型的测试用例的编写import { SearchOutlined } from "@ant-design/icons"import { Button, Col, DatePicker, Input, message, Modal, Row, Select, Table,} from "antd"import { connect } from "dva"import { Link, routerRedux } from "dva/router"import moment from "moment"import PropTypes from "prop-types"import React from "react"const { Option } = Selectconst { RangePicker } = DatePickerconst { confirm } = Modalexport class MarketRuleManage extends React.Component { constructor(props) { super(props) this.state = { productID: "", } } componentDidMount() { // console.log("componentDidMount生命周期") } getTableColumns = (columns) => { return [ ...columns, { key: "operation", title: "操作", dataIndex: "operation", render: (_text, record, _index) => { return ( <React.Fragment> <Button type="primary" size="small" style={{ marginRight: "5px" }} onClick={() => this.handleRuleEdit(record)} > 编辑 </Button> <Button type="danger" size="small" onClick={() => this.handleRuleDel(record)} > 删除 </Button> </React.Fragment> ) }, }, ] } handleSearch = () => { console.log("点击查问") const { pagination } = this.props pagination.current = 1 this.handleTableChange(pagination) } render() { // console.log("props11111", this.props) const { pagination, productList, columns, match } = this.props const { selectedRowKeys } = this.state const rowSelection = { selectedRowKeys, onChange: this.onSelectChange, } const hasSelected = selectedRowKeys.length > 0 return ( <div className="content-box marketRule-container"> <h2>XX录入零碎</h2> <Row> <Col className="tool-bar"> <div className="filter-span"> <label>产品ID</label> <Input data-test="marketingRuleID" style={{ width: 120, marginRight: "20px", marginLeft: "10px" }} placeholder="请输出产品ID" maxLength={25} onChange={this.handlemarketingRuleIDChange} ></Input> <Button type="primary" icon={<SearchOutlined />} style={{ marginRight: "15px" }} onClick={() => this.handleSearch()} data-test="handleSearch" > 查问 </Button> </div> </Col> </Row> <Row> <Col> <Table tableLayout="fixed" bordered="true" rowKey={(record) => `${record.ruleid}`} style={{ marginTop: "20px" }} pagination={{ ...pagination, }} columns={this.getTableColumns(columns)} dataSource={productList} rowSelection={rowSelection} onChange={this.handleTableChange} ></Table> </Col> </Row> </div> ) }MarketRuleManage.prototypes = { columns: PropTypes.array,}MarketRuleManage.defaultProps = { columns: [ { key: "xxx", title: "产品ID", dataIndex: "xxx", width: "10%", align: "center", }, { key: "xxx", title: "产品名称", dataIndex: "xxx", align: "center", }, { key: "xxx", title: "库存", dataIndex: "xxx", align: "center", // width: "12%" }, { key: "xxx", title: "流动有效期开始", dataIndex: "xxx", // width: "20%", align: "center", render: (text) => { return text ? moment(text).format("YYYY-MM-DD HH:mm:ss") : null }, }, { key: "xxx", title: "流动有效期完结", dataIndex: "xxx", // width: "20%", align: "center", render: (text) => { return text ? moment(text).format("YYYY-MM-DD HH:mm:ss") : null }, }, ],}const mapStateToProps = ({ marketRuleManage }) => ({ pagination: marketRuleManage.pagination, productList: marketRuleManage.productList, productDetail: marketRuleManage.productDetail,})const mapDispatchToProps = (dispatch) => ({ queryMarketRules: (data) => dispatch({ type: "marketRuleManage/queryRules", payload: data }), editMarketRule: (data) => dispatch({ type: "marketRuleManage/editMarketRule", payload: data }), delMarketRule: (data, cb) => dispatch({ type: "marketRuleManage/delMarketRule", payload: data, cb }), deleteByRuleId: (data, cb) => dispatch({ type: "marketRuleManage/deleteByRuleId", payload: data, cb }),})export default connect(mapStateToProps, mapDispatchToProps)(MarketRuleManage)简略介绍一下组件的性能:这是一个被connect包裹的高阶组件,页面展现如下: ...

April 1, 2021 · 6 min · jiezi

关于测试驱动开发:单元测试的一些分享

背景最近在给一个客户做技术咨询,而后发现了客户对于单元测试的一个有意思的景象。分享进去,大家一起学习探讨一下。 现状剖析这里以java后端我的项目例,发现客户写的测试长上面的样子。(代码曾经脱敏解决过。) @Autowired private SampleJob handler; @Test public void testStart() throws Exception { SampleParamVo paramVo = new SampleParamVo(); paramVo.setStartTime("2021-03-18"); paramVo.setEndTime("2021-03-18"); handler.execute(paramVo); } @Autowired private SampleHandler handler; @Test public void testHandler() { handler.doHandler(new DateTime("2021-11-26"), null); } 那么这样的测试代码有什么问题呢? 他人看不懂这个测试是在做什么。首先测试的办法名没有任何意义,其次测试代码也只是调用了某个函数。无奈运行。这类测试代码运行往往须要启动其余服务或者须要一些非凡的设置。无奈运行就意味着它不能成为CI跑测试的一部分。没有断言。没有断言就无奈晓得测试的代码的正确性。应用了@Autowired这样的代码,减少了测试的耦合以及编写老本。和客户深聊了之后发现,原来客户不同的人对单元测试的了解也不一样。 写这个代码的开发人员说,“这些代码是在开发实现之后做一些自测的辅助脚本。”有的开发人员说,“咱们是微服务,单元测试须要调用其余服务,写起来很麻烦,而且如果其余服务不可用时,测试也跑不过。”测试人员说:“单元测试咱们有的,我每天都在写测试用例,到单元测试的时候我就会把我的用例全副过一遍。”所以咱们能够发现,有的开发人员口中的单元测试其实应该属于集成测试或者E2E测试,有的开发人员齐全没有写过单元测试,而测试人员了解单元测试是本人手动测试的时候用的测试用例。 那咱们就先来说说什么是单元测试。 什么是单元测试?单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。通常在java的世界外面,单元测试就是指对一个public的办法编写检查和验证的代码。 为什么要写单元测试?写单元测试次要有两大目标: 验证性能实现。爱护已有性能不被毁坏。当咱们写完一个办法,咱们如何晓得本人写的办法是按冀望工作的呢?这个时候就能够增加单元测试来验证咱们的代码是按冀望工作的。即当咱们给定指定的输出,咱们取得冀望的输入,则咱们说这个性能是合乎冀望的。 其次,代码不是写了就永远不变的,当需要变更时,新增需要时,修复bug时,都会批改代码,而单元测试则能爱护咱们已有的性能不被毁坏。爱护已有性能不会被本人毁坏,被新人毁坏,被新性能毁坏。 如何写单元测试?上面是一个单元测试的例子 @Test public void should_return_fizz_given_input_can_be_divided_by_3() { FizzBuzz fizzBuzz = new FizzBuzz(); // Given String actual = fizzBuzz.sayIt(6); // When Assertions.assertEquals("Fizz", actual); // Then } 一个规范的单元测试蕴含以下几个局部: ...

March 22, 2021 · 1 min · jiezi

关于单元测试:完整单元测试解决方案Telerik-正式支持NET-5

Telerik JustMock是一个灵便、功能齐全的.NET mocking框架。Telerik JustMock可能简化单元测试,当初测试简单的场景比以前更加容易了。同时JustMock还与Visual Studio以及其余工具集成,JustMock与VS 2017,2015和2013以及其余一些工具配合应用。 最新的Telerik JustMock Service Pack版本反对.NET 5的正式版本,可帮忙您利用性能、性能等方面的即时改良。.NET 5在.NET Conf 2020上正式公布,其中包含许多改良。在R3 SP2 2020版本中,Telerik JustMock正式反对.NET 5。 .NET 5中应如何应用Telerik JustMock,是否有任何更改? 通常当须要将应用程序迁徙到较新版本的第三方库时,会因解决很多重大更改破费许多工夫。对于高于.NET Core 2.0和.NET 5的所有版本,Telerik.JustMock.dll放弃雷同,您能够在JustMockInstallationPath / Libraries / netcoreapp2.0 /中找到它。 当您应用JustMock在测试项目中迁徙到.NET 5时,应增加对System.Security.Permissions版本5.0的援用。 如果您应用Telerik JustMock NuGet软件包,则该软件包将主动解决。 异步办法中的部分函数模仿 mocking位于异步办法中的本地函数已损坏,对于R3 SP 2 2020版本,此问题已修复。 援用Ninject.Extensions.Conventions Nuget包时引发异样 JustMock的Ninject.Extensions.Conventions NuGet包导致引发了异样,R3 SP2 2020版本已解决此问题。

December 10, 2020 · 1 min · jiezi

关于单元测试:golang协程

一、过程和线程过程就是程序在操作系统中的一次执行过程,是零碎进行资源分配和调度的根本单位线程是过程的一个执行实例,是程序执行的最小单元,它是比过程更小的能独立运行的根本单位一个过程能够创立和销毁多个线程,同一个过程中的多个线程能够并发执行一个程序至多有一个过程,一个过程至多有一个线程二、并发和并行多线程程序在单核上运行,就是并发多线程程序在多核上运行,就是并行 并发 :在一个cpu中,比方10个线程,每个线程执行10毫秒(进行轮询操作),从人的角度看,如同10个线程都在运行,但从宏观上看,某一时间点看,其实只有一个线程在执行,这就是并发。 并行 :在多个cpu中(如10个),比方10个线程,每个线程执行10毫秒(各自在不同cpu上执行),从人的角度看,10个线程都在运行,但从宏观上看,某一时间点看,也同时10个线程在执行,这就是并行。 三、go协程和主线程go主线程是一个物理线程,间接作用在CPU上,是重量级的,十分耗cpu资源,一个go线程上能够起多个协程。协程是主线程开启的,轻量级的线程,逻辑态的,对资源耗费小go协程特点: 有独立的栈空间共享程序的堆空间调度由用户管制协程是轻量级的线程四、channel(管道)channel实质是一个数据结构-队列数据是先进先出线程平安,多goroutine拜访时,不须要加锁,就是说channel自身是线程平安的channel是由类型的,一个string的channel只能寄存string类型的数据遍历时,如果channel没有敞开,则会呈现deadlock谬误,如果channel曾经敞开,则会失常遍历数据,遍历结束后,就会退出遍历 细节:管道可申明为只读或只写 var cha1 chan int // 可读可写var cha2 chan<- int // 只写var cha2 <-chan int // 只读应用select能够解决从管道取数据的阻塞问题 // 理论开发中,不好确定什么时候敞开该管道// 可用select解决for { select { // 如果管道始终没敞开,不会始终阻塞而deadlock // 会主动到下一个case匹配 case v := <-intChan: fmt.Printf("读取数据") case v := <-stringChan: fmt.Printf("读取数据") default: fmt.Printf("都取不到") }}goroutine中应用recover,解决协程中呈现的panic,导致程序解体

December 9, 2020 · 1 min · jiezi