Serie: Angelia
java
149 líneas
· Actualizado 2026-09-27
GuestListTest.java
Angelia/Java/Week_6_7/code/05_junit_tdd/GuestListTest.java
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import static org.junit.jupiter.api.Assertions.*;
/**
* GuestList 的 JUnit 5 黑箱測試。
*
* 重點:
* - 變數宣告成 GuestList(介面),而不是某個實作類別:測的是「契約」,不是實作細節。
* - 每個 @Test 方法都是獨立的:JUnit 會為每個測試建立一個「新的」測試物件,
* 所以 @BeforeEach 裡建立的名單不會在測試之間互相干擾。
* - 同一組測試對兩種實作都跑一次(見 LazyTest / StrictTest 兩個子類別)。
*
* 在 IntelliJ 中:把游標放在紅色的 @Test 上按 Alt+Enter → Add JUnit5 to classpath,
* 然後按類別名旁邊的綠色播放鍵即可執行。
*/
abstract class GuestListTest {
/** 由子類別決定要測哪一種實作(工廠方法)。 */
abstract GuestList create();
private GuestList gl;
@BeforeEach
void setUp() {
gl = create(); // 每個測試開始前都拿到一份全新的空名單
}
@Test
@DisplayName("新名單是空的")
void emptyListHasNobody() {
assertFalse(gl.isComing("Fabian"));
assertEquals(0, gl.count());
assertEquals(0, gl.coming().length);
}
@Test
@DisplayName("add 之後 isComing 為 true")
void addThenIsComing() {
gl.add("Fabian");
assertTrue(gl.isComing("Fabian"));
assertFalse(gl.isComing("Nicholas"));
assertEquals(1, gl.count());
}
@Test
@DisplayName("集合語意:同一個人 add 兩次等於 add 一次")
void addingTwiceIsIdempotent() {
gl.add("Fabian");
gl.add("Fabian");
assertTrue(gl.isComing("Fabian"));
assertEquals(1, gl.count(), "重複加入不應被重複計算");
gl.remove("Fabian");
assertFalse(gl.isComing("Fabian"), "移除一次之後必須完全消失");
assertEquals(0, gl.count());
}
@Test
@DisplayName("remove 只影響被移除的人")
void removeAffectsOnlyThatGuest() {
gl.add("Fabian");
gl.add("Nicholas");
gl.remove("Fabian");
assertFalse(gl.isComing("Fabian"));
assertTrue(gl.isComing("Nicholas"));
assertEquals(1, gl.count());
}
@Test
@DisplayName("從空名單或不存在的人 remove 不會出錯")
void removeFromEmptyOrMissing() {
gl.remove("Fabian"); // 空名單
assertFalse(gl.isComing("Fabian"));
gl.add("Ann");
gl.remove("Bob"); // 不存在的人
assertTrue(gl.isComing("Ann"));
assertEquals(1, gl.count());
}
@Test
@DisplayName("移除後可以再加回來")
void reAddAfterRemove() {
gl.add("Fabian");
gl.remove("Fabian");
gl.add("Fabian");
assertTrue(gl.isComing("Fabian"));
assertEquals(1, gl.count());
}
@Test
@DisplayName("加入很多人:觸發陣列倍增也要正確")
void manyGuestsTriggerResize() {
int i = 0;
while (i < 1000) {
gl.add("guest" + i);
i = i + 1;
}
assertEquals(1000, gl.count());
assertTrue(gl.isComing("guest0"));
assertTrue(gl.isComing("guest999"));
assertFalse(gl.isComing("guest1000"));
}
@Test
@DisplayName("coming() 回傳的是防禦性複製,改它不影響名單")
void comingReturnsDefensiveCopy() {
gl.add("Fabian");
gl.add("Nicholas");
String[] snapshot = gl.coming();
assertEquals(2, snapshot.length);
String[] sortedSnapshot = snapshot.clone();
Arrays.sort(sortedSnapshot);
assertArrayEquals(new String[]{"Fabian", "Nicholas"}, sortedSnapshot);
snapshot[0] = "Intruder"; // 惡意(或不小心)改動回傳的陣列
assertFalse(gl.isComing("Intruder"), "封裝:外部改動不得影響內部狀態");
assertEquals(2, gl.count());
}
@Test
@DisplayName("assertThrows 示範:null 名字不合法(本實作選擇拋出例外)")
void nullNameIsRejected() {
// 這個測試示範 assertThrows 的用法;GuestList 介面本身沒有規定 null 的行為,
// 所以嚴格來說它是「白箱」測試——只對我們自己的實作成立。
IllegalArgumentException e =
assertThrows(IllegalArgumentException.class, () -> gl.add(null));
assertNotNull(e.getMessage());
}
}
/** 對「懶惰」實作跑整套測試。 */
class LazyGuestListTest extends GuestListTest {
@Override
GuestList create() {
return new GuestArrayList();
}
}
/** 對「嚴格」實作跑同一套測試。 */
class StrictGuestListTest extends GuestListTest {
@Override
GuestList create() {
return new GuestArrayUniqueList();
}
}
Artículos relacionados
Angelia
haskell
EN
Actualizado 2026-02-03
Adding.hs
Adding.hs — haskell source code from the Angelia learning materials (Angelia/Haskell/Adding.hs).
Leer artículo →
Angelia
haskell
EN
Actualizado 2026-02-03
Area.hs
Area.hs — haskell source code from the Angelia learning materials (Angelia/Haskell/Area.hs).
Leer artículo →
Angelia
haskell
EN
Actualizado 2026-02-03
Chess.hs
Chess.hs — haskell source code from the Angelia learning materials (Angelia/Haskell/Chess.hs).
Leer artículo →
Angelia
haskell
EN
Actualizado 2026-02-03
ChessGraphics.hs
ChessGraphics.hs — haskell source code from the Angelia learning materials (Angelia/Haskell/ChessGraphics.hs).
Leer artículo →
Angelia
haskell
EN
Actualizado 2026-02-03
Examples.hs
Examples.hs — haskell source code from the Angelia learning materials (Angelia/Haskell/Examples.hs).
Leer artículo →
Angelia
haskell
EN
Actualizado 2026-02-03
Fibonacci.hs
Fibonacci.hs — haskell source code from the Angelia learning materials (Angelia/Haskell/Fibonacci.hs).
Leer artículo →