Olá, mundo
Você pode encontrar todos os códigos para esse capítulo aqui
É comum o primeiro programa em uma nova linguagem ser um Olá, mundo.
Crie uma pasta onde quiser
Dentro da pasta, crie um arquivo chamado
ola.go
e coloque o seguinte código dentro dele
Para executá-lo, go run ola.go
Como isso funciona?
Quando você escreve um programa em Go, há um pacote main
definido com uma função(func
) main
(principal) dentro dele. Os pacotes são maneiras de agrupar códigos Go relacionados.
A palavra reservada func
é utilizada para que você defina uma função com um nome e um conteúdo.
Ao usar import "fmt"
, estamos importando um pacote que contém a função Println
que será utilizada para imprimir (escrever) um valor na tela.
Como testar isso?
Como você testaria isso? É bom separar seu "domínio"(suas regras de negócio) do resto do mundo (efeitos colaterais). A função fmt.Println
é um efeito colateral (que está imprimindo um valor no stdout [saída padrão do terminal]) e a string que estamos enviando para dentro dela é nosso domínio.
Então, vamos separar essas referências para ficar mais fácil para testarmos.
Criamos uma nova função usando func
, mas dessa vez adicionamos outra palavra reservada string
na sua definição. Isso significa que essa função terá como retorno uma string
(cadeia de caracteres).
Agora, criaremos outro arquivo chamado ola_test.go
onde iremos escrever um teste para a nossa função Ola
.
Módulos Go?
A próxima etapa é executar os testes. Digite go test
em seu terminal. Se os testes passarem, provavelmente você está usando uma versão anterior do Go. No entanto, se você estiver usando Go 1.16 ou posterior, os testes provavelmente não serão executados. Em vez disso, você verá uma mensagem de erro como esta no terminal:
Qual é o problema? Em uma palavra, módulos. Felizmente, o problema é fácil de resolver. Digite go mod init ola
em seu terminal. Isso criará um novo arquivo com o seguinte conteúdo:
Este arquivo fornece às ferramentas go
informações essenciais sobre o seu código. Se você planeja distribuir sua aplicação, você incluiria onde o código está disponível para download, bem como informações sobre dependências. Por enquanto, seu arquivo de módulo é mínimo e você pode deixá-lo assim. Para ler mais sobre os módulos, você pode verificar a referência na documentação do Golang. Podemos voltar a testar e aprender o Go agora, pois os testes devem ser executados, mesmo no Go 1.16.
Em capítulos futuros, você precisará executar go mod init ALGUM_NOME
em cada nova pasta antes de executar comandos como go test
ou go build
.
De volta ao teste
Execute go test
em seu terminal. Deve ter passado! Apenas para verificar, tente quebrar o teste, alterando a string esperado
.
Observe como você não teve que escolher entre vários frameworks de teste e, em seguida, descobrir como instalar. Tudo o que você precisa está embutido na linguagem e a sintaxe é a mesma do resto do código que você escreverá.
Escrevendo testes
Escrever um teste é como escrever uma função, com algumas regras:
Precisa estar em um arquivo com um nome parecido com
xxx_test.go
A função de teste precisa começar com a palavra
Test
A função de teste recebe um único argumento, que é
t *testing.T
Para usar o tipo
*testing.T
, você precisa importar"testing"
, como fizemos comfmt
no outro arquivo
Por enquanto é o bastante para saber que o nosso t
do tipo *testing.T
é a nossa porta de entrada para a ferramenta de testes e assim você poderá utilizar o t.Fail()
quando precisar relatar um erro.
Abordando alguns novos tópicos:
if
if
Instruções if
em Go são muito parecidas com as de outras linguagens.
Declarando variáveis
Estamos declarando algumas variáveis com a sintaxe nomeDaVariavel := valor
, que nos permite reutilizar alguns valores nos nossos testes de maneira legível.
t.Errorf
t.Errorf
Estamos chamando o método Errorf
em nosso t
que irá imprimir uma mensagem e falhar o teste. O sufixo f
no final de Errorf
representa que podemos formatar e montar uma string com valores inseridos dentro de valores de preenchimentos %s
. Quando fazemos um teste falhar, devemos ser bastante claros com o que aconteceu.
Iremos explorar a diferença entre métodos e funções depois.
Go doc
Outra funcionalidade importante do Go é sua documentação. Você pode ver a documentação na sua máquina rodando godoc -http :8000
. Se acessar localhost:8000/pkg no seu navegador, verá todos os pacotes instalados no seu sistema.
A vasta biblioteca padrão da linguagem tem uma documentação excelente com exemplos. Deve valer a pena dar uma olhada em http://localhost:8000/pkg/testing/ para verificar o que está disponível para você.
Se você não tiver o comando godoc
, talvez esteja usando uma versão mais recente do Go (1.14 ou posterior), que não inclui mais o godoc
. Você pode instalá-lo manualmente com go install golang.org/x/tools/cmd/godoc
.
nota: Se você tiver usando Go 1.17, ou superior, você deve instalar o godoc com go install golang.org/x/tools/cmd/godoc
, pois o comando go get
para instalar executáveis ficou obsoleto.
Olá, VOCÊ
Agora que temos um teste, podemos iterar sobre nosso software de maneira segura.
No último exemplo, escrevemos o teste somente depois do código ser escrito apenas para que você pudesse ter um exemplo de como escrever um teste e declarar uma função. A partir de agora, escreveremos os testes primeiro.
Nosso próximo requisito é nos deixar especificar quem recebe a saudação.
Vamos começar especificando esses requisitos em um teste. Estamos praticando TDD (Desenvolvimento Orientado a Testes) de forma bastante simples e que nos permite ter certeza que nosso teste está testando o que precisamos. Quando você escreve testes retroativamente existe o risco que seu teste possa continuar passando mesmo que o código não esteja funcionando como esperado.
Agora, rodando go test
, deve ter aparecido um erro de compilação:
Quando estiver usando uma linguagem estaticamente tipada como Go, é importante dar atenção ao compilador. O compilador entende como seu código deve se encaixar, não delegando essa função para você.
Neste caso, o compilador está te falando o que você precisa fazer para continuar. Temos que mudar a nossa função Ola
para receber um argumento.
Edite a função Ola
para que um argumento do tipo string seja aceito:
Se tentar rodar seus testes novamente, seu arquivo ola.go
irá falhar durante a compilação porque você não está passando um argumento. Passe "mundo" como argumento para fazer o teste passar.
Agora, quando for rodar seus testes, você verá algo parecido com isso:
Finalmente temos um programa que compila, mas que não está satisfazendo os requisitos de acordo com o teste.
Vamos, então, fazer o teste passar usando o argumento nome
e concatenar com Olá,
Quando você rodar os testes, eles irão passar. É comum como parte do ciclo do TDD refatorar o nosso código agora.
Uma nota sobre versionamento de código
Nesse ponto, se você estiver usando um versionamento de código (que você deveria estar fazendo!) eu faria um commit
do código no estado atual. Agora, temos um software funcional suportado por um teste.
No entanto, eu não faria um push para a branch principal, pois planejo refatorar em breve. É legal fazer um commit nesse ponto porque você pode se perder com a refatoração. Fazendo um commit você pode sempre voltar para a última versão funcional do seu software.
Não tem muita coisa para refatorar aqui, mas podemos introduzir outro recurso da linguagem: constantes.
Constantes
Constantes podem ser definidas como o exemplo abaixo:
Agora, podemos refatorar nosso código:
Depois da refatoração, rode novamente os seus testes para ter certeza que você não quebrou nada.
Constantes devem melhorar a performance da nossa aplicação, assim como evitar que você crie uma string "Ola, "
para cada vez que Ola
é chamado.
Para esclarecer, o aumento de performance é incrivelmente insignificante para esse exemplo! Mas vale a pena pensar em criar constantes para capturar o significado dos valores e, às vezes, para ajudar no desempenho.
Olá, mundo... novamente
O próximo requisito é: quando nossa função for chamada com uma string vazia, ela precisa imprimir o valor padrão "Olá, mundo", ao invés de "Olá, ".
Começaremos escrevendo um novo teste que irá falhar
Aqui nós estamos apresentando outra ferramenta em nosso arsenal de testes, os subtestes. Às vezes, é útil agrupar testes em torno de uma "coisa" e, em seguida, ter subtestes descrevendo diferentes cenários.
O benefício dessa abordagem é que você poderá construir um código que pode ser compartilhado por outros testes.
Há um código repetido quando verificamos se a mensagem é o que esperamos.
A refatoração não vale apenas para o código de produção!
É importante que seus testes sejam especificações claras do que o código precisa fazer.
Podemos e devemos refatorar nossos testes.
O que fizemos aqui?
Refatoramos nossa asserção em uma função. Isso reduz a duplicação e melhora a legibilidade de nossos testes. No Go, você pode declarar funções dentro de outras funções e atribui-las a variáveis. Você pode chamá-las, assim como as funções normais. Precisamos passar t *testing.T
como parâmetro para que possamos dizer ao código de teste que ele falhará quando necessário.
t.Helper()
é necessário para dizermos ao conjunto de testes que este é um método auxiliar. Ao fazer isso, quando o teste falhar, o número da linha relatada estará em nossa chamada de função, e não dentro do nosso auxiliar de teste. Isso ajudará outros desenvolvedores a rastrear os problemas com maior facilidade. Se você ainda não entendeu, comente, faça um teste falhar e observe a saída do teste.
Agora que temos um teste bem escrito falhando, vamos corrigir o código usando um if
.
Se executarmos nossos testes, veremos que ele satisfaz o novo requisito e não quebramos acidentalmente a outra funcionalidade.
De volta ao controle de versão
Agora estamos felizes com o código. Eu adicionaria mais um commit ao anterior para que possamos verificar o quão adorável ficou o nosso código com os testes.
Disciplina
Vamos repassar o ciclo novamente:
Escrever um teste
Compilar o código sem erros
Rodar o teste, ver o teste falhar e certificar que a mensagem de erro faz sentido
Escrever a quantidade mínima de código para o teste passar
Refatorar
Este ciclo pode parecer tedioso, mas se manter nesse ciclo de feedback é importante.
Ele não apenas garante que você tenha testes relevantes, como também ajuda a projetar um bom software refatorando-o com a segurança dos testes.
Ver a falha no teste é uma verificação importante porque também permite que você veja como é a mensagem de erro. Para quem programa, pode ser muito difícil trabalhar com uma base de código que, quando há falha nos testes, não dá uma ideia clara de qual é o problema.
Assegurando que seus testes sejam rápidos e configurando suas ferramentas para que a execução de testes seja simples, você pode entrar em um estado de fluxo ao escrever seu código.
Ao não escrever testes, você está comprometendo-se a verificar manualmente seu código executando o software que interrompe seu estado de fluxo, o que não economiza tempo, especialmente a longo prazo.
Continue! Mais requisitos
Caramba, temos mais requisitos. Agora precisamos suportar um segundo parâmetro, especificando o idioma da saudação. Se for passado um idioma que não reconhecemos, use como padrão o português.
Devemos ter certeza de que podemos usar o TDD para aprimorar essa funcionalidade facilmente!
Escreva um teste para um usuário, passando espanhol. Adicione-o ao conjunto de testes existente.
Lembre-se de não trapacear! Primeiro os testes. Quando você tenta executar o teste, o compilador deve reclamar porque está chamando Ola
com dois argumentos ao invés de um.
Acerte os problemas de compilação, adicionando um novo argumento do tipo string
ao método Ola
:
Quando você tentar executar o teste novamente, ele se queixará da função não ter recebido argumentos o suficiente para Ola
nos seus outros testes em ola.go
:
Corrija-os passando strings
vazia. Agora todos os seus testes devem compilar e passar, além do nosso novo cenário:
Podemos usar if
aqui para verificar se o idioma é igual a "espanhol" e, em caso afirmativo, alterar a mensagem:
Os testes devem passar agora.
Agora é hora de refatorar. Você verá alguns problemas no código, sequências de caracteres "mágicas", algumas das quais são repetidas. Tente refatorar você mesmo, a cada alteração, execute novamente os testes para garantir que sua refatoração não esteja quebrando nada.
Francês
Escreva um teste que verifique que quando passamos o idioma
"francês"
, obtemos"Bonjour, "
Veja o teste falhar, verifique se a mensagem de erro é fácil de ler
Faça a mínima alteração de código o suficiente para que o teste passe
Você pode ter escrito algo parecido com isso:
switch
switch
Quando você tem muitas instruções if
verificando um valor específico, é comum usar uma instrução switch
. Podemos usar o switch
para refatorar o código facilitando a leitura e a sua extensão, caso desejarmos adicionar suporte a mais idiomas posteriormente.
Faça um teste para incluir agora uma saudação no idioma de sua escolha e você deve ver como é simples estender nossa fantástica função.
Uma...última...refatoração?
Você pode achar que talvez nossa função esteja ficando um pouco grande. A refatoração mais simples para isso seria extrair algumas funcionalidades para outra função.
Alguns novos conceitos:
Em nossa assinatura de função, criamos um valor de retorno chamado
(prefixo string)
.Isso criará uma variável chamada
prefixo
na nossa função.Lhe será atribuído o valor "zero". Isso dependendo do tipo, por exemplo, para
int
será0
e para strings será""
.Você pode retornar o que quer que esteja definido, apenas chamando
return
ao invés dereturn prefixo
.
Isso será exibido no
go doc
para sua função, para que possa tornar a intenção do seu código mais clara.
default
será escolhido caso o valor recebido não corresponda a nenhuma das outras instruçõescase
doswitch
.O nome da função começa com uma letra minúscula. As funções públicas em Go começam com uma letra maiúscula e as privadas, com minúsculas. Não queremos que as partes internas do nosso algoritmo sejam expostas ao mundo, portanto tornamos essa função privada.
Resumindo
Quem imaginaria que você poderia tirar tanto proveito de um Olá, mundo
?
Até agora você deve ter alguma compreensão de:
Algumas das sintaxes da linguagem Go para:
Escrever testes
Declarar funções, com argumentos e tipos de retorno
if
,const
eswitch
Declarar variáveis e constantes
O processo TDD e por que as etapas são importantes
Escreva um teste que falhe e veja-o falhar, para que saibamos que escrevemos um teste relevante para nossos requisitos e vimos que ele produz uma descrição da falha fácil de entender
Escrever a menor quantidade de código para fazer o teste passar, para que saibamos que temos um software funcionando
Em seguida, refatorar, tendo a segurança de nossos testes para garantir que tenhamos um código bem feito e fácil de trabalhar
No nosso caso, passamos de Ola()
para Ola("nome")
, para Ola ("nome"," Francês ")
em etapas pequenas e fáceis de entender.
Naturalmente, isso é trivial comparado ao software do "mundo real", mas os princípios ainda permanecem. O TDD é uma habilidade que precisa de prática para se desenvolver. No entanto, você terá muito mais facilidade em escrever software sendo capaz de dividir os problemas em pedaços menores que possa testar.
Last updated