微信推文图片间距有缝的代码

在大多数情况下,使用遗留代码可能很困难。 但是,当涉及到添加新功能,重构或维护您不熟悉的代码时,它可能会变得势不可挡。 如果您已经使用敏捷技术几年了,并且突然间您面对大量的代码并且就您所能看到的没有测试用例,这可能会特别困难。

那该怎么办呢? 简单的答案是创建单元测试。 但是,当您开始修改代码以打破依赖关系并启用可测试性时,这可能会给您带来更多麻烦。 您真正需要的是一种轻松的方法来评估表达式,查找值并确定当前正在执行的代码分支。

迈克尔·费瑟斯(Michael Feathers)在他的《有效处理旧版代码》一书中谈到了在旧版代码中查找接缝以促进测试。 他为接缝提供的定义是“一个地方,您无需修改​​即可在其中更改程序的行为”。 接缝的类型因语言而异,对于Java,他定义了两个相关的类别,即“链接接缝”-通过这种方式对类路径进行不同的排序,可以用不同的类来代替测试。 和“对象接缝”-使用子类或模拟实现而不是最初期望的类对构造函数或方法进行调用。 (有关更多信息,请参阅Michael Feathers撰写的“有效使用旧版代码”的第4章)。

我发现另一个有利的接缝是测井接缝。 使用此接缝,您可以轻松地在类周围创建不引人注意的单元测试,而无需编辑类逻辑并避免行为更改。

寻找接缝

当使用遗留代码或未考虑可测试性编写的代码时,上面未经测试的代码场景相当普遍。 示例包括大型方法和类,复杂的分支(通常是同一方法中的许多分支级别)以及在需要时直接在代码中实例化的对象。 在这些情况下(以及其他情况下),常规的测试工具包将无法正常工作。 一个优点是大多数代码都使用日志记录框架。

从测试的角度来看,日志记录代码的原始目的实际上并不重要。 无论是用于信息,调试还是跟踪,重要的是它提供遥测信息。 然后,可以将该遥测信息重新调整用途并在单元测试中使用,从而提供可靠地重构代码和添加新功能所需的安全网。

此外,将新的日志记录代码添加到现有代码中是无害的-不会影响现有功能或行为。 这意味着我们可以使用新的语句增强日志记录功能,以报告我们希望通过单元测试进行验证的信息(例如,表达式结果,对象实例值和分支信息)。 本文稍后将提供有关此步骤的更多详细信息。

测试用例

让我们以真正的测试方式首先开发单元测试。

但是,在开始之前,我们假设正在使用的旧代码已经用Java编写,并且还利用了Apache基金会的log4j日志框架。

测试用例的结构应遵循模拟测试范例。 这些步骤是:

  1. 为要测试的类所使用的对象创建一个模拟对象,以下称为“ ClassUnderTest”。
  2. 使用测试期望配置模拟对象
  3. 将模拟对象应用或注入到要测试的类中
  4. 运行被测试的方法
  5. 验证是否满足期望

在我们的例子中,我们用模拟对象代替了日志附加程序。 附加程序的工作方式(功能)与模拟对象相同-在运行测试之前,它会以期望的值填充; 它会在测试过程中捕获班级的呼叫; 最后,它将报告是否满足了预期以及是否进行了其他任何致电。

这是代码中的测试用例的结构:

// create the testing appender   TestLoggingAppender appender = new TestLoggingAppender();

  // add expectations   appender.addMessageToVerify("count=3");    appender.addMessageToVerify("finished processing");

   // add the appender to those associated with the class under test Logger log = LogManager.getLogger(ClassUnderTest.class); log.setLevel(Level.INFO); log.addAppender(appender);

  // do usual test setup and configure the class under test ClassUnderTest testme = new ClassUnderTest();    ...

 // run the method under test and verify the results   testme.myMethod();

  // ensure all the expectations are met    assertTrue( appender.verify() );

这里唯一的技巧是记住使用log4j时,有许多不同的日志记录级别。 在配置附加器以接收日志记录信息时,需要确保正确设置了日志记录级别。 在上面的代码中,“ log.setLevel(Level.INFO)”执行此功能。

测试记录器

最后,是时候开发测试日志附加程序了。 我们已经知道测试用例在附加器上调用的方法,因此这为我们提供了该类的初始结构。 这些方法是“ addMessageToVerify”和“ verify”。

这是第一种方法。

public void addMessageToVerify( String msg  ) {
called.put( msg, new State( msg, true, false ) );
}

调用时,会将新条目添加到由附加程序管理的消息列表中。 除了消息(用作更轻松查找的关键字)之外,还存储了状态对象。 状态对象是一个简单的对象,用于存储消息和两个标志-表示是否应该接收消息以及是否调用了该消息。

接下来是“验证”。 此方法使用已创建的内部消息列表。 返回值“ true”表示实际上所有预期被调用的消息都已存在,并且没有其他消息记录到附加程序。 否则,将返回“假”值。 看起来是这样的:

public boolean verify() {       boolean result = true;       for( Iterator i=called.keySet().iterator(); i.hasNext(); ) {         State state = (State)called.get(i.next());           if( (!state.shouldCall() && state.wasCalled()) ||                 (state.shouldCall() && !state.wasCalled()) )              result = false;      }     return result;    }

我们一直在谈论来自日志记录框架的消息,但是这是怎么发生的呢? 为了使我们的测试日志记录附加程序类接受日志记录消息,需要发生两件事。

首先是需要在测试案例中启用我们的测试日志附加程序。 使用代码“ LogManager.getLogger(ClassUnderTest.class)”启用日志记录,然后将我们的测试日志记录附加程序添加到附加程序列表中,以通过调用“ log.addAppender(appender)”接收日志记录消息。

其次,我们的测试日志记录附加程序需要扩展ConsoleAppender类。 这引入了一个新方法doAppend(LoggingEvent event),我们现在需要实现该方法:

public synchronized void doAppend(LoggingEvent loggingEvent) {       String msg = loggingEvent.getMessage().toString();       if( called.containsKey(msg) )         ((State)called.get(msg)).setCalled(true);     else          called.put( msg, new State( msg, false, true ) ); }

与addMessageToVerify方法类似,doAppend方法可处理内部消息列表。 如果正在记录的消息退出,则doAppend方法将更新状态标志以表示已被调用。 如果该消息不存在,则将新项添加到列表中,并设置标志以表示该消息不是预期的而是被调用的。

这样就完成了测试日志附加器类的实现。 完整的实现可以在清单1中看到。

利用缝

最后一步是将日志记录语句添加到ClassUnderTest。

在上面的测试案例中,我们有以下两行代码,它们验证是否发生了3次事情,并且处理完成了(大概没有例外)。

appender.addMessageToVerify("count=3");    appender.addMessageToVerify("finished processing");

上述预期测试的一种可能方法是:

public void myMethod() {

     // lots of code before the section we are interested in

     try {         FileReader file = new FileReader("transactions.log");          BufferedReader reader = new BufferedReader(file);

          String data;          int count = 0;           while( (data = reader.readLine())!=null ) {                process(data,count++);           }

           LOG.info("count="+count);         LOG.info("finished processing");        } catch( Exception e ) {          // error processing       }

       // more code afterwards   }

这是一个简单的示例,并不表示通常会在旧版代码中找到的内容。 要记住的重要一点是,为了在方法中测试此部分代码,只需添加两个日志记录语句。 无需修改任何功能,也无需执行重构。

在考虑要记录什么时,可以使用以下准则:

  • 可以记录静态文本以显示测试区域的开始和结束边界
  • 静态文本可以记录在分支或循环中以确定位置
  • 可以记录循环计数器的值以确定正在执行哪个循环迭代
  • 可以记录分支确定逻辑(确定您执行“ if”还是“ else”的逻辑)
  • 可以记录任何变量(类,方法或块作用域)的值
  • 可以评估任何表达式并记录结果

结论

借助日志记录框架,为遗留代码创建单元测试可以很容易。 您可以利用现有的日志记录,并且不加干扰地添加新的日志记录语句来评估表达式,查找值并确定当前正在执行代码的哪个分支。 现在,使用工具包中的测试日志记录附加程序,您可以放心地重构现有的旧代码并添加新功能,而不必担心破坏现有功能。

清单1-完整的TestLoggingAppender清单。

public class TestLoggingAppender extends ConsoleAppender {

    private Map called = new HashMap();

    public boolean verify() {        boolean result = true;        for( Iterator i=called.keySet().iterator(); i.hasNext(); ) {            State state = (State)called.get(i.next());            if( (!state.shouldCall() && state.wasCalled()) ||                    (state.shouldCall() && !state.wasCalled()) )                result = false;        }        return result;    }

    public void printResults() {        for( Iterator i=called.keySet().iterator(); i.hasNext(); ) {            State state = (State)called.get(i.next());            StringBuffer sb = new StringBuffer();            sb.append("Logging message '").append(state.getMsg()).append("' ");            sb.append("was ").append( state.shouldCall()?"expected ":"not expected ");            sb.append( state.wasCalled()?"and called":"and was not called");            System.out.println(sb.toString());        }    }

    public void addMessageToVerify( String msg  ) {        called.put( msg, new State( msg, true, false ) );    }

    public synchronized void doAppend(LoggingEvent loggingEvent) {        String msg = loggingEvent.getMessage().toString();        if( called.containsKey(msg) )            ((State)called.get(msg)).setCalled(true);        else            called.put( msg, new State( msg, false, true ) );    }

    class State {

        private String msg;        private boolean shouldCall;        private boolean called;

        public State( String msg, boolean shouldCall, boolean wasCalled ) {            this.msg = msg;            this.shouldCall = shouldCall;            this.called = wasCalled;        }

        public String getMsg() {            return msg;        }

        public boolean shouldCall() {            return shouldCall;        }

        public boolean wasCalled() {            return called;        }

        public void setCalled(boolean called) {            this.called = called;        }    }}

翻译自: https://www.infoq.com/articles/Utilizing-Logging/?topicPageSponsorship=c1246725-b0a7-43a6-9ef9-68102c8d48e1

微信推文图片间距有缝的代码

微信推文图片间距有缝的代码_使用记录接缝进行旧代码单元测试相关推荐

  1. 图片抓取_小小爬虫批量抓取微信推文里的图片

    哈喽,大家好,今天给大家分享一个特别特别小的爬虫案例! 爬取微信推文中的图片!!!! 有人说,这有啥用,,,,万一人家推文是放的是以图片的方式放的某个PPT的内容呢,你想把它弄下来,咋整,就是爬取啦. ...

  2. 爬虫取中间文本_小小爬虫批量抓取微信推文里的图片

    哈喽,大家好,今天给大家分享一个特别特别小的爬虫案例! 爬取微信推文中的图片!!!! 有人说,这有啥用,,,,万一人家推文是放的是以图片的方式放的某个PPT的内容呢,你想把它弄下来,咋整,就是爬取啦. ...

  3. bootstrap上传图片可实现查看上一张图片和下一张图片_如何实现像人民日报微信推文一样的的点亮效果?...

    如何实现向人民日报微信推文一样的的点亮效果? 有两种方法: 方法一:就是使用代码在编辑器进行编辑emmmmmm这个方法贼麻烦,需要调至HTML模式-- 方法二:在现有编辑器模板下利用SVG动画进行编辑 ...

  4. 英语四级计算机二级的微信推文,简明·实用 | 瞬间高大上的微信公众号推文制作...

    新媒体的盛行,微信逐渐变成了越来越主流的社交工具.微信公众号涉及服务号,企业号与订阅号.优秀的订阅号遍及各个领域,在越来越多人的关注之下成就了财富,荣耀与标杆.那么如何制作优秀的推文?如何制作漂亮的排 ...

  5. 如何优雅的将微信推文自动拷贝成CSDN博文?

    为什么要批量将微信推文转成CSDN博文? 在原来运维了三年的推文公众号TSINGHUAJOKING中, 总共包含了近一千篇原创推文.除了实时性很强的交互推文之外,还有大量的技术相关的推文.今天准备将原 ...

  6. 微信推文属性的关联分析 by Apriori算法

    本文通过Apriori算法来对某公司的微信推文属性的关联分析. 本文的目的 找出可让 ['阅读量超过1K'] 的因素,以便达到这些因素使微信推文阅读量提升. 本文的结论 若想让微信推文阅读量超过1K, ...

  7. centos7+TP5.1+selenium+chrome抓取搜狗微信推文

    centos7+TP5.1+selenium+chrome抓取搜狗微信推文 一.Composer 引入 "require": {"php-webdriver/webdri ...

  8. 微信推文无缝滚动是这样炼成的

    来源 | 般若无界 作者 | 舒欣 效果展示 前两天我收到策划妹子的请求,需要在微信公众号里面做一篇推文.这个推文和以往不同,需要有两张图片无缝拼接,并且下方图片可以滚动的效果. 这个效果目前用微信自 ...

  9. 微信推文中图片无法保存的解决方案

    文章目录 前言 一.付费内容在浏览器无法打开 二.利用浏览器开发者工具获取对应图片地址 三.webp转jpg 前言 付费看微信推送却发现里面的图片无法下载,记录一下我的解决方案. 一.付费内容在浏览器 ...

最新文章

  1. java高级特性2,Java高级特性 2
  2. 自己动手实现OpenGL之glViewPort(一)
  3. 取出list中属性_你是否用过List<T>和List<?>?
  4. 两列高度自适应(转)
  5. 手把手教你用Python爬虫煎蛋妹纸海量图片
  6. 迅为linux下串口,迅为IMX6ULL开发板Linux RS232/485驱动实验(上)
  7. 离异美女跟程序员相亲,结果自我介绍完就被秒删:三无送个儿
  8. python中for循环缩进_Python基础- 缩进,选择和循环
  9. c语言 inline函数的总结,C++中inline函数详解
  10. 谈谈我的跳槽感想,从日资企业到互联网的转变
  11. linux限制堆栈大小,进程超过RedHat Enterprise Linux 6的线程堆栈大小限制?
  12. [转载] python中svm的使用_Python中支持向量机SVM的使用方法详解
  13. 小芋头君的知乎 Live 直播-前端开发者成长之路
  14. php socket 执行,PHP异步调用socket实现代码
  15. 俄罗斯黑客太疯狂,破解赌场算法,全球捞钱……
  16. 发动机冒黑烟_汽车发动机冒黑烟的原因与处理方法
  17. 谷歌浏览器能打开网页微信_Chrome浏览器打开微信页面-Go语言中文社区
  18. 管理人员巡店用表-店长每日工作流程
  19. 剑指Offe 50:数组中重复的数字
  20. 简单的ps去掉图片上不想留的文字

热门文章

  1. 自动装箱中==的使用
  2. P1719 Let‘s play a game!
  3. 源码编译安装LAMP环境
  4. 毕业设计-基于微信小程序的校园一卡通设备报修系统
  5. Excel在统计分析中的应用—第八章—假设检验-总体比例的假设检验
  6. 如何用opencv绘制点
  7. 【只推荐一位】文能写诗聊妹,武可搬砖coding~
  8. 时隔一年半,我,一个卑微的前端菜鸡,又来写面经了
  9. 完美解决PADS_VX2画多边形铜箔提示自定义交叉多边形
  10. 工业互联网和边缘计算学习总结