Aglie PPP 第6章 保龄球案例 阅读笔记

第6章 保龄球案例

大神的代码

Aglie PPP 第6章 保龄球案例 阅读笔记

 

我的代码

Aglie PPP 第6章 保龄球案例 阅读笔记

public class MyGame {
    // 击倒的木瓶
    private int[] bottles = new int[22];
    // 一轮特殊标记 0 普通 1 全中 2 补中
    private int[] frames = new int[11];
    // 当前所在轮
    private int currentFrame = 0;
    // 当前轮投掷的次数
    private int throwCount = 0;

    // 记录击倒的木瓶
    public void add(int bottle) {
        bottles[currentFrame * 2 + throwCount] = bottle;
        // 考虑最后一次的
        if (currentFrame == 10) {
            throwCount++;
            return;
        }
        // 全中的情况
        if (throwCount == 0 && bottle == 10) {
            frames[currentFrame] = 1;
            advanceFrame();
        }
        // 补中的情况
        else if (throwCount == 1 && bottles[currentFrame * 2] + bottle == 10) {
            frames[currentFrame] = 2;
            advanceFrame();
            throwCount = 0;
        }
        // 普通的情况
        else {
            // 如果是第一次投掷
            if (throwCount == 0) {
                throwCount = 1;
            }
            // 如果是第二次投掷
            else {
                throwCount = 0;
                advanceFrame();
            }
        }
    }

    private void advanceFrame() {
        if (currentFrame < 10) {
            currentFrame++;
        }
    }

    // 获取当前的分数
    public int score() {
        return scoreForFrame(currentFrame < 10 ? currentFrame + 1 : 10);
    }

    // 获取某一轮的分数
    public int scoreForFrame(int theFrame) {
        int score = 0;
        for (int i = 0; i < theFrame; i++) {
            int status = frames[i];
            // 普通情况
            if (status == 0) {
                score += bottles[i * 2] + bottles[i * 2 + 1];
            }
            // 补中
            else if (status == 2) {
                score += 10 + bottles[(i + 1) * 2];
            }
            // 全中
            else {
                // 需要考虑接下来又为全中的情况
                if (frames[i + 1] == 1) {
                    score += 10 + bottles[(i + 1) * 2] + bottles[(i + 2) * 2];
                } else {
                    score += 10 + bottles[(i + 1) * 2] + bottles[(i + 1) * 2 + 1];

                }
            }
        }
        return score;
    }
}

都通过了测试,测试代码如下

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class MyGameTest {
    private MyGame g;
    @Before
    public void setUp() {
        g = new MyGame();
    }
    @Test
    public void testOneThrows() {
        g.add(5);
        Assert.assertEquals(5, g.score());
    }
    @Test
    public void testTwoThrowsNoMark() {
        g.add(5);
        g.add(4);
        assertEquals(9, g.score());
    }
    @Test
    public void testFourThrowsNoMark() {
        g.add(5);
        g.add(4);
        g.add(7);
        g.add(2);
        assertEquals(18, g.score());
        assertEquals(9, g.scoreForFrame(1));
        assertEquals(18, g.scoreForFrame(2));
    }
    @Test
    public void testSimpleSpare() {
        g.add(3);
        g.add(7);
        g.add(3);
        assertEquals(13, g.scoreForFrame(1));
    }
    @Test
    public void testSimpleFrameAfterSpare() {
        g.add(3);
        g.add(7);
        g.add(3);
        g.add(2);
        assertEquals(13, g.scoreForFrame(1));
        assertEquals(18, g.scoreForFrame(2));
        assertEquals(18, g.score());
    }
    @Test
    public void testSimpleStrike() {
        g.add(10);
        g.add(3);
        g.add(6);
        assertEquals(19, g.scoreForFrame(1));
        assertEquals(28, g.score());
    }
    @Test
    public void testPerfectGame() {
        for (int i = 0; i < 12; i++) {
            g.add(10);
        }
        assertEquals(300, g.score());
    }
    @Test
    public void testEndOfArray() {
        for (int i = 0; i < 9; i++) {
            g.add(0);
            g.add(0);
        }
        g.add(2);
        // 10th frame spare
        g.add(8);
        // Strike in last position of array
        g.add(10);
        assertEquals(20, g.score());
    }
    @Test
    public void testSampleGame() {
        g.add(1);
        g.add(4);

        g.add(4);
        g.add(5);

        g.add(6);
        g.add(4);

        g.add(5);
        g.add(5);

        g.add(10);

        g.add(0);
        g.add(1);

        g.add(7);
        g.add(3);

        g.add(6);
        g.add(4);

        g.add(10);

        g.add(2);
        g.add(8);
        g.add(6);
        int[] scores = {
                5, 14, 29, 49, 60, 61, 77, 97, 117, 133
        };
        for (int i = 0; i < scores.length; i++) {
            assertEquals(scores[i], g.scoreForFrame(i+1));
        }
        assertEquals(133, g.score());
    }
    @Test
    public void testHeartBreak() {
        for (int i = 0; i < 11; i++) {
            g.add(10);
        }
        g.add(9);
        assertEquals(299, g.score());
    }
    @Test
    public void testTenthFrameSpare() {
        for (int i = 0; i < 9; i++) {
            g.add(10);
        }
        g.add(9);
        g.add(1);
        g.add(1);
        assertEquals(270, g.score());
    }
}

我在写代码的时候,发现真是没有什么不能加一个if解决的,如果有,就再加一个if,如果还有,就再套一层if????

 

花了整整一个下午看完了这一章,并动手实现(书中的代码和我自己的代码)。在看的过程中,我对测试驱动没什么感觉,倒是有几个地方我很有兴趣。

某人写了代码,通过测试,然后,另外一个人说,你没考虑某某情况,无法通过我的这个测试,接着拿走键盘敲测试,运行测试失败。

Aglie PPP 第6章 保龄球案例 阅读笔记

某人写了代码,通过测试,然后,另外一个人说,我觉得这里这么写会更好,拿过键盘,改某些代码,通过测试。

 

写测试时,不要嫌测试简单,也不要嫌测试太多。

在测试中,对某个类写了一个不存在的方法时,IDE就会提示存在什么什么问题,然后最好自动创建该方法。

写测试时,尽可能简单。

参数的防护

Aglie PPP 第6章 保龄球案例 阅读笔记

先实现功能

Aglie PPP 第6章 保龄球案例 阅读笔记

测试也需要重构

Aglie PPP 第6章 保龄球案例 阅读笔记

如果做这种结对编程,是需要有追求极致的理念的,并且需要懂一些测试的原理,不然

Aglie PPP 第6章 保龄球案例 阅读笔记

这种情况,虽然两个人都认为没有什么问题了,实际上,到底有没有问题还很难说。