Menu
CoddyTech

测试与集成

本课属于 Coddy GO 学习旅程的“面向对象编程”单元。第 104 课,共 107 课。

challenge icon

挑战

简单

让我们通过编写测试来验证一切是否正常,让图书管理系统的整个流程完整闭环!你将创建一个测试文件,用来验证图书馆的核心功能:确保图书可以正常借出和归还,并且错误情况也能得到正确处理。

你需要把代码分成 5 个文件:

  • book.go:定义包含 ID、Title、Author、ISBN 和 Available 字段的 Book 结构体。还要包含 NewBook 构造函数,将图书初始化为可借状态。
  • user.go:定义包含 ID、Name、Email 和 BorrowedBooks 字段的 User 结构体。还要包含 NewUser 构造函数。
  • library.go:定义包含图书和用户映射的 Library 结构体,以及 NewLibrary、AddBook、AddUser、Borrow 和 Return 方法。对于无效用户、无效图书或不可借的图书,Borrow 方法应返回错误。对于无效用户、无效图书或未借出的图书,Return 方法应返回错误。
  • library_test.go:在这里编写测试函数!创建测试来验证:
    • TestBorrowSuccess:验证借出可借图书成功(未返回错误)、图书变为不可借状态,并且图书 ID 已添加到用户的借阅列表中
    • TestBorrowUnavailable:验证借出一本已被借出的图书时会返回错误
    • TestBorrowInvalidUser:验证使用不存在的用户 ID 借书时会返回错误
    • TestReturnSuccess:验证归还已借出的图书成功、图书重新变为可借状态,并且图书 ID 已从用户的借阅列表中移除

    每个测试都应创建自己的图书馆,并添加所需的图书和用户,执行操作,然后在断言失败时使用 t.Error 或 t.Errorf 检查结果。

  • main.go:手动运行测试并报告结果。读取要执行的测试名称(borrow_success、borrow_unavailable、borrow_invalid_user 或 return_success)。根据测试名称设置相应的场景,如果所有断言都通过,就打印 PASS;如果有任何断言失败,就打印 FAIL: [reason]。

系统会提供以下输入:

  • 一个测试名称:borrow_success、borrow_unavailable、borrow_invalid_user 或 return_success

每个测试都使用以下标准测试数据:

  • 图书:ID 为 B001,书名为 Go Programming,作者为 John Doe,ISBN 为 123-456
  • 用户:ID 为 U001,姓名为 Alice,邮箱为 alice@test.com

例如,输入:

borrow_success

输出应为:

PASS

输入:

borrow_unavailable

输出应为:

PASS

输入:

borrow_invalid_user

输出应为:

PASS

输入:

return_success

输出应为:

PASS

对于 borrow_success:创建图书馆,添加图书和用户,借出图书,验证没有错误、图书不可借,并且用户的借阅列表中包含这本图书。

对于 borrow_unavailable:创建图书馆,添加图书和用户,将图书的 Available 设为 false,尝试借书,并验证返回了错误。

对于 borrow_invalid_user:创建图书馆,只添加图书(不添加用户),使用用户 ID U001 尝试借书,并验证返回了错误。

对于 return_success:创建图书馆,添加图书和用户,先借出图书,再归还图书,验证没有错误、图书重新变为可借状态,并且用户的借阅列表为空。

编写测试可以确保图书馆系统正常运行,也能让你放心地进行修改,而不必担心破坏现有功能!

亲手试试

package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)
	testName, _ := reader.ReadString('\n')
	testName = strings.TrimSpace(testName)

	// 标准测试数据
	// 图书:ID "B001",书名 "Go Programming",作者 "John Doe",ISBN "123-456"
	// 用户:ID "U001",姓名 "Alice",邮箱 "alice@test.com"

	switch testName {
	case "borrow_success":
		// TODO:测试借阅可借图书是否成功
		// 1. 创建图书馆,添加图书和用户
		// 2. 借阅这本书
		// 3. 验证:没有错误,图书不可借,用户的列表中有这本书
		// 如果全部通过,输出 "PASS";如果有任何一项失败,输出 "FAIL: [reason]"
		fmt.Println("FAIL: not implemented")

	case "borrow_unavailable":
		// TODO:测试借阅不可借的图书是否返回错误
		// 1. 创建图书馆,添加图书和用户
		// 2. 将图书的 Available 设置为 false
		// 3. 尝试借阅
		// 4. 验证是否返回错误
		fmt.Println("FAIL: not implemented")

	case "borrow_invalid_user":
		// TODO: 测试使用无效用户借书时是否返回错误
		// 1. 创建库,只添加图书(不添加用户)
		// 2. 尝试使用用户 ID "U001" 借书
		// 3. 验证是否返回错误
		fmt.Println("FAIL: not implemented")

	case "return_success":
		// TODO: 测试归还已借出的图书是否成功
		// 1. 创建图书馆,添加图书和用户
		// 2. 先借出图书
		// 3. 归还图书
		// 4. 验证:没有错误,图书可借,用户的列表为空
		fmt.Println("FAIL: not implemented")

	default:
		fmt.Println("FAIL: unknown test")
	}
}

面向对象编程中的所有课

自己练习: Go 在线编译器