Skip to content

Commit 0660c5d

Browse files
committed
docs(golang): 更新设计模式笔记。
更新状态模式笔记。
1 parent 490e863 commit 0660c5d

File tree

1 file changed

+98
-39
lines changed

1 file changed

+98
-39
lines changed

docs/zh/后端/01-Golang/03-Golang设计模式/21-状态模式.md

Lines changed: 98 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -352,48 +352,107 @@ package state
352352

353353
import (
354354
"testing"
355-
"log"
356355
)
357356

358-
// TestStatePattern 模拟客户端操作自动售货机
359-
func TestStatePattern(t *testing.T) {
360-
// 1. 初始化售货机,只有 1 件商品,价格 10 元
361-
vendingMachine := NewVendingMachine(1, 10)
362-
363-
// 2. 正常购买流程
364-
t.Log("--- 第一次购买 ---")
365-
366-
err := vendingMachine.RequestItem() // 选中商品
367-
if err != nil { log.Fatal(err) }
368-
369-
err = vendingMachine.InsertMoney(10) // 投币
370-
if err != nil { log.Fatal(err) }
357+
// 客户端
358+
// 单元测试
371359

372-
err = vendingMachine.DispenseItem() // 出货
373-
if err != nil { log.Fatal(err) }
374-
375-
t.Log("第一次购买完成")
376-
377-
// 3. 尝试购买空售货机
378-
t.Log("\n--- 第二次购买(缺货)---")
379-
380-
err = vendingMachine.RequestItem() // 尝试选中
381-
if err != nil {
382-
t.Logf("预期错误: %s", err.Error())
383-
}
384-
385-
// 4. 补货
386-
t.Log("\n--- 补货 ---")
387-
err = vendingMachine.AddItem(2)
388-
if err != nil { log.Fatal(err) }
389-
390-
t.Log("补货完成,可以继续购买")
391-
392-
// 验证状态是否恢复
393-
err = vendingMachine.RequestItem()
394-
if err == nil {
395-
t.Log("成功再次选中商品")
396-
}
360+
// TestStatePattern 模拟客户端操作自动售货机
361+
func TestVendingMachine(t *testing.T) {
362+
// 场景 1: 正常购买流程 (Happy Path)
363+
t.Run("HappyPathPurchaseSuccess", func(t *testing.T) {
364+
// Arrange: 初始化 1 个商品,价格 10 元
365+
vm := NewVendingMachine(1, 10)
366+
367+
// Act & Assert 1: 请求商品
368+
if err := vm.RequestItem(); err != nil {
369+
t.Fatalf("预期请求成功,但返回错误: %v", err)
370+
}
371+
372+
// Act & Assert 2: 投入不足的金额 (测试中间逻辑)
373+
if err := vm.InsertMoney(5); err == nil {
374+
t.Fatal("预期金额不足报错,但未报错")
375+
}
376+
377+
// Act & Assert 3: 投入足额金额
378+
if err := vm.InsertMoney(10); err != nil {
379+
t.Fatalf("预期投币成功,但返回错误: %v", err)
380+
}
381+
382+
// Act & Assert 4: 出货
383+
if err := vm.DispenseItem(); err != nil {
384+
t.Fatalf("预期出货成功,但返回错误: %v", err)
385+
}
386+
387+
// 验证副作用:库存应为 0
388+
if vm.itemCount != 0 {
389+
t.Errorf("预期库存为 0, 实际为 %d", vm.itemCount)
390+
}
391+
})
392+
393+
// 场景 2: 缺货流程 (Out of Stock)
394+
t.Run("OutOfStockFailure", func(t *testing.T) {
395+
// Arrange: 初始化 0 个商品
396+
vm := NewVendingMachine(0, 10)
397+
398+
// Act
399+
err := vm.RequestItem()
400+
401+
// Assert
402+
if err == nil {
403+
t.Error("预期缺货报错,但返回了 nil")
404+
}
405+
expectedErr := "缺货中,请勿选择" // 这里假设具体的错误信息
406+
if err.Error() != expectedErr {
407+
t.Logf("收到预期内的错误: %v", err) // 只要报错就行,具体信息如果不严格匹配可以用 Logf
408+
}
409+
})
410+
411+
// 场景 3: 状态流转限制 (非法操作)
412+
t.Run("InvalidStateTransition", func(t *testing.T) {
413+
vm := NewVendingMachine(1, 10)
414+
415+
// 未选择商品直接投币
416+
err := vm.InsertMoney(10)
417+
if err == nil {
418+
t.Error("预期报错'请先选择商品',但操作成功了")
419+
}
420+
421+
// 未投币直接出货
422+
err = vm.RequestItem() // 先选中
423+
if err != nil {
424+
t.Fatal(err)
425+
}
426+
427+
err = vm.DispenseItem() // 未投币直接出货
428+
if err == nil {
429+
t.Error("预期报错'请先支付',但操作成功了")
430+
}
431+
})
432+
433+
// 场景 4: 补货测试
434+
t.Run("RestockSuccess", func(t *testing.T) {
435+
vm := NewVendingMachine(0, 10)
436+
437+
// 初始状态应无法购买
438+
if err := vm.RequestItem(); err == nil {
439+
t.Fatal("初始应缺货")
440+
}
441+
442+
// 补货
443+
if err := vm.AddItem(5); err != nil {
444+
t.Fatalf("补货失败: %v", err)
445+
}
446+
447+
// 补货后应能购买
448+
if err := vm.RequestItem(); err != nil {
449+
t.Errorf("补货后预期可以购买,但报错: %v", err)
450+
}
451+
452+
if vm.itemCount != 5 {
453+
t.Errorf("预期库存 5, 实际 %d", vm.itemCount)
454+
}
455+
})
397456
}
398457
```
399458

0 commit comments

Comments
 (0)