From d5b5e5e0b3bd6a66b6717fe5b9e1edd574f7ceb6 Mon Sep 17 00:00:00 2001 From: Lauren Ferreira Date: Wed, 31 Jul 2019 21:40:06 -0300 Subject: [PATCH 1/7] =?UTF-8?q?Inicio=20de=20tradu=C3=A7=C3=A3o=20de=20moc?= =?UTF-8?q?ks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mocking/v1/countdown_test.go | 19 -- mocking/v1/main.go | 16 -- mocks/v1/contagem_test.go | 19 ++ mocks/v1/main.go | 16 ++ {mocking => mocks}/v2/countdown_test.go | 0 {mocking => mocks}/v2/main.go | 0 {mocking => mocks}/v3/countdown_test.go | 0 {mocking => mocks}/v3/main.go | 0 {mocking => mocks}/v4/countdown_test.go | 0 {mocking => mocks}/v4/main.go | 0 {mocking => mocks}/v5/countdown_test.go | 0 {mocking => mocks}/v5/main.go | 0 .../{mocking.md => mocks.md} | 165 +++++++++--------- 13 files changed, 119 insertions(+), 116 deletions(-) delete mode 100644 mocking/v1/countdown_test.go delete mode 100644 mocking/v1/main.go create mode 100644 mocks/v1/contagem_test.go create mode 100644 mocks/v1/main.go rename {mocking => mocks}/v2/countdown_test.go (100%) rename {mocking => mocks}/v2/main.go (100%) rename {mocking => mocks}/v3/countdown_test.go (100%) rename {mocking => mocks}/v3/main.go (100%) rename {mocking => mocks}/v4/countdown_test.go (100%) rename {mocking => mocks}/v4/main.go (100%) rename {mocking => mocks}/v5/countdown_test.go (100%) rename {mocking => mocks}/v5/main.go (100%) rename primeiros-passos-com-go/{mocking.md => mocks.md} (67%) diff --git a/mocking/v1/countdown_test.go b/mocking/v1/countdown_test.go deleted file mode 100644 index affb9dc1..00000000 --- a/mocking/v1/countdown_test.go +++ /dev/null @@ -1,19 +0,0 @@ -package main - -import ( - "bytes" - "testing" -) - -func TestCountdown(t *testing.T) { - buffer := &bytes.Buffer{} - - Countdown(buffer) - - got := buffer.String() - want := "3" - - if got != want { - t.Errorf("got '%s' want '%s'", got, want) - } -} diff --git a/mocking/v1/main.go b/mocking/v1/main.go deleted file mode 100644 index 4613c0a6..00000000 --- a/mocking/v1/main.go +++ /dev/null @@ -1,16 +0,0 @@ -package main - -import ( - "fmt" - "io" - "os" -) - -// Countdown prints a countdown from 5 to out -func Countdown(out io.Writer) { - fmt.Fprint(out, "3") -} - -func main() { - Countdown(os.Stdout) -} diff --git a/mocks/v1/contagem_test.go b/mocks/v1/contagem_test.go new file mode 100644 index 00000000..e75f9227 --- /dev/null +++ b/mocks/v1/contagem_test.go @@ -0,0 +1,19 @@ +package main + +import ( + "bytes" + "testing" +) + +func TestContagem(t *testing.T) { + buffer := &bytes.Buffer{} + + Contagem(buffer) + + resultado := buffer.String() + esperado := "3" + + if resultado != esperado { + t.Errorf("resultado '%s', esperado '%s'", resultado, esperado) + } +} diff --git a/mocks/v1/main.go b/mocks/v1/main.go new file mode 100644 index 00000000..24ad93f2 --- /dev/null +++ b/mocks/v1/main.go @@ -0,0 +1,16 @@ +package main + +import ( + "fmt" + "io" + "os" +) + +// Contagem imprime uma contagem de 3 para a sáida +func Contagem(saida io.Writer) { + fmt.Fprint(saida, "3") +} + +func main() { + Contagem(os.Stdout) +} diff --git a/mocking/v2/countdown_test.go b/mocks/v2/countdown_test.go similarity index 100% rename from mocking/v2/countdown_test.go rename to mocks/v2/countdown_test.go diff --git a/mocking/v2/main.go b/mocks/v2/main.go similarity index 100% rename from mocking/v2/main.go rename to mocks/v2/main.go diff --git a/mocking/v3/countdown_test.go b/mocks/v3/countdown_test.go similarity index 100% rename from mocking/v3/countdown_test.go rename to mocks/v3/countdown_test.go diff --git a/mocking/v3/main.go b/mocks/v3/main.go similarity index 100% rename from mocking/v3/main.go rename to mocks/v3/main.go diff --git a/mocking/v4/countdown_test.go b/mocks/v4/countdown_test.go similarity index 100% rename from mocking/v4/countdown_test.go rename to mocks/v4/countdown_test.go diff --git a/mocking/v4/main.go b/mocks/v4/main.go similarity index 100% rename from mocking/v4/main.go rename to mocks/v4/main.go diff --git a/mocking/v5/countdown_test.go b/mocks/v5/countdown_test.go similarity index 100% rename from mocking/v5/countdown_test.go rename to mocks/v5/countdown_test.go diff --git a/mocking/v5/main.go b/mocks/v5/main.go similarity index 100% rename from mocking/v5/main.go rename to mocks/v5/main.go diff --git a/primeiros-passos-com-go/mocking.md b/primeiros-passos-com-go/mocks.md similarity index 67% rename from primeiros-passos-com-go/mocking.md rename to primeiros-passos-com-go/mocks.md index 7e0a31bd..1fb83d47 100644 --- a/primeiros-passos-com-go/mocking.md +++ b/primeiros-passos-com-go/mocks.md @@ -1,117 +1,121 @@ # Mocking -[**You can find all the code for this chapter here**](https://github.com/quii/learn-go-with-tests/tree/master/mocking) +[**Você pode encontrar todos os códigos para esse capítulo aqui**](https://github.com/larien/learn-go-with-tests/tree/master/mocks) -You have been asked to write a program which counts from 3, printing each number on a new line \(with a 1 second pause\) and when it reaches zero it will print "Go!" and exit. +Te pediram para criar um programa que conta a partir de 3, imprimindo cada número em uma linha nova (com um segundo intervalo entre cada uma) e quando chega a zero, imprime "Vai!" e sai. ```text 3 2 1 -Go! +Vai! ``` -We'll tackle this by writing a function called `Countdown` which we will then put inside a `main` program so it looks something like this: +Vamos resolver isso escrevendo uma função chamada `Contagem` que vamos colocar dentro de um programa `main` e se parecer com algo assim: ```go package main func main() { - Countdown() + Contagem() } ``` -While this is a pretty trivial program, to test it fully we will need as always to take an _iterative_, _test-driven_ approach. +Apesar de ser um programa simples, para testá-lo completamente vamos precisar, como de costume, de uma abordagem _iterativa_ e _orientada a testes_. -What do I mean by iterative? We make sure we take the smallest steps we can to have _useful software_. +Mas o que quero dizer com iterativa? Precisamos ter certeza de que tomamos os menores passos que pudermos para ter um _software_ útil. -We dont want to spend a long time with code that will theoretically work after some hacking because that's often how developers fall down rabbit holes. **It's an important skill to be able to slice up requirements as small as you can so you can have** _**working software**_**.** +Não queremos passar muito tempo com código que vai funcionar hora ou outra após alguma implementação mirabolante, porque é assim que os desenvolvedores caem em armadilhas. **É importante ser capaz de dividir os requerimentos da menor forma que conseguir para você ter um** _**software funcionando**_**.** -Here's how we can divide our work up and iterate on it: +Podemos separar essa tarefa da seguinte forma: -* Print 3 -* Print 3 to Go! -* Wait a second between each line +- Imprimir 3 +- Imprimir de 3 para Vai! +- Esperar um segundo entre cada linha -## Write the test first +## Escreva o teste primeiro -Our software needs to print to stdout and we saw how we could use DI to facilitate testing this in the DI section. +Nosso software precisa imprimir para a saída. Vimos como podemos usar a injeção de dependência para facilitar nosso teste na [seção anterior](https://github.com/larien/learn-go-with-tests/tree/master/primeiros-passos-com-go/injecao-de-dependencia.md). ```go -func TestCountdown(t *testing.T) { +func TestContagem(t *testing.T) { buffer := &bytes.Buffer{} - Countdown(buffer) + Contagem(buffer) - got := buffer.String() - want := "3" + resultado := buffer.String() + esperado := "3" - if got != want { - t.Errorf("got '%s' want '%s'", got, want) + if resultado != esperado { + t.Errorf("resultado '%s', esperado '%s'", resultado, esperado) } } ``` -If anything like `buffer` is unfamiliar to you, re-read [the previous section](dependency-injection.md). +Se tiver dúvidas sobre o `buffer`, leia a [seção anterior](https://github.com/larien/learn-go-with-tests/tree/master/primeiros-passos-com-go/injecao-de-dependencia.md) novamente. -We know we want our `Countdown` function to write data somewhere and `io.Writer` is the de-facto way of capturing that as an interface in Go. +Sabemos que nossa função `Contagem` precisa escrever dados em algum lugar e o `io.Writer` é a forma de capturarmos essa saída como uma interface em Go. -* In `main` we will send to `os.Stdout` so our users see the countdown printed to the terminal. -* In test we will send to `bytes.Buffer` so our tests can capture what data is being generated. +- Na `main`, vamos enviar o `os.Stdout` como parâmetro para nossos usuários verem a contagem regressiva impressa no terminal. +- No teste, vamos enviar o `bytes.Buffer` como parâmetro para que nossos testes possam capturar que dado está sendo gerado. -## Try and run the test +## Execute o teste -`./countdown_test.go:11:2: undefined: Countdown` +`./contagem_test.go:11:2: undefined: Contagem` -## Write the minimal amount of code for the test to run and check the failing test output +`indefinido: Contagem` -Define `Countdown` +## Escreva o mínimo de código possível para fazer o teste rodar e verifique a saída do teste que tiver falhado + +Defina `Contagem`: ```go -func Countdown() {} +func Contagem() {} ``` -Try again +Tente novamente: ```go -./countdown_test.go:11:11: too many arguments in call to Countdown +./contagem_test.go:11:11: too many arguments in call to Countdown have (*bytes.Buffer) want () ``` -The compiler is telling you what your function signature could be, so update it. +`argumentos demais na chamada para Contagem` + +O compilador está te dizendo como a assinatura da função deve ser, então é só atualizá-la. ```go -func Countdown(out *bytes.Buffer) {} +func Contagem(saida *bytes.Buffer) {} ``` -`countdown_test.go:17: got '' want '3'` +`contagem_test.go:17: resultado '', esperado '3'` -Perfect! +Perfeito! -## Write enough code to make it pass +## Escreva código o suficiente para fazer o teste passar ```go -func Countdown(out *bytes.Buffer) { - fmt.Fprint(out, "3") +func Contagem(saida *bytes.Buffer) { + fmt.Fprint(saida, "3") } ``` -We're using `fmt.Fprint` which takes an `io.Writer` \(like `*bytes.Buffer`\) and sends a `string` to it. The test should pass. +Estamos usando `fmt.Fprint`, o que significa que ele recebe um `io.Writer` (como `*bytes.Buffer`) e envia uma `string` para ele. O teste deve passar. -## Refactor +## Refatoração -We know that while `*bytes.Buffer` works, it would be better to use a general purpose interface instead. +Agora sabemos que, apesar do `*bytes.Buffer` funcionar, seria melhor ter uma interface de propósito geral ao invés disso. ```go -func Countdown(out io.Writer) { - fmt.Fprint(out, "3") +func Contagem(saida io.Writer) { + fmt.Fprint(saida, "3") } ``` -Re-run the tests and they should be passing. +Execute os testes novamente e eles devem passar. -To complete matters, let's now wire up our function into a `main` so we have some working software to reassure ourselves we're making progress. +Só para finalizar, vamos colocar nossa função dentro da `main` para que possamos executar o software para nos assegurarmos de que estamos progredindo. ```go package main @@ -122,12 +126,12 @@ import ( "os" ) -func Countdown(out io.Writer) { - fmt.Fprint(out, "3") +func Contagem(saida io.Writer) { + fmt.Fprint(saida, "3") } func main() { - Countdown(os.Stdout) + Contagem(os.Stdout) } ``` @@ -221,11 +225,11 @@ If you run the program it works as we want it to. The tests still pass and the software works as intended but we have some problems: -* Our tests take 4 seconds to run. - * Every forward thinking post about software development emphasises the importance of quick feedback loops. - * **Slow tests ruin developer productivity**. - * Imagine if the requirements get more sophisticated warranting more tests. Are we happy with 4s added to the test run for every new test of `Countdown`? -* We have not tested an important property of our function. +- Our tests take 4 seconds to run. + - Every forward thinking post about software development emphasises the importance of quick feedback loops. + - **Slow tests ruin developer productivity**. + - Imagine if the requirements get more sophisticated warranting more tests. Are we happy with 4s added to the test run for every new test of `Countdown`? +- We have not tested an important property of our function. We have a dependency on `Sleep`ing which we need to extract so we can then control it in our tests. @@ -357,13 +361,13 @@ There's still another important property we haven't tested. `Countdown` should sleep before each print, e.g: -* `Sleep` -* `Print N` -* `Sleep` -* `Print N-1` -* `Sleep` -* `Print Go!` -* etc +- `Sleep` +- `Print N` +- `Sleep` +- `Print N-1` +- `Sleep` +- `Print Go!` +- etc Our latest change only asserts that it has slept 4 times, but those sleeps could occur out of sequence. @@ -581,12 +585,12 @@ People normally get in to a bad state when they don't _listen to their tests_ an If your mocking code is becoming complicated or you are having to mock out lots of things to test something, you should _listen_ to that bad feeling and think about your code. Usually it is a sign of -* The thing you are testing is having to do too many things - * Break the module apart so it does less -* Its dependencies are too fine-grained - * Think about how you can consolidate some of these dependencies into one meaningful module -* Your test is too concerned with implementation details - * Favour testing expected behaviour rather than the implementation +- The thing you are testing is having to do too many things + - Break the module apart so it does less +- Its dependencies are too fine-grained + - Think about how you can consolidate some of these dependencies into one meaningful module +- Your test is too concerned with implementation details + - Favour testing expected behaviour rather than the implementation Normally a lot of mocking points to _bad abstraction_ in your code. @@ -596,20 +600,20 @@ Normally a lot of mocking points to _bad abstraction_ in your code. Ever run into this situation? -* You want to do some refactoring -* To do this you end up changing lots of tests -* You question TDD and make a post on Medium titled "Mocking considered harmful" +- You want to do some refactoring +- To do this you end up changing lots of tests +- You question TDD and make a post on Medium titled "Mocking considered harmful" This is usually a sign of you testing too much _implementation detail_. Try to make it so your tests are testing _useful behaviour_ unless the implementation is really important to how the system runs. It is sometimes hard to know _what level_ to test exactly but here are some thought processes and rules I try to follow: -* **The definition of refactoring is that the code changes but the behaviour stays the same**. If you have decided to do some refactoring in theory you should be able to do make the commit without any test changes. So when writing a test ask yourself - * Am i testing the behaviour I want or the implementation details? - * If i were to refactor this code, would I have to make lots of changes to the tests? -* Although Go lets you test private functions, I would avoid it as private functions are to do with implementation. -* I feel like if a test is working with **more than 3 mocks then it is a red flag** - time for a rethink on the design -* Use spies with caution. Spies let you see the insides of the algorithm you are writing which can be very useful but that means a tighter coupling between your test code and the implementation. **Be sure you actually care about these details if you're going to spy on them** +- **The definition of refactoring is that the code changes but the behaviour stays the same**. If you have decided to do some refactoring in theory you should be able to do make the commit without any test changes. So when writing a test ask yourself + - Am i testing the behaviour I want or the implementation details? + - If i were to refactor this code, would I have to make lots of changes to the tests? +- Although Go lets you test private functions, I would avoid it as private functions are to do with implementation. +- I feel like if a test is working with **more than 3 mocks then it is a red flag** - time for a rethink on the design +- Use spies with caution. Spies let you see the insides of the algorithm you are writing which can be very useful but that means a tighter coupling between your test code and the implementation. **Be sure you actually care about these details if you're going to spy on them** As always, rules in software development aren't really rules and there can be exceptions. [Uncle Bob's article of "When to mock"](https://8thlight.com/blog/uncle-bob/2014/05/10/WhenToMock.html) has some excellent pointers. @@ -617,8 +621,8 @@ As always, rules in software development aren't really rules and there can be ex ### More on TDD approach -* When faced with less trivial examples, break the problem down into "thin vertical slices". Try to get to a point where you have _working software backed by tests_ as soon as you can, to avoid getting in rabbit holes and taking a "big bang" approach. -* Once you have some working software it should be easier to _iterate with small steps_ until you arrive at the software you need. +- When faced with less trivial examples, break the problem down into "thin vertical slices". Try to get to a point where you have _working software backed by tests_ as soon as you can, to avoid getting in rabbit holes and taking a "big bang" approach. +- Once you have some working software it should be easier to _iterate with small steps_ until you arrive at the software you need. > "When to use iterative development? You should use iterative development only on projects that you want to succeed." @@ -626,11 +630,10 @@ Martin Fowler. ### Mocking -* **Without mocking important areas of your code will be untested**. In our case we would not be able to test that our code paused between each print but there are countless other examples. Calling a service that _can_ fail? Wanting to test your system in a particular state? It is very hard to test these scenarios without mocking. -* Without mocks you may have to set up databases and other third parties things just to test simple business rules. You're likely to have slow tests, resulting in **slow feedback loops**. -* By having to spin up a database or a webservice to test something you're likely to have **fragile tests** due to the unreliability of such services. +- **Without mocking important areas of your code will be untested**. In our case we would not be able to test that our code paused between each print but there are countless other examples. Calling a service that _can_ fail? Wanting to test your system in a particular state? It is very hard to test these scenarios without mocking. +- Without mocks you may have to set up databases and other third parties things just to test simple business rules. You're likely to have slow tests, resulting in **slow feedback loops**. +- By having to spin up a database or a webservice to test something you're likely to have **fragile tests** due to the unreliability of such services. Once a developer learns about mocking it becomes very easy to over-test every single facet of a system in terms of the _way it works_ rather than _what it does_. Always be mindful about **the value of your tests** and what impact they would have in future refactoring. In this post about mocking we have only covered **Spies** which are a kind of mock. There are different kind of mocks. [Uncle Bob explains the types in a very easy to read article](https://8thlight.com/blog/uncle-bob/2014/05/14/TheLittleMocker.html). In later chapters we will need to write code that depends on others for data, which is where we will show **Stubs** in action. - From f7e941901d4f17213863a512b8ee0c43661c5839 Mon Sep 17 00:00:00 2001 From: Lauren Ferreira Date: Fri, 2 Aug 2019 19:59:33 -0300 Subject: [PATCH 2/7] =?UTF-8?q?Tradu=C3=A7=C3=A3o=20at=C3=A9=20spy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mocks/v2/contagem_test.go | 21 ++++ mocks/v2/countdown_test.go | 22 ---- mocks/v2/main.go | 16 +-- mocks/v3/contagem_test.go | 35 ++++++ mocks/v3/countdown_test.go | 35 ------ mocks/v3/main.go | 28 ++--- primeiros-passos-com-go/mocks.md | 205 ++++++++++++++++--------------- 7 files changed, 181 insertions(+), 181 deletions(-) create mode 100644 mocks/v2/contagem_test.go delete mode 100644 mocks/v2/countdown_test.go create mode 100644 mocks/v3/contagem_test.go delete mode 100644 mocks/v3/countdown_test.go diff --git a/mocks/v2/contagem_test.go b/mocks/v2/contagem_test.go new file mode 100644 index 00000000..6ac583b1 --- /dev/null +++ b/mocks/v2/contagem_test.go @@ -0,0 +1,21 @@ +package main + +import ( + "bytes" + "testing" +) + +func TestContagem(t *testing.T) { + buffer := &bytes.Buffer{} + + Contagem(buffer) + + resultado := buffer.String() + esperado := `3 +2 +1 +Vai!` + if resultado != esperado { + t.Errorf("resultado '%s', esperado '%s'", resultado, esperado) + } +} diff --git a/mocks/v2/countdown_test.go b/mocks/v2/countdown_test.go deleted file mode 100644 index a9a53d3c..00000000 --- a/mocks/v2/countdown_test.go +++ /dev/null @@ -1,22 +0,0 @@ -package main - -import ( - "bytes" - "testing" -) - -func TestCountdown(t *testing.T) { - buffer := &bytes.Buffer{} - - Countdown(buffer) - - got := buffer.String() - want := `3 -2 -1 -Go!` - - if got != want { - t.Errorf("got '%s' want '%s'", got, want) - } -} diff --git a/mocks/v2/main.go b/mocks/v2/main.go index c78301d0..fd1159d0 100644 --- a/mocks/v2/main.go +++ b/mocks/v2/main.go @@ -6,17 +6,17 @@ import ( "os" ) -const finalWord = "Go!" -const countdownStart = 3 +const ultimaPalavra = "Vai!" +const inicioContagem = 3 -// Countdown prints a countdown from 5 to out -func Countdown(out io.Writer) { - for i := countdownStart; i > 0; i-- { - fmt.Fprintln(out, i) +// Contagem imprime uma contagem de 3 para a sáida +func Contagem(saida io.Writer) { + for i := inicioContagem; i > 0; i-- { + fmt.Fprintln(saida, i) } - fmt.Fprint(out, finalWord) + fmt.Fprint(saida, ultimaPalavra) } func main() { - Countdown(os.Stdout) + Contagem(os.Stdout) } diff --git a/mocks/v3/contagem_test.go b/mocks/v3/contagem_test.go new file mode 100644 index 00000000..5b47a803 --- /dev/null +++ b/mocks/v3/contagem_test.go @@ -0,0 +1,35 @@ +package main + +import ( + "bytes" + "testing" +) + +func TestContagem(t *testing.T) { + buffer := &bytes.Buffer{} + sleeperSpy := &SleeperSpy{} + + Contagem(buffer, sleeperSpy) + + resultado := buffer.String() + esperado := `3 +2 +1 +Vai!` + + if resultado != esperado { + t.Errorf("resultado '%s', esperado '%s'", resultado, esperado) + } + + if sleeperSpy.Chamadas != 4 { + t.Errorf("não houve chamadas suficientes do sleeper, esperado 4, resultado %d", sleeperSpy.Chamadas) + } +} + +type SleeperSpy struct { + Chamadas int +} + +func (s *SleeperSpy) Sleep() { + s.Chamadas++ +} diff --git a/mocks/v3/countdown_test.go b/mocks/v3/countdown_test.go deleted file mode 100644 index ad93233b..00000000 --- a/mocks/v3/countdown_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package main - -import ( - "bytes" - "testing" -) - -func TestCountdown(t *testing.T) { - buffer := &bytes.Buffer{} - spySleeper := &SpySleeper{} - - Countdown(buffer, spySleeper) - - got := buffer.String() - want := `3 -2 -1 -Go!` - - if got != want { - t.Errorf("got '%s' want '%s'", got, want) - } - - if spySleeper.Calls != 4 { - t.Errorf("not enough calls to sleeper, want 4 got %d", spySleeper.Calls) - } -} - -type SpySleeper struct { - Calls int -} - -func (s *SpySleeper) Sleep() { - s.Calls++ -} diff --git a/mocks/v3/main.go b/mocks/v3/main.go index 1957f126..e7047e69 100644 --- a/mocks/v3/main.go +++ b/mocks/v3/main.go @@ -7,34 +7,34 @@ import ( "time" ) -// Sleeper allows you to put delays +// Sleeper te permite definir atrasos type Sleeper interface { Sleep() } -// DefaultSleeper is an implementation of Sleeper with a predefined delay -type DefaultSleeper struct{} +// SleeperPadrao é uma implementação de Sleeper com um atraso pré-definido +type SleeperPadrao struct{} -// Sleep will pause execution for the defined Duration -func (d *DefaultSleeper) Sleep() { +// Sleep vai pausar a execução pela Duração definida +func (d *SleeperPadrao) Sleep() { time.Sleep(1 * time.Second) } -const finalWord = "Go!" -const countdownStart = 3 +const ultimaPalavra = "Vai!" +const inicioContagem = 3 -// Countdown prints a countdown from 5 to out with a delay between count provided by Sleeper -func Countdown(out io.Writer, sleeper Sleeper) { - for i := countdownStart; i > 0; i-- { +// Contagem imprime uma contagem de 3 para a sáida com um atraso determinado por um Sleeper +func Contagem(saida io.Writer, sleeper Sleeper) { + for i := inicioContagem; i > 0; i-- { sleeper.Sleep() - fmt.Fprintln(out, i) + fmt.Fprintln(saida, i) } sleeper.Sleep() - fmt.Fprint(out, finalWord) + fmt.Fprint(saida, ultimaPalavra) } func main() { - sleeper := &DefaultSleeper{} - Countdown(os.Stdout, sleeper) + sleeper := &SleeperPadrao{} + Contagem(os.Stdout, sleeper) } diff --git a/primeiros-passos-com-go/mocks.md b/primeiros-passos-com-go/mocks.md index 1fb83d47..05883b7c 100644 --- a/primeiros-passos-com-go/mocks.md +++ b/primeiros-passos-com-go/mocks.md @@ -135,109 +135,108 @@ func main() { } ``` -Try and run the program and be amazed at your handywork. +Execute o programa e surpreenda-se com seu trabalho. -Yes this seems trivial but this approach is what I would recommend for any project. **Take a thin slice of functionality and make it work end-to-end, backed by tests.** +Apesar de parecer simples, essa é a abordagem que recomendo para qualquer projeto. **Escolher uma pequena parte da funcionalidade e fazê-la funcionar do começo ao fim com apoio de testes.** -Next we can make it print 2,1 and then "Go!". +Depois, precisamos fazer o software imprimir 2, 1 e então "Vai!". -## Write the test first +## Escreva o teste primeiro -By investing in getting the overall plumbing working right, we can iterate on our solution safely and easily. We will no longer need to stop and re-run the program to be confident of it working as all the logic is tested. +Após investirmos tempo e esforço para fazer o principal funcionar, podemos iterar nossa solução com segurança e de forma simples. Não vamos mais precisar para parar e executar o programa novamente para ter confiança de que ele está funcionando, desde que a lógica esteja testada. ```go -func TestCountdown(t *testing.T) { +func TestContagem(t *testing.T) { buffer := &bytes.Buffer{} - Countdown(buffer) + Contagem(buffer) - got := buffer.String() - want := `3 + resultado := buffer.String() + esperado := `3 2 1 -Go!` - - if got != want { - t.Errorf("got '%s' want '%s'", got, want) +Vai!` + if resultado != esperado { + t.Errorf("resultado '%s', esperado '%s'", resultado, esperado) } } ``` -The backtick syntax is another way of creating a `string` but lets you put things like newlines which is perfect for our test. +A sintaxe de aspas simples é outra forma de criar uma `string`, mas te permite colocar coisas como linhas novas, o que é perfeito para nosso teste. -## Try and run the test +## Execute o teste -```text -countdown_test.go:21: got '3' want '3 +```bash +contagem_test.go:21: resultado '3', esperado '3 2 1 - Go!' + Vai!' ``` -## Write enough code to make it pass +## Escreva código o suficiente para fazer o teste passar ```go -func Countdown(out io.Writer) { +func Contagem(saida io.Writer) { for i := 3; i > 0; i-- { - fmt.Fprintln(out, i) + fmt.Fprintln(saida, i) } - fmt.Fprint(out, "Go!") + fmt.Fprint(saida, "Go!") } ``` -Use a `for` loop counting backwards with `i--` and use `fmt.Fprintln` to print to `out` with our number followed by a newline character. Finally use `fmt.Fprint` to send "Go!" aftward. +Usamos um laço `for` fazendo contagem regressiva com `i--` e depois `fmt.Fprintln` para imprimir a `saida` com nosso número seguro por um caracter de nova linha. Finalmente, usamos o `fmt.Fprint` para enviar "Vai!" no final. -## Refactor +## Refatoração -There's not much to refactor other than refactoring some magic values into named constants. +Não há muito para refatorar além de transformar alguns valores mágicos em constantes com nomes descritivos. ```go -const finalWord = "Go!" -const countdownStart = 3 +const ultimaPalavra = "Go!" +const inicioContagem = 3 -func Countdown(out io.Writer) { - for i := countdownStart; i > 0; i-- { - fmt.Fprintln(out, i) +func Contagem(saida io.Writer) { + for i := inicioContagem; i > 0; i-- { + fmt.Fprintln(saida, i) } - fmt.Fprint(out, finalWord) + fmt.Fprint(saida, ultimaPalavra) } ``` -If you run the program now, you should get the desired output but we don't have it as a dramatic countdown with the 1 second pauses. +Se executar o programa agora, você deve obter a saída de sejada, mas não tem uma contagem regressiva dramática com as pausas de 1 segundo. -Go let's you achieve this with `time.Sleep`. Try adding it in to our code. +Go te permite obter isso com `time.Sleep`. Tente adicionar essa função ao seu código. ```go -func Countdown(out io.Writer) { - for i := countdownStart; i > 0; i-- { +func Contagem(saida io.Writer) { + for i := inicioContagem; i > 0; i-- { time.Sleep(1 * time.Second) - fmt.Fprintln(out, i) + fmt.Fprintln(saida, i) } time.Sleep(1 * time.Second) - fmt.Fprint(out, finalWord) + fmt.Fprint(saida, ultimaPalavra) } ``` -If you run the program it works as we want it to. +Se você executar o programa, ele funciona conforme esperado. -## Mocking +## Mock -The tests still pass and the software works as intended but we have some problems: +Os testes ainda vão passar e o software funciona como planejado, mas temos alguns problemas: -- Our tests take 4 seconds to run. - - Every forward thinking post about software development emphasises the importance of quick feedback loops. - - **Slow tests ruin developer productivity**. - - Imagine if the requirements get more sophisticated warranting more tests. Are we happy with 4s added to the test run for every new test of `Countdown`? -- We have not tested an important property of our function. +- Nossos testes levam 4 segundos para rodar. + - Todo conteúdo gerado sobre desenvolvimento de software enfatiza a importância de loops de feedback rápidos. + - **Testes lentos arruinam a produtividade do desenvolvedor**. + - Imagine se os requerimentos ficam mais sofisticados, gerando a necessidade de mais testes. É viável adicionar 4s para cada teste novo de `Contagem`? +- Não testamos uma propriedade importante da nossa função. -We have a dependency on `Sleep`ing which we need to extract so we can then control it in our tests. +Temos uma dependência no `Sleep` que precisamos extrair para podermos controlá-la nos nossos testes. -If we can _mock_ `time.Sleep` we can use _dependency injection_ to use it instead of a "real" `time.Sleep` and then we can **spy on the calls** to make assertions on them. +Se conseguirmos _mockar_ o `time.Sleep`, podemos usar a _injeção de dependências_ para usá-lo ao invés de um `time.Sleep` "de verdade", e então podemos **verificar as chamadas** para certificar de que estão corretas. -## Write the test first +## Escreva o teste primeiro -Let's define our dependency as an interface. This lets us then use a _real_ Sleeper in `main` and a _spy sleeper_ in our tests. By using an interface our `Countdown` function is oblivious to this and adds some flexibility for the caller. +Vamos definir nossa dependência como uma interface. Isso nos permite usar um Sleeper _de verdade_ em `main` e um _sleeper spy_ nos nossos testes. Usar uma interface na nossa função `Contagem` é essencial para isso e dá certa flexibilidade à função que a chamar. ```go type Sleeper interface { @@ -245,133 +244,135 @@ type Sleeper interface { } ``` -I made a design decision that our `Countdown` function would not be responsible for how long the sleep is. This simplifies our code a little for now at least and means a user of our function can configure that sleepiness however they like. +Tomei uma decisão de design que nossa função `Contagem` não seria responsável por quanto tempo o sleep leva. Isso simplifica um pouco nosso código, pelo menos por enquanto, e significa que um usuário da nossa função pode configurar a duração desse tempo como preferir. -Now we need to make a _mock_ of it for our tests to use. +Agora precisamos criar um _mock_ disso para usarmos nos nossos testes. ```go -type SpySleeper struct { - Calls int +type SleeperSpy struct { + Chamadas int } -func (s *SpySleeper) Sleep() { - s.Calls++ +func (s *SleeperSpy) Sleep() { + s.Chamadas++ } ``` -_Spies_ are a kind of _mock_ which can record how a dependency is used. They can record the arguments sent in, how many times, etc. In our case, we're keeping track of how many times `Sleep()` is called so we can check it in our test. +_Spies_ (espiões) são um tipo de _mock_ em que podemos gravar como uma dependência é usada. Eles podem gravar os argumentos definidos, quantas vezes são usados etc. No nosso caso, vamos manter o controle de quantas vezes `Sleep()` é chamada para verificá-la no nosso teste. -Update the tests to inject a dependency on our Spy and assert that the sleep has been called 4 times. +Atualize os testes para injetar uma dependência no nosso Espião e verifique se o sleep foi chamado 4 vezes. ```go -func TestCountdown(t *testing.T) { +func TestContagem(t *testing.T) { buffer := &bytes.Buffer{} - spySleeper := &SpySleeper{} + sleeperSpy := &SleeperSpy{} - Countdown(buffer, spySleeper) + Contagem(buffer, sleeperSpy) - got := buffer.String() - want := `3 + resultado := buffer.String() + esperado := `3 2 1 -Go!` +Vai!` - if got != want { - t.Errorf("got '%s' want '%s'", got, want) + if resultado != esperado { + t.Errorf("resultado '%s', esperado '%s'", resultado, esperado) } - if spySleeper.Calls != 4 { - t.Errorf("not enough calls to sleeper, want 4 got %d", spySleeper.Calls) + if sleeperSpy.Chamadas != 4 { + t.Errorf("não houve chamadas suficientes do sleeper, esperado 4, resultado %d", sleeperSpy.Chamadas) } } ``` -## Try and run the test +## Execute o teste -```text -too many arguments in call to Countdown +```bash +too many arguments in call to Contagem have (*bytes.Buffer, *SpySleeper) want (io.Writer) ``` -## Write the minimal amount of code for the test to run and check the failing test output +## Escreva o mínimo de código possível para fazer o teste rodar e verifique a saída do teste que tiver falhado -We need to update `Countdown` to accept our `Sleeper` +Precisamos atualizar a `Contagem` para aceitar nosso `Sleeper`: ```go -func Countdown(out io.Writer, sleeper Sleeper) { - for i := countdownStart; i > 0; i-- { +func Contagem(saida io.Writer, sleeper Sleeper) { + for i := inicioContagem; i > 0; i-- { time.Sleep(1 * time.Second) - fmt.Fprintln(out, i) + fmt.Fprintln(saida, i) } time.Sleep(1 * time.Second) - fmt.Fprint(out, finalWord) + fmt.Fprint(saida, ultimaPalavra) } ``` -If you try again, your `main` will no longer compile for the same reason +Se tentar novamente, nossa `main` não vai mais compilar pelo menos motivo: ```text -./main.go:26:11: not enough arguments in call to Countdown +./main.go:26:11: not enough arguments in call to Contagem have (*os.File) want (io.Writer, Sleeper) ``` -Let's create a _real_ sleeper which implements the interface we need +Vamos criar um sleeper _de verdade_ que implementa a interface que precisamos: ```go -type DefaultSleeper struct {} +type SleeperPadrao struct {} -func (d *DefaultSleeper) Sleep() { - time.Sleep(1 * time.Second) +func (d *SleeperPadrao) Sleep() { + time.Sleep(1 * time.Second) } ``` -We can then use it in our real application like so +Podemos usá-lo na nossa aplicação real, como: ```go func main() { - sleeper := &DefaultSleeper{} - Countdown(os.Stdout, sleeper) + sleeper := &SleeperPadrao{} + Contagem(os.Stdout, sleeper) } ``` -## Write enough code to make it pass +## Escreva código o suficiente para fazer o teste passar + +Agora o teste está compilando, mas não passando. Isso acontece porque ainda estamos chamando o `time.Sleep` ao invés da injetada. Vamos arrumar isso. The test is now compiling but not passing because we're still calling the `time.Sleep` rather than the injected in dependency. Let's fix that. ```go -func Countdown(out io.Writer, sleeper Sleeper) { - for i := countdownStart; i > 0; i-- { +func Contagem(saida io.Writer, sleeper Sleeper) { + for i := inicioContagem; i > 0; i-- { sleeper.Sleep() - fmt.Fprintln(out, i) + fmt.Fprintln(saida, i) } sleeper.Sleep() - fmt.Fprint(out, finalWord) + fmt.Fprint(saida, ultimaPalavra) } ``` -The test should pass and no longer taking 4 seconds. +O teste deve passar sem levar 4 segundos. -### Still some problems +### Ainda temos alguns problemas -There's still another important property we haven't tested. +Ainda há outra propriedade importante que não estamos testando. -`Countdown` should sleep before each print, e.g: +A `Contagem` deve ter uma pausa para cada impressão, como por exemplo: -- `Sleep` -- `Print N` -- `Sleep` -- `Print N-1` -- `Sleep` -- `Print Go!` +- `Pausa` +- `Imprime N` +- `Pausa` +- `Imprime N-1` +- `Pausa` +- `Imprime Vai!` - etc -Our latest change only asserts that it has slept 4 times, but those sleeps could occur out of sequence. +Nossa alteração mais recente só verifica se o software teve 4 pausas, mas essas pausas poderiam ocorrer fora de ordem. -When writing tests if you're not confident that your tests are giving you sufficient confidence, just break it! \(make sure you have committed your changes to source control first though\). Change the code to the following +Quando escrevemos testes, se não estiver confiante de que seus testes estão te dando confiança o suficiente, quebre-o (mas certifique-se de que você salvou suas alterações antes)! Mude o código para o seguinte: ```go func Countdown(out io.Writer, sleeper Sleeper) { From 38d2654ed4cbeee424d861c6847c199234deb09b Mon Sep 17 00:00:00 2001 From: Lauren Ferreira Date: Fri, 2 Aug 2019 20:25:12 -0300 Subject: [PATCH 3/7] =?UTF-8?q?Tradu=C3=A7=C3=A3o=20at=C3=A9=20teste=20de?= =?UTF-8?q?=20ordem?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mocks/v3/contagem_test.go | 2 +- mocks/v3/main.go | 12 +-- mocks/v4/contagem_test.go | 61 ++++++++++++++ mocks/v4/countdown_test.go | 61 -------------- mocks/v4/main.go | 35 ++++---- primeiros-passos-com-go/mocks.md | 137 ++++++++++++++++--------------- 6 files changed, 154 insertions(+), 154 deletions(-) create mode 100644 mocks/v4/contagem_test.go delete mode 100644 mocks/v4/countdown_test.go diff --git a/mocks/v3/contagem_test.go b/mocks/v3/contagem_test.go index 5b47a803..37a53ad8 100644 --- a/mocks/v3/contagem_test.go +++ b/mocks/v3/contagem_test.go @@ -30,6 +30,6 @@ type SleeperSpy struct { Chamadas int } -func (s *SleeperSpy) Sleep() { +func (s *SleeperSpy) Pausa() { s.Chamadas++ } diff --git a/mocks/v3/main.go b/mocks/v3/main.go index e7047e69..e0e18044 100644 --- a/mocks/v3/main.go +++ b/mocks/v3/main.go @@ -7,16 +7,16 @@ import ( "time" ) -// Sleeper te permite definir atrasos +// Sleeper te permite definir pausas type Sleeper interface { - Sleep() + Pausa() } // SleeperPadrao é uma implementação de Sleeper com um atraso pré-definido type SleeperPadrao struct{} -// Sleep vai pausar a execução pela Duração definida -func (d *SleeperPadrao) Sleep() { +// Pausa vai pausar a execução pela Duração definida +func (d *SleeperPadrao) Pausa() { time.Sleep(1 * time.Second) } @@ -26,11 +26,11 @@ const inicioContagem = 3 // Contagem imprime uma contagem de 3 para a sáida com um atraso determinado por um Sleeper func Contagem(saida io.Writer, sleeper Sleeper) { for i := inicioContagem; i > 0; i-- { - sleeper.Sleep() + sleeper.Pausa() fmt.Fprintln(saida, i) } - sleeper.Sleep() + sleeper.Pausa() fmt.Fprint(saida, ultimaPalavra) } diff --git a/mocks/v4/contagem_test.go b/mocks/v4/contagem_test.go new file mode 100644 index 00000000..a1d60aed --- /dev/null +++ b/mocks/v4/contagem_test.go @@ -0,0 +1,61 @@ +package main + +import ( + "bytes" + "reflect" + "testing" +) + +func TestContagem(t *testing.T) { + + t.Run("imprime 3 até Vai!", func(t *testing.T) { + buffer := &bytes.Buffer{} + Contagem(buffer, &SpyContagemOperacoes{}) + + resultado := buffer.String() + esperado := `3 +2 +1 +Vai!` + + if resultado != esperado { + t.Errorf("resultado '%s', esperado '%s'", resultado, esperado) + } + }) + + t.Run("pausa antes de cada impressão", func(t *testing.T) { + spyImpressoraSleep := &SpyContagemOperacoes{} + Contagem(spyImpressoraSleep, spyImpressoraSleep) + + esperado := []string{ + pausa, + escrita, + pausa, + escrita, + pausa, + escrita, + pausa, + escrita, + } + + if !reflect.DeepEqual(esperado, spyImpressoraSleep.Chamadas) { + t.Errorf("esperado %v chamadas, resultado %v", esperado, spyImpressoraSleep.Chamadas) + } + }) +} + +type SpyContagemOperacoes struct { + Chamadas []string +} + +func (s *SpyContagemOperacoes) Pausa() { + s.Chamadas = append(s.Chamadas, pausa) +} + +func (s *SpyContagemOperacoes) Write(p []byte) (n int, err error) { + s.Chamadas = append(s.Chamadas, escrita) + return +} + +const escrita = "escrita" +const pausa = "pausa" diff --git a/mocks/v4/countdown_test.go b/mocks/v4/countdown_test.go deleted file mode 100644 index 3ae7a7d4..00000000 --- a/mocks/v4/countdown_test.go +++ /dev/null @@ -1,61 +0,0 @@ -package main - -import ( - "bytes" - "reflect" - "testing" -) - -func TestCountdown(t *testing.T) { - - t.Run("prints 5 to Go!", func(t *testing.T) { - buffer := &bytes.Buffer{} - Countdown(buffer, &CountdownOperationsSpy{}) - - got := buffer.String() - want := `3 -2 -1 -Go!` - - if got != want { - t.Errorf("got '%s' want '%s'", got, want) - } - }) - - t.Run("sleep before every print", func(t *testing.T) { - spySleepPrinter := &CountdownOperationsSpy{} - Countdown(spySleepPrinter, spySleepPrinter) - - want := []string{ - sleep, - write, - sleep, - write, - sleep, - write, - sleep, - write, - } - - if !reflect.DeepEqual(want, spySleepPrinter.Calls) { - t.Errorf("wanted calls %v got %v", want, spySleepPrinter.Calls) - } - }) -} - -type CountdownOperationsSpy struct { - Calls []string -} - -func (s *CountdownOperationsSpy) Sleep() { - s.Calls = append(s.Calls, sleep) -} - -func (s *CountdownOperationsSpy) Write(p []byte) (n int, err error) { - s.Calls = append(s.Calls, write) - return -} - -const write = "write" -const sleep = "sleep" diff --git a/mocks/v4/main.go b/mocks/v4/main.go index c943e7a5..e0e18044 100644 --- a/mocks/v4/main.go +++ b/mocks/v4/main.go @@ -7,35 +7,34 @@ import ( "time" ) -// Sleeper allows you to put delays +// Sleeper te permite definir pausas type Sleeper interface { - Sleep() + Pausa() } -// DefaultSleeper is an implementation of Sleeper with a predefined delay -type DefaultSleeper struct{} +// SleeperPadrao é uma implementação de Sleeper com um atraso pré-definido +type SleeperPadrao struct{} -// Sleep will pause execution for the defined Duration -func (d *DefaultSleeper) Sleep() { +// Pausa vai pausar a execução pela Duração definida +func (d *SleeperPadrao) Pausa() { time.Sleep(1 * time.Second) } -const finalWord = "Go!" -const countdownStart = 3 +const ultimaPalavra = "Vai!" +const inicioContagem = 3 -// Countdown prints a countdown from 5 to out with a delay between count provided by Sleeper -func Countdown(out io.Writer, sleeper Sleeper) { - - for i := countdownStart; i > 0; i-- { - sleeper.Sleep() - fmt.Fprintln(out, i) +// Contagem imprime uma contagem de 3 para a sáida com um atraso determinado por um Sleeper +func Contagem(saida io.Writer, sleeper Sleeper) { + for i := inicioContagem; i > 0; i-- { + sleeper.Pausa() + fmt.Fprintln(saida, i) } - sleeper.Sleep() - fmt.Fprint(out, finalWord) + sleeper.Pausa() + fmt.Fprint(saida, ultimaPalavra) } func main() { - sleeper := &DefaultSleeper{} - Countdown(os.Stdout, sleeper) + sleeper := &SleeperPadrao{} + Contagem(os.Stdout, sleeper) } diff --git a/primeiros-passos-com-go/mocks.md b/primeiros-passos-com-go/mocks.md index 05883b7c..505892b0 100644 --- a/primeiros-passos-com-go/mocks.md +++ b/primeiros-passos-com-go/mocks.md @@ -375,123 +375,124 @@ Nossa alteração mais recente só verifica se o software teve 4 pausas, mas ess Quando escrevemos testes, se não estiver confiante de que seus testes estão te dando confiança o suficiente, quebre-o (mas certifique-se de que você salvou suas alterações antes)! Mude o código para o seguinte: ```go -func Countdown(out io.Writer, sleeper Sleeper) { - for i := countdownStart; i > 0; i-- { - sleeper.Sleep() +func Contagem(saida io.Writer, sleeper Sleeper) { + for i := inicioContagem; i > 0; i-- { + sleeper.Pausa() + fmt.Fprintln(saida, i) } - for i := countdownStart; i > 0; i-- { - fmt.Fprintln(out, i) + for i := inicioContagem; i > 0; i-- { + fmt.Fprintln(saida, i) } - sleeper.Sleep() - fmt.Fprint(out, finalWord) + sleeper.Pausa() + fmt.Fprint(saida, ultimaPalavra) } ``` -If you run your tests they should still be passing even though the implementation is wrong. +Se executar seus testes, eles ainda vão passar, apesar da implementação estar errada. -Let's use spying again with a new test to check the order of operations is correct. +Vamos usar o spy novamente com um novo teste para verificar se a ordem das operações está correta. -We have two different dependencies and we want to record all of their operations into one list. So we'll create _one spy for them both_. +Temos duas dependências diferentes e queremos gravar todas as operações delas em uma lista. Logo, vamos criar _um spy para ambas_. ```go -type CountdownOperationsSpy struct { - Calls []string +type SpyContagemOperacoes struct { + Chamadas []string } -func (s *CountdownOperationsSpy) Sleep() { - s.Calls = append(s.Calls, sleep) +func (s *SpyContagemOperacoes) Pausa() { + s.Chamadas = append(s.Chamadas, pausa) } -func (s *CountdownOperationsSpy) Write(p []byte) (n int, err error) { - s.Calls = append(s.Calls, write) +func (s *SpyContagemOperacoes) Write(p []byte) (n int, err error) { + s.Chamadas = append(s.Chamadas, escrita) return } -const write = "write" -const sleep = "sleep" +const escrita = "escrita" +const pausa = "pausa" ``` -Our `CountdownOperationsSpy` implements both `io.Writer` and `Sleeper`, recording every call into one slice. In this test we're only concerned about the order of operations, so just recording them as list of named operations is sufficient. +Nosso `SpyContagemOperacoes` implementa tanto o `io.Writer` quanto o `Sleeper`, gravando cada chamada em um slice. Nesse teste, temos preocupação apenas na ordem das operações, então apenas gravá-las em uma lista de operações nomeadas é suficiente. -We can now add a sub-test into our test suite. +Agora podemos adicionar um subteste no nosso conjunto de testes. ```go -t.Run("sleep before every print", func(t *testing.T) { - spySleepPrinter := &CountdownOperationsSpy{} - Countdown(spySleepPrinter, spySleepPrinter) - - want := []string{ - sleep, - write, - sleep, - write, - sleep, - write, - sleep, - write, - } +t.Run("pausa antes de cada impressão", func(t *testing.T) { + spyImpressoraSleep := &SpyContagemOperacoes{} + Contagem(spyImpressoraSleep, spyImpressoraSleep) + + esperado := []string{ + pausa, + escrita, + pausa, + escrita, + pausa, + escrita, + pausa, + escrita, + } - if !reflect.DeepEqual(want, spySleepPrinter.Calls) { - t.Errorf("wanted calls %v got %v", want, spySleepPrinter.Calls) - } -}) + if !reflect.DeepEqual(esperado, spyImpressoraSleep.Chamadas) { + t.Errorf("esperado %v chamadas, resultado %v", esperado, spyImpressoraSleep.Chamadas) + } + }) ``` -This test should now fail. Revert it back and the new test should pass. +Esse teste deve falhar. Volte o código que quebramos para a versão correta e agora o novo teste deve passar. -We now have two tests spying on the `Sleeper` so we can now refactor our test so one is testing what is being printed and the other one is ensuring we're sleeping in between the prints. Finally we can delete our first spy as it's not used anymore. +Agora temos dois spies no `Sleeper`. O próximo passo é refatorar nosso teste para que um teste o que está sendo impresso e o outro se certifique de que estamos pausando entre as impressões. Por fim, podemos apagar nosso primeiro spy, já que não é mais utilizado. ```go -func TestCountdown(t *testing.T) { +func TestContagem(t *testing.T) { - t.Run("prints 3 to Go!", func(t *testing.T) { + t.Run("imprime 3 até Vai!", func(t *testing.T) { buffer := &bytes.Buffer{} - Countdown(buffer, &CountdownOperationsSpy{}) + Contagem(buffer, &SpyContagemOperacoes{}) - got := buffer.String() - want := `3 + resultado := buffer.String() + esperado := `3 2 1 -Go!` +Vai!` - if got != want { - t.Errorf("got '%s' want '%s'", got, want) + if resultado != esperado { + t.Errorf("resultado '%s', esperado '%s'", resultado, esperado) } }) - t.Run("sleep before every print", func(t *testing.T) { - spySleepPrinter := &CountdownOperationsSpy{} - Countdown(spySleepPrinter, spySleepPrinter) - - want := []string{ - sleep, - write, - sleep, - write, - sleep, - write, - sleep, - write, + t.Run("pausa antes de cada impressão", func(t *testing.T) { + spyImpressoraSleep := &SpyContagemOperacoes{} + Contagem(spyImpressoraSleep, spyImpressoraSleep) + + esperado := []string{ + pausa, + escrita, + pausa, + escrita, + pausa, + escrita, + pausa, + escrita, } - if !reflect.DeepEqual(want, spySleepPrinter.Calls) { - t.Errorf("wanted calls %v got %v", want, spySleepPrinter.Calls) + if !reflect.DeepEqual(esperado, spyImpressoraSleep.Chamadas) { + t.Errorf("esperado %v chamadas, resultado %v", esperado, spyImpressoraSleep.Chamadas) } }) } ``` -We now have our function and its 2 important properties properly tested. +Agora temos nossa função e suas duas propriedades testadas adequadamente. -## Extending Sleeper to be configurable +## Extendendo o Sleeper para se tornar configurável -A nice feature would be for the `Sleeper` to be configurable. +Uma funcionalidadee legal seria o `Sleeper` seja configurável. -### Write the test first +### Escreva o teste primeiro -Let's first create a new type for `ConfigurableSleeper` that accepts what we need for configuration and testing. +Agora vamos criar um novo tipo para `SleeperConfiguravel` que aceita o que precisamos para configuração e teste. ```go type ConfigurableSleeper struct { From 19bfb790c836268384a83388c7aa4ddf66bee8d3 Mon Sep 17 00:00:00 2001 From: Lauren Ferreira Date: Fri, 2 Aug 2019 21:34:51 -0300 Subject: [PATCH 4/7] =?UTF-8?q?Finaliza=C3=A7=C3=A3o=20de=20tradu=C3=A7?= =?UTF-8?q?=C3=A3o=20de=20Mocks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mocks/v5/contagem_test.go | 82 +++++++++++++++++ mocks/v5/countdown_test.go | 82 ----------------- mocks/v5/main.go | 41 +++++---- primeiros-passos-com-go/mocks.md | 147 ++++++++++++++++--------------- 4 files changed, 176 insertions(+), 176 deletions(-) create mode 100644 mocks/v5/contagem_test.go delete mode 100644 mocks/v5/countdown_test.go diff --git a/mocks/v5/contagem_test.go b/mocks/v5/contagem_test.go new file mode 100644 index 00000000..9cbb3903 --- /dev/null +++ b/mocks/v5/contagem_test.go @@ -0,0 +1,82 @@ +package main + +import ( + "bytes" + "reflect" + "testing" + "time" +) + +func TestContagem(t *testing.T) { + + t.Run("imprime 3 até Vai!", func(t *testing.T) { + buffer := &bytes.Buffer{} + Contagem(buffer, &SpyContagemOperacoes{}) + + resultado := buffer.String() + esperado := `3 +2 +1 +Vai!` + + if resultado != esperado { + t.Errorf("resultado '%s', esperado '%s'", resultado, esperado) + } + }) + + t.Run("pausa antes de cada impressão", func(t *testing.T) { + spyImpressoraSleep := &SpyContagemOperacoes{} + Contagem(spyImpressoraSleep, spyImpressoraSleep) + + esperado := []string{ + pausa, + escrita, + pausa, + escrita, + pausa, + escrita, + pausa, + escrita, + } + + if !reflect.DeepEqual(esperado, spyImpressoraSleep.Chamadas) { + t.Errorf("esperado %v chamadas, resultado %v", esperado, spyImpressoraSleep.Chamadas) + } + }) +} + +func TestSleeperConfiguravel(t *testing.T) { + tempoPausa := 5 * time.Second + + tempoSpy := &TempoSpy{} + sleeper := SleeperConfiguravel{tempoPausa, tempoSpy.Pausa} + sleeper.Pausa() + + if tempoSpy.duracaoPausa != tempoPausa { + t.Errorf("deveria ter pausado por %v, mas pausou por %v", tempoPausa, tempoSpy.duracaoPausa) + } +} + +type SpyContagemOperacoes struct { + Chamadas []string +} + +func (s *SpyContagemOperacoes) Pausa() { + s.Chamadas = append(s.Chamadas, pausa) +} + +func (s *SpyContagemOperacoes) Write(p []byte) (n int, err error) { + s.Chamadas = append(s.Chamadas, escrita) + return +} + +const escrita = "escrita" +const pausa = "pausa" + +type TempoSpy struct { + duracaoPausa time.Duration +} + +func (t *TempoSpy) Pausa(duracao time.Duration) { + t.duracaoPausa = duracao +} diff --git a/mocks/v5/countdown_test.go b/mocks/v5/countdown_test.go deleted file mode 100644 index c5be19ee..00000000 --- a/mocks/v5/countdown_test.go +++ /dev/null @@ -1,82 +0,0 @@ -package main - -import ( - "bytes" - "reflect" - "testing" - "time" -) - -func TestCountdown(t *testing.T) { - - t.Run("prints 5 to Go!", func(t *testing.T) { - buffer := &bytes.Buffer{} - Countdown(buffer, &CountdownOperationsSpy{}) - - got := buffer.String() - want := `3 -2 -1 -Go!` - - if got != want { - t.Errorf("got '%s' want '%s'", got, want) - } - }) - - t.Run("sleep before every print", func(t *testing.T) { - spySleepPrinter := &CountdownOperationsSpy{} - Countdown(spySleepPrinter, spySleepPrinter) - - want := []string{ - sleep, - write, - sleep, - write, - sleep, - write, - sleep, - write, - } - - if !reflect.DeepEqual(want, spySleepPrinter.Calls) { - t.Errorf("wanted calls %v got %v", want, spySleepPrinter.Calls) - } - }) -} - -func TestConfigurableSleeper(t *testing.T) { - sleepTime := 5 * time.Second - - spyTime := &SpyTime{} - sleeper := ConfigurableSleeper{sleepTime, spyTime.Sleep} - sleeper.Sleep() - - if spyTime.durationSlept != sleepTime { - t.Errorf("should have slept for %v but slept for %v", sleepTime, spyTime.durationSlept) - } -} - -type CountdownOperationsSpy struct { - Calls []string -} - -func (s *CountdownOperationsSpy) Sleep() { - s.Calls = append(s.Calls, sleep) -} - -func (s *CountdownOperationsSpy) Write(p []byte) (n int, err error) { - s.Calls = append(s.Calls, write) - return -} - -const write = "write" -const sleep = "sleep" - -type SpyTime struct { - durationSlept time.Duration -} - -func (s *SpyTime) Sleep(duration time.Duration) { - s.durationSlept = duration -} diff --git a/mocks/v5/main.go b/mocks/v5/main.go index 940b7e55..12b6ea68 100644 --- a/mocks/v5/main.go +++ b/mocks/v5/main.go @@ -7,38 +7,37 @@ import ( "time" ) -// Sleeper allows you to put delays +/// Sleeper te permite definir pausas type Sleeper interface { - Sleep() + Pausa() } -// ConfigurableSleeper is an implementation of Sleeper with a defined delay -type ConfigurableSleeper struct { - duration time.Duration - sleep func(time.Duration) +// SleeperConfiguravel é uma implementação de Sleepr com uma pausa definida +type SleeperConfiguravel struct { + duracao time.Duration + pausa func(time.Duration) } -// Sleep will pause execution for the defined Duration -func (c *ConfigurableSleeper) Sleep() { - c.sleep(c.duration) +// Pausa vai pausar a execução pela Duração definida +func (s *SleeperConfiguravel) Pausa() { + s.pausa(s.duracao) } -const finalWord = "Go!" -const countdownStart = 3 +const ultimaPalavra = "Vai!" +const inicioContagem = 3 -// Countdown prints a countdown from 5 to out with a delay between count provided by Sleeper -func Countdown(out io.Writer, sleeper Sleeper) { - - for i := countdownStart; i > 0; i-- { - sleeper.Sleep() - fmt.Fprintln(out, i) +// Contagem imprime uma contagem de 3 para a sáida com um atraso determinado por um Sleeper +func Contagem(saida io.Writer, sleeper Sleeper) { + for i := inicioContagem; i > 0; i-- { + sleeper.Pausa() + fmt.Fprintln(saida, i) } - sleeper.Sleep() - fmt.Fprint(out, finalWord) + sleeper.Pausa() + fmt.Fprint(saida, ultimaPalavra) } func main() { - sleeper := &ConfigurableSleeper{1 * time.Second, time.Sleep} - Countdown(os.Stdout, sleeper) + sleeper := &SleeperConfiguravel{1 * time.Second, time.Sleep} + Contagem(os.Stdout, sleeper) } diff --git a/primeiros-passos-com-go/mocks.md b/primeiros-passos-com-go/mocks.md index 505892b0..cab64b63 100644 --- a/primeiros-passos-com-go/mocks.md +++ b/primeiros-passos-com-go/mocks.md @@ -495,147 +495,148 @@ Uma funcionalidadee legal seria o `Sleeper` seja configurável. Agora vamos criar um novo tipo para `SleeperConfiguravel` que aceita o que precisamos para configuração e teste. ```go -type ConfigurableSleeper struct { - duration time.Duration - sleep func(time.Duration) +type SleeperConfiguravel struct { + duracao time.Duration + pausa func(time.Duration) } ``` -We are using `duration` to configure the time slept and `sleep` as a way to pass in a sleep function. The signature of `sleep` is the same as for `time.Sleep` allowing us to use `time.Sleep` in our real implementation and a spy in our tests. +Estamos usando a `duracao` para configurar o tempo de pausa e `pausa` como forma de passar uma função de pausa. A assinatura de `sleep` é a mesma de `time.Sleep`, nos permitindo usar `time.Sleep` na nossa implementação real e um spy nos nossos testes. ```go -type SpyTime struct { - durationSlept time.Duration +type TempoSpy struct { + duracaoPausa time.Duration } -func (s *SpyTime) Sleep(duration time.Duration) { - s.durationSlept = duration +func (t *TempoSpy) Pausa(duracao time.Duration) { + t.duracaoPausa = duracao } ``` -With our spy in place, we can create a new test for the configurable sleeper. +Definindo nosso spy, podemos criar um novo teste para o sleeper configurável. ```go -func TestConfigurableSleeper(t *testing.T) { - sleepTime := 5 * time.Second +func TestSleeperConfiguravel(t *testing.T) { + tempoPausa := 5 * time.Second - spyTime := &SpyTime{} - sleeper := ConfigurableSleeper{sleepTime, spyTime.Sleep} - sleeper.Sleep() + tempoSpy := &TempoSpy{} + sleeper := SleeperConfiguravel{tempoPausa, tempoSpy.Pausa} + sleeper.Pausa() - if spyTime.durationSlept != sleepTime { - t.Errorf("should have slept for %v but slept for %v", sleepTime, spyTime.durationSlept) + if tempoSpy.duracaoPausa != tempoPausa { + t.Errorf("deveria ter pausado por %v, mas pausou por %v", tempoPausa, tempoSpy.duracaoPausa) } } ``` -There should be nothing new in this test and it is setup very similar to the previous mock tests. +Não há nada de novo nesse teste e seu funcionamento é bem semelhante aos testes com mock anteriores. -### Try and run the test +### Execute o teste -```text +```bash sleeper.Sleep undefined (type ConfigurableSleeper has no field or method Sleep, but does have sleep) ``` -You should see a very clear error message indicating that we do not have a `Sleep` method created on our `ConfigurableSleeper`. +`sleeper.Pausa não definido (tipo SleeperConfiguravel não tem campo ou método Pausa, mas tem o método sleep` + +Você deve ver uma mensagem de erro bem clara indicando que não temos um método `Pausa` criado no nosso `SleeperConfiguravel`. -### Write the minimal amount of code for the test to run and check failing test output +### Escreva o mínimo de código possível para fazer o teste rodar e verifique a saída do teste que tiver falhado ```go -func (c *ConfigurableSleeper) Sleep() { +func (c *SleeperConfiguravel) Pausa() { } ``` -With our new `Sleep` function implemented we have a failing test. +Com nossa nova função `Pausa` implementada, ainda há um teste falhando. -```text -countdown_test.go:56: should have slept for 5s but slept for 0s +```bash +contagem_test.go:56: deveria ter pausado por 5s, mas pausou por 0s ``` -### Write enough code to make it pass +### Escreva código o suficiente para fazer o teste passar -All we need to do now is implement the `Sleep` function for `ConfigurableSleeper`. +Tudo o que precisamos fazer agora é implementar a função `Pausa` para o `SleeperConfiguravel`. ```go -func (c *ConfigurableSleeper) Sleep() { - c.sleep(c.duration) +func (s *SleeperConfiguravel) Pausa() { + s.pausa(s.duracao) } ``` -With this change all of the test should be passing again. +Com essa mudança, todos os testes devem voltar a passar. -### Cleanup and refactor +### Limpeza e refatoração -The last thing we need to do is to actually use our `ConfigurableSleeper` in the main function. +A última coisa que precisamos fazer é de fato usar nosso `SleeperConfiguravel` na função main. ```go func main() { - sleeper := &ConfigurableSleeper{1 * time.Second, time.Sleep} - Countdown(os.Stdout, sleeper) + sleeper := &SleeperConfiguravel{1 * time.Second, time.Sleep} + Contagem(os.Stdout, sleeper) } ``` -If we run the tests and the program manually, we can see that all the behavior remains the same. +Se executarmos os testes e o programa manualmente, podemos ver que todo o comportamento permanece o mesmo. + +Já que estamos usando o `SleeperConfiguravel`, é seguro deletar o `SleeperPadrao`. -Since we are using the `ConfigurableSleeper`, it is safe to delete the `DefaultSleeper` implementation. Wrapping up our program. +## Mas o mock não é do demonho? -## But isn't mocking evil? +Você já deve ter ouvido que o mock é do mal. Quase qualquer coisa no desenvolvimento de software pode ser usada para o mal, assim como o [DRY](https://pt.wikipedia.org/wiki/Don%27t_repeat_yourself). -You may have heard mocking is evil. Just like anything in software development it can be used for evil, just like [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself). +As pessoas acabam chegando numa fase ruim em que não _dão atenção aos próprios testes_ e _não respeitam a etapa de refatoração_. -People normally get in to a bad state when they don't _listen to their tests_ and are _not respecting the refactoring stage_. +Se seu código de mock estiver ficando complicado ou você tem que mockar muita coisa para testar algo, você deve _prestar mais atenção_ a essa sensação ruim e pensar sobre o seu código. Geralmente isso é sinal de que: -If your mocking code is becoming complicated or you are having to mock out lots of things to test something, you should _listen_ to that bad feeling and think about your code. Usually it is a sign of +- A coisa que você está tentando faz coisas demais + - Modularize a função para que faça menos coisas +- Suas dependências estão muito desacopladas + - Pense e uma forma de consolidar algumas das dependências em um módulo útil +- Você está se preocupando demais com detalhes de implementaçaõ + - Dê prioridade em testar o comportamento esperado ao invés da implementação -- The thing you are testing is having to do too many things - - Break the module apart so it does less -- Its dependencies are too fine-grained - - Think about how you can consolidate some of these dependencies into one meaningful module -- Your test is too concerned with implementation details - - Favour testing expected behaviour rather than the implementation +Normalmente, muitos pontos de mock são sinais de _abstração ruim_ no seu código. -Normally a lot of mocking points to _bad abstraction_ in your code. +**Costumam pensar que essa é uma fraqueza no TDD, mas na verdade é um ponto forte**. Testes mal desenvolvidos são resultado de código ruim. Código bem desenvolvido é fácil de ser testado. -**What people see here is a weakness in TDD but it is actually a strength**, more often than not poor test code is a result of bad design or put more nicely, well-designed code is easy to test. +### Só que mocks e testes ainda estão dificultando minha vida! -### But mocks and tests are still making my life hard! +Já se deparou com a situação a seguir? -Ever run into this situation? +- Você quer refatorar algo +- Para isso, você precisa mudar vários testes +- Você duvida do TDD e cria um post no Medium chamado "Mock é prejudicial" -- You want to do some refactoring -- To do this you end up changing lots of tests -- You question TDD and make a post on Medium titled "Mocking considered harmful" +Isso costuma ser um sinal de que você está testando muito _detalhe de implementação_. Tente fazer de forma que esteja testando _comportamentos úteis_, a não ser que a implementação seja tão importante que a falta dela possa fazer o sistema quebrar. -This is usually a sign of you testing too much _implementation detail_. Try to make it so your tests are testing _useful behaviour_ unless the implementation is really important to how the system runs. +Às vezes é difícil saber _qual nível_ testar exatamente, então aqui vai algumas ideias e regras que tento seguir: -It is sometimes hard to know _what level_ to test exactly but here are some thought processes and rules I try to follow: +-**A definição de refatoração é que o código muda, mas o comportamento permanece o mesmo**. Se você decidiu refatorar alguma coisa, na teoria você deve ser capaz de salvar seu código sem que o teste mude. Então, quando estiver escrevendo um teste, pergunte para si: - Estou testando o comportamento que quero ou detalhes de implementação? - Se fosse refatorar esse código, eu teria que fazer muitas mudanças no meu teste? -- **The definition of refactoring is that the code changes but the behaviour stays the same**. If you have decided to do some refactoring in theory you should be able to do make the commit without any test changes. So when writing a test ask yourself - - Am i testing the behaviour I want or the implementation details? - - If i were to refactor this code, would I have to make lots of changes to the tests? -- Although Go lets you test private functions, I would avoid it as private functions are to do with implementation. -- I feel like if a test is working with **more than 3 mocks then it is a red flag** - time for a rethink on the design -- Use spies with caution. Spies let you see the insides of the algorithm you are writing which can be very useful but that means a tighter coupling between your test code and the implementation. **Be sure you actually care about these details if you're going to spy on them** +- Apesar do Go te deixar testar funções privadas, eu evitaria fazer isso, já que funções privadas costumam ser detalhes de implementação. +- Se o teste estiver com **3 mocks, esse é um sinal de alerta** - hora de repensar no design. +- Use spies com cuidado. Spies te deixam ver a parte interna do algoritmo que você está escrevendo, o que pode ser bem útil, mas significa que há um acoplamento maior entre o código do teste e a implementação. **Certifique-se de que você realmente precisa desses detalhes se você vai colocar um spy neles**. -As always, rules in software development aren't really rules and there can be exceptions. [Uncle Bob's article of "When to mock"](https://8thlight.com/blog/uncle-bob/2014/05/10/WhenToMock.html) has some excellent pointers. +Como sempre, regras no desenvolvimento de software não são realmente regras e podem haver exceções. [O artigo do Uncle Bob sobre "Quando mockar"](https://8thlight.com/blog/uncle-bob/2014/05/10/WhenToMock.html) (em inglês) tem alguns pontos excelentes. -## Wrapping up +## Resumo -### More on TDD approach +### Mais sobre abordagem TDD -- When faced with less trivial examples, break the problem down into "thin vertical slices". Try to get to a point where you have _working software backed by tests_ as soon as you can, to avoid getting in rabbit holes and taking a "big bang" approach. -- Once you have some working software it should be easier to _iterate with small steps_ until you arrive at the software you need. +- Quando se deparar com exemplos menos comuns, divida o problema em "linhas verticais finas". Tente chegar em um ponto onde você tem _software em funcionamento com o apoio de testes_ o mais rápido possível, para evitar cair em armadilhas e se perder. +- Quando tiver uma parte software em funcionamento, deve ser mais fácil _iterar com etapas pequenas_ até chegar no software que você precisa. -> "When to use iterative development? You should use iterative development only on projects that you want to succeed." +> "Quando usar o desenvolvimento iterativo? Apenas em projetos que você quer obter sucesso." Martin Fowler. -### Mocking +### Mock -- **Without mocking important areas of your code will be untested**. In our case we would not be able to test that our code paused between each print but there are countless other examples. Calling a service that _can_ fail? Wanting to test your system in a particular state? It is very hard to test these scenarios without mocking. -- Without mocks you may have to set up databases and other third parties things just to test simple business rules. You're likely to have slow tests, resulting in **slow feedback loops**. -- By having to spin up a database or a webservice to test something you're likely to have **fragile tests** due to the unreliability of such services. +- **Sem o mock, partes importantes do seu código não serão testadas**. No nosso caso, não seríamos capazes de testar se nosso código pausava em cada impressão, mas existem inúmeros exemplos. Chamar um serviço que _pode_ falhar? Querer testar seu sistema em um estado em particular? É bem difícil testar esses casos sem mock. +- Sem mocks você pode ter que definir bancos de dados e outras dependências externas só para testar regras de negócio simples. Seus testes provavelmente ficarão mais lentos, resultando em **loops de feedback lentos**. +- Ter que se conectar a um banco de dados ou webservice para testar algo vai tornar seus testes **frágeis** por causa da falta de segurança nesses serviços. -Once a developer learns about mocking it becomes very easy to over-test every single facet of a system in terms of the _way it works_ rather than _what it does_. Always be mindful about **the value of your tests** and what impact they would have in future refactoring. +Uma vez que a pessoa aprende a mockar, é bem fácil testar pontos demais de um sistema em termos da _forma que ele funciona_ ao invés _do que ele faz_. Sempre tenha em mente o **valor dos seus testes** e qual impacto eles teriam em uma refatoração futura. -In this post about mocking we have only covered **Spies** which are a kind of mock. There are different kind of mocks. [Uncle Bob explains the types in a very easy to read article](https://8thlight.com/blog/uncle-bob/2014/05/14/TheLittleMocker.html). In later chapters we will need to write code that depends on others for data, which is where we will show **Stubs** in action. +Nesse artigo sobre mock, falamos sobre **spies**, que são um tipo de mock. Aqui estão diferentes tipos de mocks. [O Uncle Bob explica os tipos em um artigo bem fácil de ler](https://8thlight.com/blog/uncle-bob/2014/05/14/TheLittleMocker.html) (em inglês). Nos próximos capítulos, vamos precisar escrever código que depende de outros para obter dados, que é aonde vou mostrar os **Stubs** em ação. From e17eb241498599cc5187c68d74a173b86721b8a8 Mon Sep 17 00:00:00 2001 From: Lauren Ferreira Date: Fri, 2 Aug 2019 21:36:11 -0300 Subject: [PATCH 5/7] =?UTF-8?q?Corre=C3=A7=C3=A3o=20de=20refer=C3=AAncias?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- SUMMARY.md | 2 +- build.books.sh | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1e50dfce..55c63fc5 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ 9. [Ponteiros e erros](primeiros-passos-com-go/pointers-and-errors.md) - Aprenda sobre ponteiros e erros. 10. [Maps](primeiros-passos-com-go/maps.md) - Aprenda sobre armazenamento de valores na estrutura de dados `map`. 11. [Injeção de dependência](primeiros-passos-com-go/dependency-injection.md) - Aprenda sobre injeção de dependência, qual sua relação com interfaces e uma introdução a io. -12. [Mocking](primeiros-passos-com-go/mocking.md) - Use injeção de dependência com mocking para testar um código sem nenhum teste. +12. [Mocking](primeiros-passos-com-go/mocks.md) - Use injeção de dependência com mocking para testar um código sem nenhum teste. 13. [Concorrência](primeiros-passos-com-go/concurrency.md) - Aprenda como escrever código concorrente para tornar seu software mais rápido. 14. [Select](primeiros-passos-com-go/select.md) - Aprenda a sincronizar processos assíncronos de forma elegante. 15. [Reflection](primeiros-passos-com-go/reflection.md) - Aprenda sobre reflection. diff --git a/SUMMARY.md b/SUMMARY.md index bd28fcc4..816138c5 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -15,7 +15,7 @@ - [Ponteiros e erros](primeiros-passos-com-go/pointers-and-errors.md) - [Maps](primeiros-passos-com-go/maps.md) - [Injeção de dependência](primeiros-passos-com-go/dependency-injection.md) -- [Mocking](primeiros-passos-com-go/mocking.md) +- [Mocking](primeiros-passos-com-go/mocks.md) - [Concorrência](primeiros-passos-com-go/concurrency.md) - [Select](primeiros-passos-com-go/select.md) - [Reflection](primeiros-passos-com-go/reflection.md) diff --git a/build.books.sh b/build.books.sh index 16819d0e..1e34147f 100755 --- a/build.books.sh +++ b/build.books.sh @@ -14,7 +14,7 @@ docker run -v `pwd`:/source jagregory/pandoc -o aprenda-go-com-testes.pdf --late primeiros-passos-com-go/pointers-and-errors.md \ primeiros-passos-com-go/maps.md \ primeiros-passos-com-go/dependency-injection.md \ - primeiros-passos-com-go/mocking.md \ + primeiros-passos-com-go/mocks.md \ primeiros-passos-com-go/concurrency.md \ primeiros-passos-com-go/select.md \ primeiros-passos-com-go/reflection.md \ @@ -42,7 +42,7 @@ docker run -v `pwd`:/source jagregory/pandoc -o aprenda-go-com-testes.epub --lat primeiros-passos-com-go/pointers-and-errors.md \ primeiros-passos-com-go/maps.md \ primeiros-passos-com-go/dependency-injection.md \ - primeiros-passos-com-go/mocking.md \ + primeiros-passos-com-go/mocks.md \ primeiros-passos-com-go/concurrency.md \ primeiros-passos-com-go/select.md \ primeiros-passos-com-go/reflection.md \ From c9b09d29fe73a7d934966f11283e4c412566ee5a Mon Sep 17 00:00:00 2001 From: Lauren Ferreira Date: Wed, 7 Aug 2019 18:27:24 -0300 Subject: [PATCH 6/7] Text review fixes --- mocks/v1/main.go | 2 +- mocks/v2/main.go | 2 +- mocks/v3/main.go | 2 +- mocks/v4/main.go | 2 +- mocks/v5/main.go | 2 +- primeiros-passos-com-go/mocks.md | 10 +++++----- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/mocks/v1/main.go b/mocks/v1/main.go index 24ad93f2..71bea0fc 100644 --- a/mocks/v1/main.go +++ b/mocks/v1/main.go @@ -6,7 +6,7 @@ import ( "os" ) -// Contagem imprime uma contagem de 3 para a sáida +// Contagem imprime uma contagem de 3 para a saída func Contagem(saida io.Writer) { fmt.Fprint(saida, "3") } diff --git a/mocks/v2/main.go b/mocks/v2/main.go index fd1159d0..e71a1ea0 100644 --- a/mocks/v2/main.go +++ b/mocks/v2/main.go @@ -9,7 +9,7 @@ import ( const ultimaPalavra = "Vai!" const inicioContagem = 3 -// Contagem imprime uma contagem de 3 para a sáida +// Contagem imprime uma contagem de 3 para a saída func Contagem(saida io.Writer) { for i := inicioContagem; i > 0; i-- { fmt.Fprintln(saida, i) diff --git a/mocks/v3/main.go b/mocks/v3/main.go index e0e18044..8f0e78cd 100644 --- a/mocks/v3/main.go +++ b/mocks/v3/main.go @@ -23,7 +23,7 @@ func (d *SleeperPadrao) Pausa() { const ultimaPalavra = "Vai!" const inicioContagem = 3 -// Contagem imprime uma contagem de 3 para a sáida com um atraso determinado por um Sleeper +// Contagem imprime uma contagem de 3 para a saída com um atraso determinado por um Sleeper func Contagem(saida io.Writer, sleeper Sleeper) { for i := inicioContagem; i > 0; i-- { sleeper.Pausa() diff --git a/mocks/v4/main.go b/mocks/v4/main.go index e0e18044..8f0e78cd 100644 --- a/mocks/v4/main.go +++ b/mocks/v4/main.go @@ -23,7 +23,7 @@ func (d *SleeperPadrao) Pausa() { const ultimaPalavra = "Vai!" const inicioContagem = 3 -// Contagem imprime uma contagem de 3 para a sáida com um atraso determinado por um Sleeper +// Contagem imprime uma contagem de 3 para a saída com um atraso determinado por um Sleeper func Contagem(saida io.Writer, sleeper Sleeper) { for i := inicioContagem; i > 0; i-- { sleeper.Pausa() diff --git a/mocks/v5/main.go b/mocks/v5/main.go index 12b6ea68..0968c60c 100644 --- a/mocks/v5/main.go +++ b/mocks/v5/main.go @@ -26,7 +26,7 @@ func (s *SleeperConfiguravel) Pausa() { const ultimaPalavra = "Vai!" const inicioContagem = 3 -// Contagem imprime uma contagem de 3 para a sáida com um atraso determinado por um Sleeper +// Contagem imprime uma contagem de 3 para a saída com um atraso determinado por um Sleeper func Contagem(saida io.Writer, sleeper Sleeper) { for i := inicioContagem; i > 0; i-- { sleeper.Pausa() diff --git a/primeiros-passos-com-go/mocks.md b/primeiros-passos-com-go/mocks.md index cab64b63..fe271585 100644 --- a/primeiros-passos-com-go/mocks.md +++ b/primeiros-passos-com-go/mocks.md @@ -534,7 +534,7 @@ Não há nada de novo nesse teste e seu funcionamento é bem semelhante aos test ### Execute o teste ```bash -sleeper.Sleep undefined (type ConfigurableSleeper has no field or method Sleep, but does have sleep) +sleeper.Pausa undefined (type SleeperConfiguravel has no field or method Pausa, but does have pausa) ``` `sleeper.Pausa não definido (tipo SleeperConfiguravel não tem campo ou método Pausa, mas tem o método sleep` @@ -589,16 +589,16 @@ As pessoas acabam chegando numa fase ruim em que não _dão atenção aos própr Se seu código de mock estiver ficando complicado ou você tem que mockar muita coisa para testar algo, você deve _prestar mais atenção_ a essa sensação ruim e pensar sobre o seu código. Geralmente isso é sinal de que: -- A coisa que você está tentando faz coisas demais +- A coisa que você está testando está tendo que fazer coisas demais - Modularize a função para que faça menos coisas - Suas dependências estão muito desacopladas - Pense e uma forma de consolidar algumas das dependências em um módulo útil -- Você está se preocupando demais com detalhes de implementaçaõ +- Você está se preocupando demais com detalhes de implementação - Dê prioridade em testar o comportamento esperado ao invés da implementação Normalmente, muitos pontos de mock são sinais de _abstração ruim_ no seu código. -**Costumam pensar que essa é uma fraqueza no TDD, mas na verdade é um ponto forte**. Testes mal desenvolvidos são resultado de código ruim. Código bem desenvolvido é fácil de ser testado. +**As pessoas costumam pensar que essa é uma fraqueza no TDD, mas na verdade é um ponto forte**. Testes mal desenvolvidos são resultado de código ruim. Código bem desenvolvido é fácil de ser testado. ### Só que mocks e testes ainda estão dificultando minha vida! @@ -625,7 +625,7 @@ Como sempre, regras no desenvolvimento de software não são realmente regras e ### Mais sobre abordagem TDD - Quando se deparar com exemplos menos comuns, divida o problema em "linhas verticais finas". Tente chegar em um ponto onde você tem _software em funcionamento com o apoio de testes_ o mais rápido possível, para evitar cair em armadilhas e se perder. -- Quando tiver uma parte software em funcionamento, deve ser mais fácil _iterar com etapas pequenas_ até chegar no software que você precisa. +- Quando tiver uma parte do software em funcionamento, deve ser mais fácil _iterar com etapas pequenas_ até chegar no software que você precisa. > "Quando usar o desenvolvimento iterativo? Apenas em projetos que você quer obter sucesso." From f08eb5b4d1d9f29cf763908a466c3240df97521b Mon Sep 17 00:00:00 2001 From: Lauren Ferreira Date: Fri, 9 Aug 2019 11:56:08 -0300 Subject: [PATCH 7/7] =?UTF-8?q?Corre=C3=A7=C3=A3o=20da=20revis=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- primeiros-passos-com-go/mocks.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/primeiros-passos-com-go/mocks.md b/primeiros-passos-com-go/mocks.md index fe271585..d300e9dc 100644 --- a/primeiros-passos-com-go/mocks.md +++ b/primeiros-passos-com-go/mocks.md @@ -2,7 +2,7 @@ [**Você pode encontrar todos os códigos para esse capítulo aqui**](https://github.com/larien/learn-go-with-tests/tree/master/mocks) -Te pediram para criar um programa que conta a partir de 3, imprimindo cada número em uma linha nova (com um segundo intervalo entre cada uma) e quando chega a zero, imprime "Vai!" e sai. +Te pediram para criar um programa que conta a partir de 3, imprimindo cada número em uma linha nova (com um segundo de intervalo entre cada uma) e quando chega a zero, imprime "Vai!" e sai. ```text 3 @@ -143,7 +143,7 @@ Depois, precisamos fazer o software imprimir 2, 1 e então "Vai!". ## Escreva o teste primeiro -Após investirmos tempo e esforço para fazer o principal funcionar, podemos iterar nossa solução com segurança e de forma simples. Não vamos mais precisar para parar e executar o programa novamente para ter confiança de que ele está funcionando, desde que a lógica esteja testada. +Após investirmos tempo e esforço para fazer o principal funcionar, podemos iterar nossa solução com segurança e de forma simples. Não vamos mais precisar parar e executar o programa novamente para ter confiança de que ele está funcionando, desde que a lógica esteja testada. ```go func TestContagem(t *testing.T) { @@ -202,7 +202,7 @@ func Contagem(saida io.Writer) { } ``` -Se executar o programa agora, você deve obter a saída de sejada, mas não tem uma contagem regressiva dramática com as pausas de 1 segundo. +Se executar o programa agora, você deve obter a saída desejada, mas não tem uma contagem regressiva dramática com as pausas de 1 segundo. Go te permite obter isso com `time.Sleep`. Tente adicionar essa função ao seu código. @@ -309,7 +309,7 @@ func Contagem(saida io.Writer, sleeper Sleeper) { } ``` -Se tentar novamente, nossa `main` não vai mais compilar pelo menos motivo: +Se tentar novamente, nossa `main` não vai mais compilar pelo mesmo motivo: ```text ./main.go:26:11: not enough arguments in call to Contagem @@ -340,8 +340,6 @@ func main() { Agora o teste está compilando, mas não passando. Isso acontece porque ainda estamos chamando o `time.Sleep` ao invés da injetada. Vamos arrumar isso. -The test is now compiling but not passing because we're still calling the `time.Sleep` rather than the injected in dependency. Let's fix that. - ```go func Contagem(saida io.Writer, sleeper Sleeper) { for i := inicioContagem; i > 0; i-- { @@ -488,7 +486,7 @@ Agora temos nossa função e suas duas propriedades testadas adequadamente. ## Extendendo o Sleeper para se tornar configurável -Uma funcionalidadee legal seria o `Sleeper` seja configurável. +Uma funcionalidade legal seria o `Sleeper` ser configurável. ### Escreva o teste primeiro