Arquivo

Textos com Etiquetas ‘Testes’

Não escreva código novo sem antes ter um teste falhando

16 de fevereiro de 2010

O título desse post é uma frase de Kent Beck, autor do livro Test Driven Development: By Example. A idéia é que você sempre escreva testes antes de implementar qualquer código. Após o teste escrito falhar, você implementa o suficiente para fazer o teste passar. Com os testes passando, você está livre para refatorar (tanto implementação, quanto teste). A partir daí você cria um novo teste e segue o mesmo fluxo. Esse ciclo se repete até você ter toda a funcionalidade deseja implementada, ou seja, ter testes para todas as possibilidades da sua implementação.

Este é o “bê-a-bá” de TDD, mas na prática isso dificilmente acontece. Não porque não queremos fazer testes (se você não quiser escrever testes, o problema é todo seu), mas porque somos exímios programadores, desenvolvemos orientados a testes por anos, e não precisamos mais seguir os baby steps (passos de bebê), afinal somos programadores maduros.

Sendo assim, pulamos etapas: codificamos primeiro para depois escrever os testes, refatoramos mesmo com testes ainda não passando, escrevemos mais testes mesmo tendo testes anteriores falhando, e por aí vai.

Cuidado! Por mais que você seja um programador “fodão”, ainda sim você pode deixar de testar alguma coisa. Uma lógica de negócio, uma alternativa de fluxo ou uma condição de erro podem passar desapercebidas ao se pular as etapas básicas de TDD. Esse teste faltando, por mais simples que seja, pode causar um erro em ambiente de produção e causar transtornos para o cliente e/ou usuário final da sua aplicação.

Vamos utilizar como exemplo uma simulação de pareamento, onde uma dupla de desenvolvedores irá criar um método chamado positive_balance? para dizer se uma conta bancária, representada pela classe BankAccount, possui saldo positivo.

A linguagem utilizada será Ruby e o framework para testes será RSpec.

Os programadores são Félix (piloto do pareamento) e Péricles. Os dois concordam em iniciar criando a classe BankAccount com a declaração do método positive_balance? sem nenhuma implementação:

class BankAccount
  def positive_balance?

  end
end

- Legal, agora vamos escrever nosso teste. - diz Péricles.
- Para uma conta bancária possuir fundos é nessário que seu saldo seja maior que zero.

describe BankAccount do
  it "should have positive balance" do
    account = BankAccount.new
    account.value = 100.00
    account.positive_balance?.should be_true
  end
end

Eles rodam o teste:

F

1)
NoMethodError in 'BankAccount should have positive balance'
undefined method `value=' for #
./spec/bank_account_spec.rb:6:

Finished in 0.010015 seconds

1 example, 1 failure

E o resultado com erro diz a eles que não existe um atributo value na classe BankAccount. Félix e Péricles o criam:

class BankAccount
  attr_accessor :value

  def positive_balance?

  end
end

E executam o teste novamente:

F

1)
'BankAccount should have positive balance' FAILED
expected nil to be true
./spec/bank_account_spec.rb:7:

Finished in 0.010605 seconds

1 example, 1 failure

O teste falha. Então chegou a hora de escrever código novo, a implementação da funcionalidade que eles querem. Félix implementa o suficiente para o teste passar.

class BankAccount
  attr_accessor :value

  def positive_balance?
    true
  end
end

Péricles discorda totalmente.
- Cê tá louco, mano?! Vai retornar true para tudo?! O cara vai ter sempre saldo na conta?

Félix argumenta.
- A gente não precisa escrever código suficiente para o teste passar? Isso é suficiente.

E roda o teste:

.

Finished in 0.009987 seconds

1 example, 0 failures

- Viu? Passou. - finaliza Félix.
- Mas isso é muito baby step. - reclama Péricles - Vamos implementar o código real, ou seja:

class BankAccount
  attr_accessor :value

  def positive_balance?
    self.value > 0
  end
end

- Mas por que vamos implementar isso agora? Afinal nossos testes estão passando. - Félix rebate.
- Porque está na cara que esse código retornando true sempre não funciona.

Félix continua forçando a discussão.
- Como não funciona? Funciona sim, os testes estão passando.
- Funciona, mas a implementação está errada. - diz Péricles.
- Errada? Mas atende os requisitos até o momento. Afinal, os testes são para assegurar que a lógica do negócio está sendo cumprida.

Péricles fica pensativo.
- Mas o único teste que fizemos não está cobrindo todos os casos da lógica.
- Concordo com você, Péricles. E o que devemos fazer agora então?
- Devemos escrever um teste em que a conta bancária não irá ter fundos.
- Exatamente! - confirma Félix.

E eles continuam nesse linha de raciocínio até o final do pareamento.

Não estou aqui dizendo que você tem que sempre seguir à risca o Red Green Refactor do TDD, muito menos usar baby steps toda vez que você codificar (afinal, a vida não é um dojo), mas que você tenha atenção e controle do que está fazendo, tento o domínio da funcionalidade que está implementando.

Uma das maneiras de se conseguir isso é com pareamento. Seu par irá lhe ajudar a não deixar escapar nenhum teste. Outra maneira é com inspeção de código. De repente, outro desenvolvedor que não participou da implementação pode enxergar algo que você (e/ou seu par) não viu.

De qualquer forma, seja humilde. Use as etapas de TDD para funcionalidades ou lógica mais complexas. E também fique livre para burlar as regras para implementar coisas simples e funcionalidades básicas, ou quando estiver bastante à vontade e seguro do que está fazendo. Mas nunca, eu disse nunca, deixe de escrever os testes.

TDD , , ,

Desprenda-se de convenções de nomenclatura em nome de testes

21 de novembro de 2009

Eu compartilho da opinião de Jimmy Bogard, que diz que os nomes dos testes precisam descrever o que e o porque, a partir da perspectiva do usuário, onde o desenvolver possa ler o nome do teste e claramente entender o comportamento que é esperado.

Um teste unitário nada mais é que um método em uma classe, e tanto em C# como Java, existem convenções de nomenclatura de métodos.

Em C#, nome de métodos são declarados utilizando Pascal Case:

[TestMethod]
public void ProductShouldHaveAtLeastOneCategory()
{
  //Test implementation.
}

Já em Java, convencionou-se escrever métodos utilizando Camel Case:

@Test
public void productShouldHaveAtLeastOneCategory() {
  //Test implementation.
}

Muitas vezes, o nome desses testes (métodos) ficam um tanto longos, como os exemplos acima. Dessa forma, a legibilidade não é muito boa.

Seguindo um dos conselhos de Neal Ford, em sua apresentação 10 Ways to Improve Your Code, você pode deixar de lado as convenções de nomenclatura da linguagem em favor da legilidade dos nomes dos seus testes. Escreva o nome do teste como se fosse uma frase, nada de letras maiúsculas para cada palavra, e use “_” (underscore) para separar as palavras.

Veja como fica o exemplo acima em C#:

[TestMethod]
public void Product_should_have_at_least_one_category()
{
  //Test implementation.
}

E agora em Java:

@Test
public void product_should_have_at_least_one_category() {
  //Test implementation.
}

Não há nenhum mal em se desprender das convenções de nomenclatura de C# e Java em prol da legibilidade dos nomes dos testes. Afinal, testes são uma documentação executável e nós queremos uma documentação clara para nosso código.

TDD , , , , , , ,

Cheeseburgers, Decorators e Mocks

29 de julho de 2009

Em São Paulo, eu sempre comi cheeseburgers feitos com pão, hamburguer e queijo. Mas quando eu fui para Itararé, cidade do interior do estado de São Paulo, descobri que eles também colocavam milho no sanduíche.

Para exemplificar, vamos imaginar que o cheeseburger de Ilhéus-BA, venha com molho de pimenta. Só para constar, eu nunca fui para Ilhéus, apesar de ser a cidade natal de meu pai. Então na verdade não tenho a mínima idéia de como seja o cheeseburger de lá.

Imagem original de MarketFare Foods, Inc.

Imagem original de MarketFare Foods, Inc.

Vamos transportar esses três tipos de cheeseburgers para objetos e fazer alguns testes com eles. Usarei como plataforma .NET, linguagem C#, a ferramenta de testes unitários que vem com o Visual Studio 2008 e o Rhino Mocks como framework de criação de mocks.

Leia mais…

.NET, Arquitetura , , , , , , , , , , , , ,

fisl10 - TDD e Rails: Mais rápido, mais forte e melhor

30 de junho de 2009

A primeira apresentação que assisti no fisl10 foi muito boa. Lucas Húngaro mostrou formas de criar aplicações Ruby on Rails com testes, passando um pouco da sua experiência em desenvolvimento Web.

Lucas Húngaro

A palestra foi dividida em quatro partes: Fundamentos, Abordagens, Como eu desenvolvo com testes no Rails e Dicas. Mas separei aqui em mais duas: Boas Práticas e Maus Sinais.

Leia mais…

Eventos, Ruby, TDD , , , , , , , , , , , , ,

Programação serena

20 de junho de 2009

Meu pai, que considero um exemplo de pessoa honesta, humilde e de bom caráter, me ensinou que na vida precisamos agir com serenidade. Ele me apresentou a oração da serenidade:

Concedei-me, Senhor, a serenidade necessária para aceitar as coisas que não posso modificar, coragem para modificar aquelas que posso e sabedoria para distinguir umas das outras.

Agora, o que isso tem a ver com desenvolvimento de software?

Imagine um cenário que você precise incluir uma nova funcionalidade em uma aplicação existente. Suponha que o código dessa aplicação não está muito bom, há acoplamentos entre os objetos, pouca cobertura de testes e a arquitetura deixa a desejar. Você precisa incluir a nova funcionalidade, mas não pode aumentar o débito técnico.

Por outro lado, você não irá refazer toda a aplicação de uma forma melhor, pois além de você não ter tempo (e dinheiro) disponível para isso, o sistema hoje atende os requisitos atuais e executa sem problemas.

Nessa situação, você precisa de sabedoria para distinguir o que pode ser modificado neste momento no código existente para melhorá-lo e o que você não irá modificar agora, já que não afeta diretamente a nova funcionalidade.

Você necessita de coragem para modificar o código legado, pagar o débito técnico, criar testes automatizados, refatorar, tornar o código mais claro, reformular o design, diminuir acoplamentos.

Você terá serenidade para aceitar que nem tudo pode ser melhorado agora, pois você tem prazo e orçamento a serem cumpridos. O objetivo neste momento é implementar a nova funcionalidade.

Com serenidade você pode alcançar uma melhoria contínua no seu software.
.
Obs.: Após rascunhar o conteúdo deste post dei uma olhada no meu leitor de feeds e me deparei com o post Parar e Refatorar? da InfoQ Brasil. A discussão sobre o tema é longa, mas a serenidade também se aplica.

Arquitetura , , , ,

.NET Architects Day 2009

13 de junho de 2009

No próximo dia 27 de junho vai rolar o primeiro evento do grupo de discussão sobre arquitetura de software .NET Architects.

Eu infelizmente não vou, pois estarei em outro evento. Mas Luciano Coelho e Rodrigo Ortiz, que trabalham comigo, irão e poderão nos contar tudo que aconteceu.

Algo interessante é que exatamente todos os assuntos que serão abordados, estaremos utilizando em um novo projeto que irá iniciar no segundo semestre.

Veja o conteúdo das palestras:

Programando com prazer com Domain Driven Design (DDD)
Giovanni Bassi
O Domain Driven Design é uma nova abordagem para desenvolvimento de software. Mas não é tão nova assim. Ela reune melhores práticas de OO e traz uma nova visão a velhos conceitos. Entenda nesta palestra a proposta do DDD, e porque ele pode mudar sua maneira de programar.

Utilizando Injeção de Dependência com Unity (Enterprise Library)
Leandro Daniel
Nessa palestra veremos o padrão de Injeção de Dependência como uma alternativa técnica na construção de aplicações plugáveis, onde se deseja manter a flexibilidade para troca de componentes com menor impacto de manutenção, maior reusabilidade e facilidade na aplicação de testes.

ASP.NET MVC: tome seu HTML de volta
Victor Cavalcante
Nessa palestra veremos o que é o ASP.NET MVC e o que ele não é, como ele funciona, diferenças entre ASP.NET MVC e Web Forms, extensibilidade, testabilidade, criação de templates com T4 e jQuery. A intenção desta palestra é dar informações suficientes para que o arquiteto decida utilizar ou não ASP.NET MVC.

ORM - Sendo preguiçoso com NHibernate
Juliano Oliveira
Nessa palestra você verá os principais pontos que fazem dos frameworks de ORM e do NHibernate ferramentas tão importantes nos projetos, desmistificar seus maiores mitos, os principais recursos, ferramentas de análise (NHProof) e verá também como ser produtivo com o NHibernate.

Testes: garantindo que seu código faz o que você quer
Mauricio Aniche
Entenda porque testes automatizados de software são importantes e quais as vantagens que ele traz para a equipe de desenvolvimento. Veja também na prática que criar testes automatizados é simples, rápido e realmente útil.

O valor da inscrição é de R$ 50,00 e o evento terá aproximadamente 9 horas de duração.
Mais informações você pode ter diretamente na página do evento.

.NET, Arquitetura, Eventos, TDD , , , , , , , , , , , ,

Apresentação de TDD na Fatec Jundiaí

21 de abril de 2009

Nos dias 6 a 9 de abril, a Fatec Jundiaí organizou o evento “Semana da Tecnologia”, com várias atividades acadêmicas para seus alunos.

A convite do Prof. Demerval, que dá aula de Teoria da Administração, e também de Luciano Coelho, aluno do curso Tecnologia em Informática para Gestão de Negócios da Fatec Jundiaí e companheiro de trabalho, na quinta-feira, dia 9, fiz uma apresentação de introdução ao TDD - Test Driven-Development.

O público presente era de alunos iniciando no desenvolvimento de software e que tiveram ali seu primeiro contato com o desenvolvimento orientado a testes.

A apresentação (com áudio) você pode acompanhar abaixo e o código-fonte dos testes utilizados na apresentação você pode baixar aqui.

Referências:

Eventos, TDD , , , ,