Menu
Coddy logo textTech

Testing & Integration

Part of the Object Oriented Programming section of Coddy's GO journey — lesson 104 of 107.

challenge icon

Challenge

Easy

Let's bring our Library Management System full circle by writing tests that verify everything works correctly! You'll create a test file that validates your library's core functionality—ensuring books can be borrowed and returned properly, and that error conditions are handled correctly.

You'll organize your code across five files:

  • book.go: Your Book struct with ID, Title, Author, ISBN, and Available fields. Include the NewBook constructor that initializes books as available.
  • user.go: Your User struct with ID, Name, Email, and BorrowedBooks fields. Include the NewUser constructor.
  • library.go: Your Library struct with maps for books and users, along with NewLibrary, AddBook, AddUser, Borrow, and Return methods. The Borrow method should return errors for invalid user, invalid book, or unavailable book. The Return method should return errors for invalid user, invalid book, or book not borrowed.
  • library_test.go: This is where you'll write your test functions! Create tests that verify:
    • TestBorrowSuccess — Verify that borrowing an available book succeeds (no error returned), the book becomes unavailable, and the book ID is added to the user's borrowed list
    • TestBorrowUnavailable — Verify that borrowing an already-borrowed book returns an error
    • TestBorrowInvalidUser — Verify that borrowing with a non-existent user ID returns an error
    • TestReturnSuccess — Verify that returning a borrowed book succeeds, the book becomes available again, and the book ID is removed from the user's borrowed list

    Each test should set up its own library with the necessary books and users, perform the operation, and check the results using t.Error or t.Errorf when assertions fail.

  • main.go: Run your tests manually and report results. Read the test name to execute (borrow_success, borrow_unavailable, borrow_invalid_user, or return_success). Based on the test name, set up the appropriate scenario and print PASS if all assertions pass, or FAIL: [reason] if any assertion fails.

The following input will be provided:

  • A test name: borrow_success, borrow_unavailable, borrow_invalid_user, or return_success

For each test, use these standard test fixtures:

  • Book: ID B001, Title Go Programming, Author John Doe, ISBN 123-456
  • User: ID U001, Name Alice, Email alice@test.com

For example, given:

borrow_success

Your output should be:

PASS

And given:

borrow_unavailable

Your output should be:

PASS

And given:

borrow_invalid_user

Your output should be:

PASS

And given:

return_success

Your output should be:

PASS

For borrow_success: Create library, add book and user, borrow the book, verify no error, verify book is unavailable, verify user has the book in their borrowed list.

For borrow_unavailable: Create library, add book and user, set book's Available to false, attempt to borrow, verify an error is returned.

For borrow_invalid_user: Create library, add only the book (no user), attempt to borrow with user ID U001, verify an error is returned.

For return_success: Create library, add book and user, borrow the book first, then return it, verify no error, verify book is available again, verify user's borrowed list is empty.

Writing tests ensures your library system behaves correctly and gives you confidence to make changes without breaking existing functionality!

Try it yourself

package main

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

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

	// Standard test fixtures
	// Book: ID "B001", Title "Go Programming", Author "John Doe", ISBN "123-456"
	// User: ID "U001", Name "Alice", Email "alice@test.com"

	switch testName {
	case "borrow_success":
		// TODO: Test that borrowing an available book succeeds
		// 1. Create library, add book and user
		// 2. Borrow the book
		// 3. Verify: no error, book unavailable, user has book in list
		// Print "PASS" if all pass, or "FAIL: [reason]" if any fail
		fmt.Println("FAIL: not implemented")

	case "borrow_unavailable":
		// TODO: Test that borrowing unavailable book returns error
		// 1. Create library, add book and user
		// 2. Set book's Available to false
		// 3. Attempt to borrow
		// 4. Verify an error is returned
		fmt.Println("FAIL: not implemented")

	case "borrow_invalid_user":
		// TODO: Test that borrowing with invalid user returns error
		// 1. Create library, add only the book (no user)
		// 2. Attempt to borrow with user ID "U001"
		// 3. Verify an error is returned
		fmt.Println("FAIL: not implemented")

	case "return_success":
		// TODO: Test that returning a borrowed book succeeds
		// 1. Create library, add book and user
		// 2. Borrow the book first
		// 3. Return the book
		// 4. Verify: no error, book available, user's list empty
		fmt.Println("FAIL: not implemented")

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

All lessons in Object Oriented Programming