A API hipotética deverá gerenciar seu acervo pessoal de livros. Ela deve exigir uma autenticação para excluir e atualizar os livros e o restante das operações podem ser públicas.
- Go é uma linguagem de fácil aprendizado.
- Go é minimalista.
- A linguagem Go oferece uma suíte poderosa e simples por padrão para a criação de testes.
- Go oferece performance sem sacrificar produtividade.
Por critério de organização, em nossos testes colocamos o _test na declaração do pacote, para definir um escopo separado de nossas variáveis globais. Podemos configurar e inicializar as nossas depêndecias usando o testmain do Go.
func TestMain(m *testing.M) {
setup()
code := m.Run()
tearDown()
os.Exit(code)
}Para criar um teste em Go apenas escrevemos Test em maiúsculo seguindo com um nome daquilo que precisa ser testado. Você pode rodar o teste de maneira recursiva no diretório, usando:
go test -v ./... Existe uma flag -cover que mostra a cobertura de teste no pacote.
A api fornece suporte a subtestes que é uma excelente maneira de torná seu teste de unidade mais robusto.
func TestSum(t *testing) {
testCases := []struct{
Description string
Number int
Expected int
}{
{"O dobro de 2 deve retornar 4", 2, 4}
}
for _, testCase := range testCases {
t.Run(tesCase.Description, func(t *testing) {
product := twice(testCase.Number)
if testCase.Expected != product {
t.Errorf("Expected %v but got %v", testCase.Expected, product)
}
}
}
}O Example pode ser utilizado para documentar e também testar a função.
func ExampleExportCSV() {
books := []entities.Book{
{ID: 1, Name: "Pequeno Príncipe", Price: 140.30, ISBN: "RERAIA-EIRURJGM-QQIW"},
}
presenters.ExportBookToCSV(books, os.Stdout)
// output:
// 1,Pequeno Príncipe,RERAIA-EIRURJGM-QQIW,140.3
}Nessa API escolhi utilizar alguns princípios da Arquitetura limpa. Na Arquitetura limpa a divisão fica assim:
- Entities - O pacote tem as nossas entidades.
- Repositories - Nossos objetos que vão abstrair o nosso SQL e as particularidades do Banco de dados.
- Usecases - Possui nossa a lógica de negócio da aplicação.
- Presenters - A interface do cliente com a nossa aplicação, possui os controllers que irão gerenciar a forma que o HTTP irá apresentar para o cliente.
Então, cada camada pode ser testada de forma isolada, e simulada utilizando os princípios de injeção de depedência. Podemos testar toda nossa lógica de negócio em usecases e em presenters o status code e a lógica presente no controller.
A linguagem Go é multiparadigma e permite que você utilize high order function o que significa que você pode utilizar uma função como argumento e como retorno de função.
func greet(user User) {
fmt.Printf("Olá %v", user.Name)
}
func main() {
pubSub := pubsub.New()
pubSub.on("new_user", greet)
}Na criação de middleware em Go podemos utilizar o http.HandlerFunc.
// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as HTTP handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler that calls f.
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}Ele é um tipo que na tradução literal permite que funções comuns com a sua assitura implementem a interface http.Handler.
Então a escrita do middleware em Go fica assim.
func hasLogger(handler http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
log.Println(r.Host + r.URL.Path)
handler(w, r)
}
}Ele tem um funcionamento parecido com um decorator mesmo. Então baseando nisso, nós podemos criar também nosso prório tipo chamado Middleware.
type Middleware func(http.HandlerFunc) http.HandlerFuncE extrapolando um pouco mais podemos juntar todos os nosso middlewares no controller fazendo esta função.
func decorate(handler http.HandlerFunc, middlewares ...Middleware) http.HandlerFunc {
for _, middleware := range middlewares {
handler = middleware(handler)
}
return handler
}