Aglie PPP 第6章 保龄球案例 阅读笔记
第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????
花了整整一个下午看完了这一章,并动手实现(书中的代码和我自己的代码)。在看的过程中,我对测试驱动没什么感觉,倒是有几个地方我很有兴趣。
某人写了代码,通过测试,然后,另外一个人说,你没考虑某某情况,无法通过我的这个测试,接着拿走键盘敲测试,运行测试失败。
某人写了代码,通过测试,然后,另外一个人说,我觉得这里这么写会更好,拿过键盘,改某些代码,通过测试。
写测试时,不要嫌测试简单,也不要嫌测试太多。
在测试中,对某个类写了一个不存在的方法时,IDE就会提示存在什么什么问题,然后最好自动创建该方法。
写测试时,尽可能简单。
参数的防护
先实现功能
测试也需要重构
如果做这种结对编程,是需要有追求极致的理念的,并且需要懂一些测试的原理,不然
这种情况,虽然两个人都认为没有什么问题了,实际上,到底有没有问题还很难说。