กลุ่มปรกติที่เห็นได้บ่อยๆ (Normal cases)
------
1.ลง X ลงไปตอนที่กระดานว่าง ระบบให้ลงได้ แต่ยังไม่มีผู้ชนะ และสลับเป็นตาของ O
2.ลง O ลงไปตอนที่กระดานว่าง ระบบให้ลงได้ แต่ยังไม่มีผู้ชนะ และสลับเป็นตาของ X
🧔 ข้อดีในการทำแบบนี้คือเราสามารถเห็นข้อผิดพลาดได้เลยโดยที่ยังไม่ต้องเขียนโค้ดด้วยซ้ำ เช่น กฎิกาของเกม OX จริงๆจะต้องให้ X ลงก่อน ดังนั้นกรณีที่ 2 จะต้องไม่มี เพราะ O ลงก่อนไม่ได้! ดังนั้นก็ลบข้อ 2 ออกซะ
กลุ่มปรกติที่เห็นได้บ่อยๆ (Normal cases)
------
1.ลง X ลงไปตอนที่กระดานว่าง ระบบให้ลงได้ แต่ยังไม่มีผู้ชนะ และสลับเป็นตาของ O
กลุ่มปรกติที่เห็นได้บ่อยๆ (Normal cases)
------
1.ลง X ไปตอนที่กระดานว่าง ระบบให้ลงได้ แต่ยังไม่มีผู้ชนะ และสลับเป็นตาของ O
2.ลง O ไปในช่องว่าซึ่งบนกระดานมี X 1 ตัวเท่านั้น ระบบให้ลงได้ แต่ยังไม่มีผู้ชนะ และสลับเป็นตาของ X
3.ลง X ไปในช่องว่าซึ่งบนกระดานมี X 1 ตัวและ O 1 ตัว ระบบให้ลงได้ แต่ยังไม่มีผู้ชนะ และสลับเป็นตาของ O
4.ลง O ไปในช่องว่าซึ่งบนกระดานมี X 2 ตัวและ O 1 ตัว ระบบให้ลงได้ แต่ยังไม่มีผู้ชนะ และสลับเป็นตาของ X
5.ลง X ไปในช่องว่าซึ่งบนกระดานมี X 2 ตัวและ O 2 ตัว แต่ X ทั้งหมดไม่ได้เรียงกัน ระบบให้ลงได้ แต่ยังไม่มีผู้ชนะ และสลับเป็นตาของ O
6.ลง O ไปในช่องว่าซึ่งบนกระดานมี X 3 ตัวและ O 2 ตัว แต่ O ทั้งหมดไม่ได้เรียงกัน ระบบให้ลงได้ แต่ยังไม่มีผู้ชนะ และสลับเป็นตาของ X
7.ลง X ไปในช่องว่าซึ่งบนกระดานมี X 2 ตัวและ O 2 ตัว และ X ทั้งหมดเรียงกัน ระบบให้ลงได้และประกาศว่า X ชนะพร้อมกับเพิ่มแต้มให้ X 1 คะแนน
8.ลง O ไปในช่องว่าซึ่งบนกระดานมี X 3 ตัวและ O 2 ตัว และ O ทั้งหมดเรียงกัน ระบบให้ลงได้และประกาศว่า O ชนะ พร้อมกับเพิ่มแต้มให้ O 1 คะแนน
9.ลง X ไปในช่องว่างซึ่งบนกระดานมี X 4 ตัวและ O 4 ตัว แต่ X ทั้งหมดไม่ได้เรียงกัน ระบบให้ลงได้ และแจ้งว่าเกมเสมอ
กลุ่มที่นานๆจะเจอที (Alternative cases)
-----
1.ลง X ไปในช่องที่ไม่ว่าง ระบบไม่ให้ลงพร้อมแจ้งเตือน และยังคงเป็นตาของ X อยู่
2.ลง O ไปในช่องที่ไม่ว่าง ระบบไม่ให้ลงพร้อมแจ้งเตือน และยังคงเป็นตาของ O อยู่
กลุ่มที่เกิดสถานะการณ์แปลกๆในในโปรแกรม
-----
1.ลง X ไปในช่องว่างซึ่งบนกระดานมี X 1 ตัวเท่านั้น ระบบไม่ให้ลงพร้อมแจ้งเตือน และสลับเป็นตาของ O
2.ลง X ไปในช่องที่ไม่มีอยู่ในกระดาน ระบบไม่ให้ลงพร้อมแจ้งเตือน และยังคงเป็นตาของ X อยู่
กลุ่มปรกติที่เห็นได้บ่อยๆ (Normal cases)
-----
1.ลง X ไปตอนที่กระดานว่าง ระบบให้ลงได้ แต่ยังไม่มีผู้ชนะ และสลับเป็นตาของ O
2.ลง O ไปในช่องว่าซึ่งบนกระดานมี X 1 ตัวเท่านั้น ระบบให้ลงได้ แต่ยังไม่มีผู้ชนะ และสลับเป็นตาของ X
3.ลง X ไปในช่องว่าซึ่งบนกระดานมี X 1 ตัวและ O 1 ตัว ระบบให้ลงได้ แต่ยังไม่มีผู้ชนะ และสลับเป็นตาของ O
4.ลง O ไปในช่องว่าซึ่งบนกระดานมี X 2 ตัวและ O 1 ตัว ระบบให้ลงได้ แต่ยังไม่มีผู้ชนะ และสลับเป็นตาของ X
5.ลง X ไปในช่องว่าซึ่งบนกระดานมี X 2 ตัวและ O 2 ตัว แต่ X ทั้งหมดไม่ได้เรียงกัน ระบบให้ลงได้ แต่ยังไม่มีผู้ชนะ และสลับเป็นตาของ O
6.ลง O ไปในช่องว่าซึ่งบนกระดานมี X 3 ตัวและ O 2 ตัว แต่ O ทั้งหมดไม่ได้เรียงกัน ระบบให้ลงได้ แต่ยังไม่มีผู้ชนะ และสลับเป็นตาของ X
7.ลง X ไปในช่องว่าซึ่งบนกระดานมี X 2 ตัวและ O 2 ตัว และ X ทั้งหมดเรียงกัน ระบบให้ลงได้และประกาศว่า X ชนะพร้อมกับเพิ่มแต้มให้ X 1 คะแนน
8.ลง O ไปในช่องว่าซึ่งบนกระดานมี X 3 ตัวและ O 2 ตัว และ O ทั้งหมดเรียงกัน ระบบให้ลงได้และประกาศว่า O ชนะ พร้อมกับเพิ่มแต้มให้ O 1 คะแนน
9.ลง X ไปในช่องว่างซึ่งบนกระดานมี X 4 ตัวและ O 4 ตัว แต่ X ทั้งหมดไม่ได้เรียงกัน ระบบให้ลงได้ และแจ้งว่าเกมเสมอ
กลุ่มที่นานๆจะเจอที (Alternative cases)
-----
10.ลง X ไปในช่องที่ไม่ว่าง ระบบไม่ให้ลงพร้อมแจ้งเตือน และยังคงเป็นตาของ X อยู่
11.ลง O ไปในช่องที่ไม่ว่าง ระบบไม่ให้ลงพร้อมแจ้งเตือน และยังคงเป็นตาของ O อยู่
กลุ่มที่เกิดสถานะการณ์แปลกๆในในโปรแกรม
-----
12.ลง X ไปในช่องว่างซึ่งบนกระดานมี X 1 ตัวเท่านั้น ระบบไม่ให้ลงพร้อมแจ้งเตือน และสลับเป็นตาของ O
13.ลง X ไปในช่องที่ไม่มีอยู่ในกระดาน ระบบไม่ให้ลงพร้อมแจ้งเตือน และยังคงเป็นตาของ X อยู่
[Fact(DisplayName = "ลง X ไปตอนที่กระดานว่าง ระบบให้ลงได้ แต่ยังไม่มีผู้ชนะ และสลับเป็นตาของ O")]
public void PlaceXWhenBoardIsEmpty()
{
var boardGame = new BoardGame();
var canPlace = boardGame.Place("X", 0, 0);
Assert.True(canPlace);
Assert.Equal("O", boardGame.CurrentTurn);
Assert.Null(boardGame.GetWinner());
}
public string CurrentTurn { get; set; }
public bool Place(string symbol, int row, int column)
{
throw new NotImplementedException();
}
public string GetWinner()
{
throw new NotImplementedException();
}
public bool Place(string symbol, int row, int column)
{
Slots[row, column] = symbol;
var isEvenNumber = Slots.Cast<string>().Count(it => it != null) % 2 == 0;
if (isEvenNumber)
{
CurrentTurn = "X";
}
else
{
CurrentTurn = "O";
}
return true;
}
🧔 ลอง Run test ละก็ผ่าน ดังนั้นผมก็จะ Refactor ต่อกับไฟล์เดิมนี่แหละ เพราะผมคิดว่า การตรวจว่าเป็นตาของ X หรือ O ในบรรทัดที่ 7~14 ยังเยิ่นเย้ออยู่ ซึ่งก็จะ Refactor ใหม่ออกมาได้เป็นแบบนี้
GameBoard.cs
public bool Place(string symbol, int row, int column)
{
Slots[row, column] = symbol;
var isEvenNumber = Slots.Cast<string>().Count(it => it != null) % 2 == 0;
CurrentTurn = isEvenNumber ? "X" : "O";
return true;
}
🧔 อะเช Run test แล้วก็ผ่านอยู่ งั้นตอนนี้ไปเอาเทสเคสที่ 3 มาทำต่อบ้างดีกว่า ซึ่งมันเขียนไว้ว่า
3.ลง X ไปในช่องว่าซึ่งบนกระดานมี X 1 ตัวและ O 1 ตัว ระบบให้ลงได้ แต่ยังไม่มีผู้ชนะ และสลับเป็นตาของ O
ดังนั้นผมก็จะเขียนเทสให้ตัวนี้ออกมาเป็นตามนี้
BoardGameTest.cs
[Fact(DisplayName = "ลง X ไปในช่องว่าซึ่งบนกระดานมี X 1 ตัวและ O 1 ตัว ระบบให้ลงได้ แต่ยังไม่มีผู้ชนะ และสลับเป็นตาของ O")]
public void PlaceXInEmptySlotWhenBoardHave_1X_1O()
{
var boardGame = new BoardGame
{
Slots = new string[,]
{
{ "X", "O", null },
{ null, null, null },
{ null, null, null },
}
};
var canPlace = boardGame.Place("X", 1, 0);
Assert.True(canPlace);
Assert.Equal("O", boardGame.CurrentTurn);
Assert.Null(boardGame.GetWinner());
}
🧔 แล้วก็ลอง Run test ก็จะพบว่ามันผ่านเหมือนกัน แต่สิ่งที่ผมเห็นแล้วน่ารำคาญคือเจ้าไฟล์ BoardGameTest.cs เพราะทุกครั้งที่ผมเขียนเทส มันจะดูเหมือนมันเขียนของเดิมซ้ำๆ ไม่เชื่อลองดูไฟล์เต็มๆมันดูนะ
BoardGameTest.cs
[Fact(DisplayName = "ลง X ไปตอนที่กระดานว่าง ระบบให้ลงได้ แต่ยังไม่มีผู้ชนะ และสลับเป็นตาของ O")]
public void PlaceXWhenBoardIsEmpty()
{
var boardGame = new BoardGame();
var canPlace = boardGame.Place("X", 0, 0);
Assert.True(canPlace);
Assert.Equal("O", boardGame.CurrentTurn);
Assert.Null(boardGame.GetWinner());
}
[Fact(DisplayName = "ลง O ไปในช่องว่าซึ่งบนกระดานมี X 1 ตัวเท่านั้น ระบบให้ลงได้ แต่ยังไม่มีผู้ชนะ และสลับเป็นตาของ X")]
public void PlaceOInEmptySlotWhenBoardHave_1X_0O()
{
var boardGame = new BoardGame
{
Slots = new string[,]
{
{ "X", null, null },
{ null, null, null },
{ null, null, null },
}
};
var canPlace = boardGame.Place("O", 0, 1);
Assert.True(canPlace);
Assert.Equal("X", boardGame.CurrentTurn);
Assert.Null(boardGame.GetWinner());
}
[Fact(DisplayName = "ลง X ไปในช่องว่าซึ่งบนกระดานมี X 1 ตัวและ O 1 ตัว ระบบให้ลงได้ แต่ยังไม่มีผู้ชนะ และสลับเป็นตาของ O")]
public void PlaceXInEmptySlotWhenBoardHave_1X_1O()
{
var boardGame = new BoardGame
{
Slots = new string[,]
{
{ "X", "O", null },
{ null, null, null },
{ null, null, null },
}
};
var canPlace = boardGame.Place("X", 1, 0);
Assert.True(canPlace);
Assert.Equal("O", boardGame.CurrentTurn);
Assert.Null(boardGame.GetWinner());
}
🧔 แน่นอนถ้าผมเปลี่ยนเป็นแบบนี้ก็ต้องลอง Run test ให้มันผ่านด้วยเช่นกัน ซึ่งก็ผ่านตามที่คาดไว้ ดังนั้นผมก็จะเริ่มเอาเทสเคสที่ 4~6 ลงมาใส่ต่อเลย (เพราะผมรู้ว่ามันก็ผ่านเหมือนกัน)
4.ลง O ไปในช่องว่าซึ่งบนกระดานมี X 2 ตัวและ O 1 ตัว ระบบให้ลงได้ แต่ยังไม่มีผู้ชนะ และสลับเป็นตาของ X
5.ลง X ไปในช่องว่าซึ่งบนกระดานมี X 2 ตัวและ O 2 ตัว แต่ X ทั้งหมดไม่ได้เรียงกัน ระบบให้ลงได้ แต่ยังไม่มีผู้ชนะ และสลับเป็นตาของ O
6.ลง O ไปในช่องว่าซึ่งบนกระดานมี X 3 ตัวและ O 2 ตัว แต่ O ทั้งหมดไม่ได้เรียงกัน ระบบให้ลงได้ แต่ยังไม่มีผู้ชนะ และสลับเป็นตาของ X
ซึ่งก็จะได้โค้ดออกมาตามนี้
BoardGameTest.cs
[Fact(DisplayName = "ลง O ไปในช่องว่าซึ่งบนกระดานมี X 2 ตัวและ O 1 ตัว ระบบให้ลงได้ แต่ยังไม่มีผู้ชนะ และสลับเป็นตาของ X")]
public void PlaceOInEmptySlotWhenBoardHave_2X_1O()
{
var slots = new string[,]
{
{ "X", "O", null },
{ "X", null, null },
{ null, null, null },
};
verifyPlaceASymbolToEmptySpaceThenSystemMustAcceptTheRequest(slots, "O", 1, 1, "X");
}
[Fact(DisplayName = "ลง X ไปในช่องว่าซึ่งบนกระดานมี X 2 ตัวและ O 2 ตัว แต่ X ทั้งหมดไม่ได้เรียงกัน ระบบให้ลงได้ แต่ยังไม่มีผู้ชนะ และสลับเป็นตาของ O")]
public void PlaceXInEmptySlotWhenBoardHave_2X_2O_ButNotConnectedTogather()
{
var slots = new string[,]
{
{ "X", "O", null },
{ "X", "O", null },
{ null, null, null },
};
verifyPlaceASymbolToEmptySpaceThenSystemMustAcceptTheRequest(slots, "O", 0, 2, "O");
}
[Fact(DisplayName = "ลง O ไปในช่องว่าซึ่งบนกระดานมี X 3 ตัวและ O 2 ตัว แต่ O ทั้งหมดไม่ได้เรียงกัน ระบบให้ลงได้ แต่ยังไม่มีผู้ชนะ และสลับเป็นตาของ X")]
public void PlaceOInEmptySlotWhenBoardHave_3X_2O_ButNotConnectedTogather()
{
var slots = new string[,]
{
{ "X", "O", null },
{ "X", "O", null },
{ null, "X", null },
};
verifyPlaceASymbolToEmptySpaceThenSystemMustAcceptTheRequest(slots, "O", 2, 0, "X");
}