• 安静的boy
    2020-01-08
    这节满满的干货👍👍👍
    
     22
  • 失火的夏天
    2020-01-08
    思考题1,该方法逻辑就是填充一个ID,基本都是内部实现的一个id生成器,可以不用重写。一定要重写也行,自己弄一个自增id实现就行了。
    思考题2,提供方法的类不要new,也就是我们常说的service类,这个是要依赖注入的。提供属性的类,比如vo,bo,entity这些就可以new。
    
     19
  • 辣么大
    2020-01-08
    参考争哥今天的代码写了例子中的测试(可运行):
    https://github.com/gdhucoder/Algorithms4/tree/master/designpattern/u29

    今天学习到了高级的单元测试方法:
    1、依赖外部单例:将单例封装
    2、未决行为:例时间、随机数。将未决行为重新封装,测试时mock,使用匿名类。

     关于讨论1:需要mock的情况id会写入数据库的话,测试后需要恢复现场。曾经遇到过这么一个情况,id是通过一张表维护的,大于0,在代码中id的数据类型是Integer(遗留代码),由于测试时没有恢复现场,导致测试数据库中id增加过快,超过了代码中Integer的表示范围,而产生了意想不到的问题。
    展开
     4
     13
  • 桂城老托尼
    2020-01-08
    感谢争哥分享
    课后讨论1.id的生成逻辑有点没看懂,单纯从代码覆盖上看,fillTransactionId 未覆盖完全,需要mock下这个静态方法,当然也有其他分支逻辑可以覆盖。
    id没有在execute方法中不是核心属性(mock方法的入参),不影响execute的可测试性。 id的生成用静态方法真的好么?
    2.有行为的对象不适合在类中new,尽量使用依赖注入,依赖接口编程,而不是具体的实现。 数据对象适合在类中new 比如各种model do vo info 。
    一家之言欢迎讨论指正。
    展开
    
     7
  • QQ怪
    2020-01-08
    看到一半,我就来评论,老师收下我的膝盖,太强了

    作者回复: 😁 感谢认可!

    
     6
  • 楊_宵夜
    2020-01-20
    争歌, 代码中isExpired()方法的修饰符是protected, 如果某些方法从设计原则来说应该设置为private的话, 那么这样的手动mock的方式是否就不适用了呢?
    换个角度来提问: 为了维持可测试性, 在代码中加入过多protected的方法, 是否合理呢?

    作者回复: 也是没办法的事情,理论上应该是private的。所以会有@VisibleForTesting这样的annotation

    
     5
  • 达文西
    2020-01-09
    内容都是干货,不够看啊
    
     3
  • 下雨天
    2020-01-08
    问题回答:
    1. IdGenerator.generateTransactionId()有未决行为逻辑,但不是说有未决行为就一定影响可测试性,前提是需要看未决行为是否有测试必要性,此处生成一个随机数(类似 System.currentTimeMillis()),测试意义不大!

    2.贫血模型实体类
    
     3
  • 逍遥思
    2020-01-08
    1. 不会影响可测试性,因为 generateTransactionId 并不需要依赖什么外部服务,所以也不需要 mock
    2. 不是。不依赖外部服务的类就可以内部创建,比如 String
    
     3
  • 平风造雨
    2020-01-08
    // 抽取了当前时间获取的逻辑,方便测试
        private long currentTimeMillis;
        private Date dueTime;
        public Demo(Date dueTime){
            this.dueTime = dueTime;
            this.currentTimeMillis = getCurrentTimeMillis();
        }

        protected long getCurrentTimeMillis(){
            return System.currentTimeMillis();
        }
        public long caculateDelayDays() {
            if(dueTime.getTime() >= currentTimeMillis){
                return 0;
            }
            long delayTime = currentTimeMillis - dueTime.getTime();
            long delayDays = delayTime / 86400_000;
            return delayDays;
        }
        @Test
        public void testCaculateDelayDays(){
            TimeZone timeZone = TimeZone.getTimeZone("Asia/ShangHai");
            Calendar calendar = Calendar.getInstance(timeZone);
            calendar.clear();
            calendar.set(2020, Calendar.FEBRUARY,1,0,0,0);
            Date dueTime = calendar.getTime();
            Demo demo = new DemoClassOne(dueTime);
            Assert.assertEquals(demo.caculateDelayDays(), 0);
            calendar.clear();
            calendar.set(2019, Calendar.DECEMBER, 31, 0,0,0);
            dueTime = calendar.getTime();
            demo = new DemoClassOne(dueTime);
            Assert.assertEquals(demo.caculateDelayDays(), 1);
        }

        public static class DemoClassOne extends Demo {
            public DemoClassOne(Date dueTime) {
                super(dueTime);
            }
            @Override
            protected long getCurrentTimeMillis() {
                TimeZone timeZone = TimeZone.getTimeZone("Asia/ShangHai");
                Calendar calendar = Calendar.getInstance(timeZone);
                calendar.clear();
                calendar.set(2020, Calendar.JANUARY,1,0,0,0);
                return calendar.getTimeInMillis();
            }
        }
    展开
    
     3
  • Jesse
    2020-01-08
    思考题1,该方法产生一个唯一的ID,我认为不需要mock。
    思考题2,我觉得如果对象有行为,并且行为与外部系统交互或者执行的结果具有不确定性,就需要依赖注入来完成测试。如果对象的行为是可预测的并且唯一的,可以直接new。
    
     2
  • 相逢是缘
    2020-01-20
    打卡
    1、什么是代码可测试性:
    针对代码编写单元测试的难易程度。如果编写单元测试很难,意味着代码设计不够合理,代码的可测试性不好。

    2、如何编写可测试性的代码
    1、通过依赖注入,我们在编写单元测试的时候,可以通过 mock 的方法解依赖外部服务
    2、依赖外部单例:将单例封装
    3、未决行为:例时间、随机数。将未决行为重新封装,测试时mock。

    3、常见的测试不友好的代码有下面这 5 种:
    1、代码中包含未决行为逻辑
    2、滥用可变全局变量
    3、滥用静态方法
    4、使用复杂的继承关系
    5、高度耦合的代码
    展开
    
     1
  • 小伟
    2020-01-20
    思考题:
    1. 看IdGenerator怎么实现,如果要查数据库或分布式服务,那么会有影响,需要mock;如果是本地生产,不需要mock。
    2. 个人观点,不要在方法里new对象,依赖都要以注入的方式获取。
    
     1
  • 落叶飞逝的恋
    2020-01-20
    不依赖框架的类,都可以手动new,比如Person对象,可以内部new,而像Spring的Service、Repository、Controller这些依赖框架的,需要用到依赖注入
    
     1
  • 落叶飞逝的恋
    2020-01-19
    IdGenerator.generateTransactionId()本身就是产生随机数的,对测试流程不影响
    
     1
  • 饭粒
    2020-01-11
    读完这篇感觉一下就认识了代码的可测试性。依赖注入提高代码的可测试性,那 spring 里推荐使用 setter 方法形式的 @autowired 注入 bean 更好哎。
    然后我认为 IdGenerator.generateTransactionId() 不需要 mock,它的功能应该就是生成一个全局唯一的 id,对 Transaction 而言功能简单,不影响测试性,本身的实现逻辑不在 Transaction 测试。
    
     1
  • 美美
    2020-01-08
    有多个通过spring注入的类时,应该怎么做测试呢?

    作者回复: 可以借助springtest测试框架来做

     3
     1
  • Jeff.Smile
    2020-01-08
    想到一个问题,代码结构扁平化的极端结果可能会造成依赖对象过多吗?这种情况mock不是依然难搞吗

    作者回复: ”代码结构扁平化的极端结果“能举个例子吗?

    
     1
  • Corner
    2020-02-03
    可不可以这么理解呢,如果静态方法依赖外部系统或者逻辑复杂,是不是最好重写为面向对象的实例方法呢?
    
    
  • Jay
    2020-01-27
    666,还是很实用,特别是重构代码可测试性部分很有启发
    
    
我们在线,来聊聊吧