生鲜电商网站建设与管理,深圳企业网站建设公司哪家好,企业工商登记信息查询系统,网站建设需要注意些什么测试驱动开发 测试前移单元测试中单元的故事 在本文的上半部分 #xff0c;您可能会看到一些不好但很受欢迎的测试示例。 但是我不是一个专业的批评家#xff08;也被称为“巨魔”或“仇恨者”#xff09;#xff0c;没有任何建设性的话就抱怨。 多年的TDD教给我的不仅仅是… 测试驱动开发 测试前移 单元测试中单元的故事 在本文的上半部分 您可能会看到一些不好但很受欢迎的测试示例。 但是我不是一个专业的批评家也被称为“巨魔”或“仇恨者”没有任何建设性的话就抱怨。 多年的TDD教给我的不仅仅是事情会变得多么糟糕。 有许多简单但有效的技巧可以使您的测试生活变得更加轻松。 想象一下您有一家小公司中一间小型会议室的预订系统。 由于某些奇怪的原因它必须处理离线预订。 人们将他们的预订请求发布到某个前端每周一次您会收到一个文本文件其中包含公司的工作时间以及所有的预订在当天多长时间由谁在什么时间点提交订购。 您的系统应根据一些业务规则先到先得仅在办公室工作时间内提供此类服务为房间生成日历。 作为分析的一部分我们提供了明确定义的输入数据和预期结果并带有示例。 确实TDD的情况很好。 可悲的是在现实生活中从来没有发生过这样的事情。 我们的示例测试数据如下所示 class TestData {static final String INPUT_FIRST_LINE 0900 1730\n;static final String FIRST_BOOKING 2011-03-17 10:17:06 EMP001\n 2011-03-21 09:00 2\n;static final String SECOND_BOOKING 2011-03-16 12:34:56 EMP002\n 2011-03-21 09:00 2\n;static final String THIRD_BOOKING 2011-03-16 09:28:23 EMP003\n 2011-03-22 14:00 2\n;static final String FOURTH_BOOKING 2011-03-17 10:17:06 EMP004\n 2011-03-22 16:00 1\n;static final String FIFTH_BOOKING 2011-03-15 17:29:12 EMP005\n 2011-03-21 16:00 3;static final String INPUT_BOOKING_LINES FIRST_BOOKING SECOND_BOOKING THIRD_BOOKING FOURTH_BOOKING FIFTH_BOOKING;static final String CORRECT_INPUT INPUT_FIRST_LINE INPUT_BOOKING_LINES;static final String CORRECT_OUTPUT 2011-03-21\n 09:00 11:00 EMP002\n 2011-03-22\n 14:00 16:00 EMP003\n 16:00 17:00 EMP004\n ;
} 现在我们从一个积极的测试开始 BookingCalendarGenerator bookingCalendarGenerator new BookingCalendarGenerator();Test
public void shouldPrepareBookingCalendar() {//whenString calendar bookingCalendarGenerator.generate(TestData.CORRECT_INPUT);//thenassertEquals(TestData.CORRECT_OUTPUT, calendar);
} 看来我们已经使用“生成”方法设计了BookingCalendarGenerator。 很公平。 让我们添加更多测试。 测试业务规则。 我们得到这样的东西 Testpublic void noPartOfMeetingMayFallOutsideOfficeHours() {//givenString tooEarlyBooking 2011-03-16 12:34:56 EMP002\n 2011-03-21 06:00 2\n;String tooLateBooking 2011-03-16 12:34:56 EMP002\n 2011-03-21 20:00 2\n;//whenString calendar bookingCalendarGenerator.generate(TestData.INPUT_FIRST_LINE tooEarlyBooking tooLateBooking);//thenassertTrue(calendar.isEmpty());}Testpublic void meetingsMayNotOverlap() {//givenString firstMeeting 2011-03-10 12:34:56 EMP002\n 2011-03-21 16:00 1\n;String secondMeeting 2011-03-16 12:34:56 EMP002\n 2011-03-21 15:00 2\n;//whenString calendar bookingCalendarGenerator.generate(TestData.INPUT_FIRST_LINE firstMeeting secondMeeting);//thenassertEquals(2011-03-21\n 16:00 17:00 EMP002\n, calendar);}Testpublic void bookingsMustBeProcessedInSubmitOrder() {//givenString firstMeeting 2011-03-17 12:34:56 EMP002\n 2011-03-21 16:00 1\n;String secondMeeting 2011-03-16 12:34:56 EMP002\n 2011-03-21 15:00 2\n;//whenString calendar bookingCalendarGenerator.generate(TestData.INPUT_FIRST_LINE firstMeeting secondMeeting);//thenassertEquals(2011-03-21\n15:00 17:00 EMP002\n, calendar);}Testpublic void orderingOfBookingSubmissionShouldNotAffectOutcome() {//givenListString shuffledBookings newArrayList(TestData.FIRST_BOOKING, TestData.SECOND_BOOKING,TestData.THIRD_BOOKING, TestData.FOURTH_BOOKING, TestData.FIFTH_BOOKING);shuffle(shuffledBookings);String inputBookingLines Joiner.on(\n).join(shuffledBookings);//whenString calendar bookingCalendarGenerator.generate(TestData.INPUT_FIRST_LINE inputBookingLines);//thenassertEquals(TestData.CORRECT_OUTPUT, calendar);} 仅此而已。 但是如果我们得到一些垃圾作为输入怎么办。 还是如果我们得到一个空字符串 让我们为此设计 Test(expected IllegalArgumentException.class)public void rubbishInputDataShouldEndWithException() {//whenString calendar bookingCalendarGenerator.generate(rubbish);//then exception is thrown}Test(expected IllegalArgumentException.class)public void emptyInputDataShouldEndWithException() {//whenString calendar bookingCalendarGenerator.generate();//then exception is thrown} IllegalArgumentException很公平。 我们不需要再花哨的方式处理它。 我们已经完成了。 最后让我们在测试下编写该类BookingCalendarGenerator。 因此我们做到了。 结果表明对于一个方法来说整个过程有点大。 因此我们使用了“提取方法”模式的强大功能。 我们将代码片段分为不同的方法。 我们将可操作的方法和数据分组为类。 我们使用面向对象编程的功能使用单一职责原理使用组合准确地说是分解最后得到一个像这样的程序包 我们有一个公共类和几个包作用域类。 这些包范围类显然属于公共类。 为了清晰起见这是一个类图 那些不是愚蠢的数据对象。 这些是成熟的课程。 具有行为责任感和封装感。 这是我们测试驱动者可能想到的一件事我们没有针对这些类的测试。 我们只有公共班级。 不好对吧 没有测试一定是不好的。 很坏。 对 错误。 我们有测试。 我们启动了代码覆盖率工具然后看到100的方法和类。 95的线。 不错在下一篇文章中我将达到不确定性的5。 但是我们只有一个单元测试类。 这样好吗 好吧让我强调一下指出答案 这是一个UNIT测试。 有理由将其称为UNIT测试 该单元不必是一个单一的类。 该单元不必是单个包装。 由您决定单位。 这是一个通用名称因为您的理智和常识应该告诉您停止的地方。 所以我们有六个班级作为一个单元有什么大不了的 除了其他人之外是否有人要使用其中一个类别呢 他不会对此进行测试对吗 错误。 除了在测试中实际调用的那些类之外这些类都是包范围的。 这个包裹范围的事情告诉您“退后一步。 不要碰我我属于这个包裹。 不要试图单独使用我我是设计在这里”。 因此是的如果程序员将其中之一或将其公开他可能会知道所有保证都将失效。 写你自己的测试伙计。 我被问到是否有人要向其中一个类添加某些行为呢 他怎么会知道他没有破东西 好吧他将从测试开始对吗 是TDD对不对 如果需求有变化则将此变化编码为测试然后直到那时您才开始弄乱代码。 因此您是安全的。 我看到人们盲目地写每堂课的测试却没有思考这让我哭了。 我最近做了很多配对编程您知道我发现了什么吗 Java程序员通常不使用package-scope。 Java程序员通常不知道这种保护意味着对我来说我的所有后代和每个人都在同一软件包中。 没错受保护不仅仅是包范围更不是一点点。 因此如果Java程序员不知道包范围实际上是什么并且与Groovy相反这是默认值那么他们如何理解单元是什么 我能得到多高 现在有一个有趣的想法如果我们可以对一个包进行单个测试那么我们可以对一个包树进行单个测试。 你知道像这样 我们都知道Java中的软件包不是真正的树状包唯一具有目录结构的是按照非常古老的约定而且我们知道目录结构仅用于解决名称冲突问题尽管如此我们还是倾向于使用包就像name.after.the.dot有意义一样。 就像我们可以将一个包裹隐藏在另一个包裹中一样。 或与他们建立千层面的烤宽面条。 那么可以为一个树形树使用一个测试类吗 是的。 但是如果是这样到哪里结束 我们可以从包树一直到应用程序的入口点吗 这些……可能是集成测试或功能测试。 我们能做到吗 那会好吗 答案是可以。 在一个完美的世界中那会很好。 在我们那肮脏的悬挂在刀刃上的世界里这简直是疯了。 为什么 因为功能性的端到端测试很慢。 太慢了。 太慢了以至于您想将它们扔掉然后到某个地方而不必总是等待某些东西。 一个充满创造力不断反馈和闪电般快速安全的地方。 您将返回单元测试。 甚至还有更多原因。 一种是很难对应用程序的所有流程进行端到端测试。 您可能应该对所有主要流程都执行此操作但是对于错误连接不良以及所有可能在一处或另一处抛出的棘手逻辑部分呢 不有时候像这样设置集成测试环境会太困难了所以最终还是要用单元测试来测试它。 第二个原因是尽管功能测试并未在代码上浇注具体的内容但不会通过在测试用例中重复执行算法来抑制您的创造力但是它们也没有提供重构的安全性。 当您拥有一个具有单个公共类的程序包时很明显有人可以安全地做什么而他不能做什么。 当您将某些内容包含在库或插件中时它仍然很明显。 但是如果您有成千上万个公共类并且要实现一个新功能则可能要使用其中一些并且您想知道它们很好。 因此不在我们的世界中仅进行功能测试是没有意义的。 抱歉。 但是按类创建测试也没有意义。 出于某种原因它被称为UNIT测试。 用那个 祝您编程愉快别忘了分享 参考 测试驱动陷阱来自我们JCG合作伙伴 Jakub Nabrdalik的第2部分 在Solid Craft博客上。 翻译自: https://www.javacodegeeks.com/2012/09/test-driven-traps-part-2.html测试驱动开发 测试前移