Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Testes e Mocks em Go: Sobrevivendo com paus e pedras

Testes e Mocks em Go: Sobrevivendo com paus e pedras

Go provê uma recursos bastantes simples para testes, isso pode causar uma dificuldade inicial quando se vai testes de unidade de funções que acessam APIs ou banco de dados, por exemplo.

Como tornar o código mais desacoplado por meio de interfaces e utilizar mocks em Go para que seja possivel abstrair o comportamento interno de funções. Como operam bibliotecas que extendem o Go para que seja possivel mockar conexões HTTP e conexões com o banco de dados.

Palestrante: Cristina Silva. Desenvolvedora full-stack na Stone Pagamentos, participa da criação ferramentas e APIs principalmente em Go, Python e Javascript.

• Categoria: Testes e Tutorial.
• Conhecimento de Go necessário: ★★☆☆☆
• Palavras-chave: #mock #interfaces #testing

Este trabalho está licenciado com uma Licença Creative Commons - Atribuição-NãoComercial-SemDerivações 4.0 Internacional.

Cristina Silva

April 20, 2017
Tweet

More Decks by Cristina Silva

Other Decks in Programming

Transcript

  1. Hello, Go! PROGRAMANDO COM PEDRAS E PAUS. Go é uma

    linguagem sem excessos. Tem estruturas, interfaces e só. 4 MANO DO CÉU, UM PONTEIRO! Alguns dizem que Go lembra Python, outros que Go lembra C. COMUNIDADE? TEM NÃO. Não é do tamanho e força da comunidade de Python, mas vem crescendo, principalmente no exterior. PACKAGE MANAGER? TEM NÃO. Isto é um ponto estranho, há intenções de mudança. GOROOT? GOPATH? Go tem uma estrutura de pastas para trabalho um tanto atípica. GO TOOLS! Ferramentas nativas do Go são uns verdadeiros amorzinhos. COMPILADOR CHATO DO C@#$%~! Sem mais. MODIFICADORES DE ACESSO SIMPLES. Bem simples mesmo.
  2. 5

  3. Teste Raiz package math import "testing" type testpair struct {

    values []float64 average float64 } var tests = []testpair{ { []float64{1,2}, 1.5 }, { []float64{1,1,1,1,1,1}, 1 }, { []float64{-1,1}, 0 }, } func TestAverage(t *testing.T) { for _, pair := range tests { v := Average(pair.values) if v != pair.average { t.Error( "For", pair.values, "expected", pair.average, "got", v, ) } } 6 math_test.go
  4. The answer to life the universe and everything package universe

    // Answer to life, the universe and everything. func Answer() int { return 42 } 8 package universe import "testing" func TestAnswer(t *testing.T) { expected := 43 actual := Answer() if expected != actual { t.Errorf("The anwser should be %d and got %d.", expected, actual) } } universe.go universe_test.go
  5. go test tool Executando todos os arquivos de teste dentro

    de um pacote. λ go test --- FAIL: TestAnswer (0.00s) universe_test.go:10: The anwser should be 43 and got 42. FAIL exit status 1 FAIL github.com/crissilvaeng/goseed/api/universe 0.027s λ go test PASS ok github.com/crissilvaeng/goseed/api/universe 0.038s λ go test -v === RUN TestAnswer --- PASS: TestAnswer (0.00s) PASS ok github.com/crissilvaeng/goseed/api/universe 0.045s 9
  6. go test tool 10 Executando apenas um teste. λ go

    test -run TestAnswer Executando todos os arquivos de teste com a tag integration. λ go test ./... -tags=integration Executando todos os testes dentro de um único arquivo. λ go test universe_test.go universe.go
  7. Test Suite 11 package universe import "testing" func TestAnswers(t *testing.T)

    { t.Run("Answers=42", func(t *testing.T) { expected := 42 actual := Answer() if expected != actual { t.Errorf("The anwser should be %d and got %d.", expected, actual) } }) t.Run("Answers=Batata", func(t *testing.T) { expected := "batata" actual := OtherAnswer() if expected != actual { t.Errorf("The anwser should be %s and got %s.", expected, actual) } }) } universe_test.go
  8. go test tool 12 Executando suite de testes completa. λ

    go test -run Answers Executando apenas teste de resposta 42. λ go test -run /Answers=42 Executando apenas teste de resposta Batata. λ go test -run /Answers=Batata
  9. mock HTTP Httpmock - GET func TestGetAnswer(t *testing.T) { httpmock.Activate()

    defer httpmock.DeactivateAndReset() httpmock.RegisterResponder("GET", "https://localhost:8080/answer", httpmock.NewStringResponder(200, `{"answer": 42}`)) } 14 Httpmock - POST func TestPostAnswer(t *testing.T) { httpmock.Activate() defer httpmock.DeactivateAndReset() httpmock.RegisterResponder("POST", affiliationUrl, httpmock.NewStringResponder(201, `{"answer": 42}`)) }
  10. mock Interface package universe import "github.com/crissilvaeng/goseed/api/universe" var provider Universe func

    init() { provider = new(universe) } func Provider() Universe { return provider } func SetProvider(universe Universe) { provider = universe } type Universe interface { GiveMeTheAnswer() (int, error) } type universe struct{} func (u *universe) GiveMeTheAnswer() (int, error) { return u.Answer() } 15
  11. mock Interface func TestMockingUniverse(t *testing.T) { ctrl := gomock.NewController(t) providerUniverse

    := mock.NewMockUniverse(ctrl) defer ctrl.Finish() providerUniverse.GiveMeTheAnswer().Return(42, nil) universe.SetProvider(providerUniverse) } 17
  12. Credits 19 ▪ Presentation template by SlidesCarnival ▪ Photographs by

    Unsplash ▪ Gopher Stickers by tenntenn ▪ The Go Gopher by Renne French