Testes e Integração
Parte da seção Programação Orientada a Objetos do Journey de GO da Coddy — lição 104 de 107.
Desafio
FácilVamos completar o nosso Sistema de Gerenciamento de Biblioteca escrevendo testes que verificam se tudo funciona corretamente! Você criará um arquivo de teste que valida a funcionalidade principal da sua biblioteca — garantindo que os livros possam ser emprestados e devolvidos adequadamente, e que as condições de erro sejam tratadas corretamente.
Você organizará seu código em cinco arquivos:
book.go: Sua structBookcom os camposID,Title,Author,ISBNeAvailable. Inclua o construtorNewBookque inicializa os livros como disponíveis.user.go: Sua structUsercom os camposID,Name,EmaileBorrowedBooks. Inclua o construtorNewUser.library.go: Sua structLibrarycom maps para livros e usuários, junto com os métodosNewLibrary,AddBook,AddUser,BorroweReturn. O métodoBorrowdeve retornar erros para usuário inválido, livro inválido ou livro indisponível. O métodoReturndeve retornar erros para usuário inválido, livro inválido ou livro não emprestado.library_test.go: É aqui que você escreverá suas funções de teste! Crie testes que verifiquem:TestBorrowSuccess— Verifique se o empréstimo de um livro disponível é bem-sucedido (nenhum erro retornado), se o livro se torna indisponível e se o ID do livro é adicionado à lista de emprestados do usuárioTestBorrowUnavailable— Verifique se o empréstimo de um livro já emprestado retorna um erroTestBorrowInvalidUser— Verifique se o empréstimo com um ID de usuário inexistente retorna um erroTestReturnSuccess— Verifique se a devolução de um livro emprestado é bem-sucedida, se o livro se torna disponível novamente e se o ID do livro é removido da lista de emprestados do usuário
Cada teste deve configurar sua própria biblioteca com os livros e usuários necessários, realizar a operação e verificar os resultados usando
t.Errorout.Errorfquando as asserções falharem.main.go: Execute seus testes manualmente e relate os resultados. Leia o nome do teste a ser executado (borrow_success,borrow_unavailable,borrow_invalid_useroureturn_success). Com base no nome do teste, configure o cenário apropriado e imprimaPASSse todas as asserções passarem, ouFAIL: [reason]se qualquer asserção falhar.
A seguinte entrada será fornecida:
- Um nome de teste:
borrow_success,borrow_unavailable,borrow_invalid_useroureturn_success
Para cada teste, use estes fixtures de teste padrão:
- Livro: ID
B001, TitleGo Programming, AuthorJohn Doe, ISBN123-456 - Usuário: ID
U001, NameAlice, Emailalice@test.com
Por exemplo, dado:
borrow_successSua saída deve ser:
PASSE dado:
borrow_unavailableSua saída deve ser:
PASSE dado:
borrow_invalid_userSua saída deve ser:
PASSE dado:
return_successSua saída deve ser:
PASSPara borrow_success: Crie a biblioteca, adicione o livro e o usuário, empreste o livro, verifique se não há erro, verifique se o livro está indisponível, verifique se o usuário tem o livro em sua lista de emprestados.
Para borrow_unavailable: Crie a biblioteca, adicione o livro e o usuário, defina o Available do livro como false, tente emprestar, verifique se um erro é retornado.
Para borrow_invalid_user: Crie a biblioteca, adicione apenas o livro (sem usuário), tente emprestar com o ID de usuário U001, verifique se um erro é retornado.
Para return_success: Crie a biblioteca, adicione o livro e o usuário, primeiro empreste o livro e depois devolva-o, verifique se não há erro, verifique se o livro está disponível novamente, verifique se a lista de emprestados do usuário está vazia.
Escrever testes garante que seu sistema de biblioteca se comporte corretamente e lhe dá confiança para fazer alterações sem quebrar as funcionalidades existentes!
Experimente você mesmo
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
testName, _ := reader.ReadString('\n')
testName = strings.TrimSpace(testName)
// Fixtures de teste padrão
// Livro: ID "B001", Título "Go Programming", Autor "John Doe", ISBN "123-456"
// Usuário: ID "U001", Nome "Alice", Email "alice@test.com"
switch testName {
case "borrow_success":
// TODO: Testar se o empréstimo de um livro disponível é bem-sucedido
// 1. Criar biblioteca, adicionar livro e usuário
// 2. Emprestar o livro
// 3. Verificar: sem erro, livro indisponível, usuário tem o livro na lista
// Imprimir "PASS" se tudo passar, ou "FAIL: [motivo]" se algum falhar
fmt.Println("FAIL: not implemented")
case "borrow_unavailable":
// TODO: Testar se o empréstimo de um livro indisponível retorna erro
// 1. Criar biblioteca, adicionar livro e usuário
// 2. Definir Available do livro como false
// 3. Tentar emprestar
// 4. Verificar se um erro é retornado
fmt.Println("FAIL: not implemented")
case "borrow_invalid_user":
// TODO: Testar se o empréstimo com usuário inválido retorna erro
// 1. Criar biblioteca, adicionar apenas o livro (sem usuário)
// 2. Tentar emprestar com o ID de usuário "U001"
// 3. Verificar se um erro é retornado
fmt.Println("FAIL: not implemented")
case "return_success":
// TODO: Testar se a devolução de um livro emprestado é bem-sucedida
// 1. Criar biblioteca, adicionar livro e usuário
// 2. Emprestar o livro primeiro
// 3. Devolver o livro
// 4. Verificar: sem erro, livro disponível, lista do usuário vazia
fmt.Println("FAIL: not implemented")
default:
fmt.Println("FAIL: unknown test")
}
}
Todas as lições de Programação Orientada a Objetos
1Fundamentos de OOP em Go
Arquivos ExternosGo Workspace e MódulosPacotes e ImportaçõesNomes Exportados vs Não ExportadosIntrodução a OOP em GoStructs como ClassesDefinindo Métodos em StructsRecebedores de Ponteiro vs ValorInicialização de StructsFunções ConstrutorasRecapitulação - Calculadora Simples4Interfaces
Introdução a InterfacesImplementação ImplícitaInterface como ContratoInterface Vazia (any)Type AssertionType SwitchComposição de InterfacesInterfaces Stringer & ErrorRecapitulação - Calculadora de Formas7Encapsulamento
Campos Exportados vs Não ExportadosEncapsulamento em Nível de PacoteMétodos Getter e SetterOcultação de Informação em GoRecapitulação - Registros de Estudantes10Generics (Go 1.18+)
Introdução a GenericsParâmetros de TipoRestrições de TipoStructs GenéricasSolução Alternativa para Métodos GenéricosRecapitulação - Coleção Genérica2Mergulho Profundo em Tipos e Structs
Tipos Básicos e CompostosDefinições de Tipos PersonalizadosStruct TagsStructs AnônimasStructs AninhadasZero Values e PadrõesRecapitulação - Agenda de Contatos5Composição em vez de Herança
Por que Go não possui HerançaFundamentos de Incorporação de StructsPromoção de MétodosIncorporando Múltiplas StructsIncorporação vs AgregaçãoShadowing de Métodos IncorporadosRecapitulação - Hierarquia de Funcionários8Tratamento de Erros e OOP
A Interface errorTipos de Erro PersonalizadosError Wrapping (fmt.Errorf)Erros Sentinelaerrors.Is() e errors.As()Panic, Defer e RecoverRecapitulação - File Parser3Ponteiros e Memória
Fundamentos de Ponteiros em GoPonteiros para StructsPassagem por Valor vs ReferênciaA Função new()Garbage Collection em GoRecapitulação - Construtor de Lista Encadeada6Polimorfismo em Go
Polimorfismo via InterfacesDuck Typing em GoRegras de Satisfação de InterfaceColeções PolimórficasInjeção de DependênciaRecapitulação - Processador de Pagamentos9Concorrência e OOP
Fundamentos de GoroutinesCanais e ComunicaçãoCanais com Buffer vs. Sem BufferInstrução Selectsync.Mutex e sync.RWMutexsync.WaitGroupDesign de Structs Thread-SafeRecapitulação - Worker Pool12Conceitos Avançados de OOP
Padrão Functional OptionsPadrão Builder em GoEncadeamento de MétodosType Aliases vs DefiniçõesFundamentos de ReflectionVisão Geral de Geração de Código15Projeto: Gerenciamento de Biblioteca
Visão Geral e Estrutura do ProjetoStructs de Livro e Usuário