第5、6、7、8、9章测试驱动开发过程

User Story(用户故事)

作为一位酒店大堂服务员,我想在大堂的城市时钟不准时,用设置自己手机时间的方法,自动统一调整这些城市时钟的时间,来避免逐一根据时差调整这些时钟的繁琐工作。

写测试用例

HotelWorldClocksTest.java

public class HotelWorldClocksTest {

    private HotelWorldClockSystem hotelWorldClockSystem;
    private PhoneClock phoneClock;

    @Before
    public void init() {
        this.hotelWorldClockSystem = new HotelWorldClockSystem();
        this.phoneClock = new PhoneClock(8);
    }

    @Test
    public void the_time_of_clock_London_should_be_1_after_the_phone_clock_is_set_to_9_Beijing_time() {
        // Arrange
        CityClock londonClock = new CityClock(0);
        hotelWorldClockSystem.attach("london", londonClock);

        // Act
        phoneClock.setHotelWorldClockSystem(hotelWorldClockSystem);
        phoneClock.setTime(9);

        // Assert
        assertEquals(1, londonClock.getLocalTime());
    }

    @Test
    public void the_time_of_clock_NewYork_should_be_20_after_the_phone_clock_is_set_to_9_Beijing_time() {
        // Arrange
        CityClock newYorkClock = new CityClock(-5);
        hotelWorldClockSystem.attach("newYork", newYorkClock);

        // Act
        phoneClock.setHotelWorldClockSystem(hotelWorldClockSystem);
        phoneClock.setTime(9);

        // Assert
        assertEquals(20, newYorkClock.getLocalTime());
    }

    @Test
    public void the_time_of_clock_London_and_NewYork_should_be_1_and_20_respectively_after_the_phone_clock_is_set_to_9_Beijing_time() {
        // Arrange
        CityClock newYorkClock = new CityClock(-5);
        CityClock londonClock = new CityClock(0);
        hotelWorldClockSystem.attach("london", londonClock);
        hotelWorldClockSystem.attach("newYork", newYorkClock);

        // Act
        phoneClock.setHotelWorldClockSystem(hotelWorldClockSystem);
        phoneClock.setTime(9);

        // Assert
        assertEquals(1, londonClock.getLocalTime());
        assertEquals(20, newYorkClock.getLocalTime());
    }

    @Test
    public void the_time_of_the_phone_clock_should_be_set_correctly_after_its_setTime_method_is_invoked() {
        // Arrange

        // Act
        phoneClock.setTime(9);

        // Assert
        assertEquals(9, phoneClock.getLocalTime());
    }
}

生成并调试代码

HotelWorldClockSystem.java

public class HotelWorldClockSystem {

    private Map<String, Clock> cityClocks = new HashMap<String, Clock>();

    public void attach(String name, Clock londonClock) {
        cityClocks.put(name, londonClock);
    }

    public void updateCityClockWithUtcZeroTime(int utcZeroTime) {
        for (Clock clock : cityClocks.values()) {
            clock.setLocalTime((utcZeroTime + clock.utcOffSet + 24) % 24);
        }
    }

}

Clock.java

public class Clock {

    protected int utcOffSet;
    protected int localTime;

    public Clock(int utcOffSet) {
        this.utcOffSet = utcOffSet;
    }

    public int getLocalTime() {
        return this.localTime;
    }

    public void setLocalTime(int localTime) {
        this.localTime = localTime;
    }
}

PhoneClock.java

public class PhoneClock extends Clock {

    private HotelWorldClockSystem hotelWorldClockSystem;

    public PhoneClock(int utcOffSet) {
        super(utcOffSet);
    }

    public void setLocalTime(int localTime) {
        super.localTime = localTime;
        if (this.hotelWorldClockSystem != null)
            this.hotelWorldClockSystem
                    .updateCityClockWithUtcZeroTime((localTime
                            - super.utcOffSet + 24) % 24);
    }

    public void setHotelWorldClockSystem(
            HotelWorldClockSystem hotelWorldClockSystem) {
        this.hotelWorldClockSystem = hotelWorldClockSystem;
    }
}

最终的类图

这里写图片描述

测试驱动开发的过程

1.”尽量简单”的标准选取第一个测试
a)用User Story的格式描述产品特性。用‘产品特性’这样基于沟通的字眼替换带有强制、专制和持久色彩的‘需求’一词
b)从User Story中选取一种简单情况编写第一个测试函数,测试函数名写的长一点作为易于阅读的文档,在一个测试中先写Assert部分,然后推导出Act和Arrange这两部分代码
c)根据测试函数里的符合自己意图的代码驱动生成生产代码,只写能让编译通过的、尽量少的代码
d)列出TODO清单,重构是测试通过
2.”尽量有意思”的标准选取下一个测试
a)写好一个测试的Assert部分后,在以此推导出Act和Arrange部分的意图代码
b)循着意图代码中红色的编译错误的指引来编写最少的代码消除错误
c)调试,用最少的代码使测试通过
d)足够自信时,步子可以迈的大一点
3.迭代的测试
a)完成所有TODO列表之后,重新审阅代码找出还未测到的情况和遗漏的代码“腐臭”
b)将子类构造器中出现的重复成员变量上移到父类中,以消除重复
c)将那些因被替换而不再被调用的代码删掉
d)将子类中签名相同但实现不同的方法,提取一个抽象方法放到父类中
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值