Posts Tagged ‘PHP’

From PHP to Rails (5 meses depois)

fevereiro 13th, 2011

Salve pessoal,

A algum tempo decidi migrar do PHP para o Rails e desde então não tenho feito nada relacionado à PHP e me dedicado exclusivamente ao estudo e trabalho com Ruby on Rails. Os motivos eu expliquei bem e quase 6 meses depois eu acho que já posso dar uma explanada boa do que vem sendo meu cotidiano de projetos e experiências com a ferramenta.

Linguagem Ruby

O Ruby é uma linguagem fantástica: o Rails se aproveita muito bem de todas as capacidades e liberdades (as vezes até libertinagens) dela para fazer magia com algumas coisas. É muito impressionante você sair de uma linguagem estritamente movida basicamente à funções e classes para uma linguagem mutiparadigma que te deixa programar de várias formas diferentes.

A adaptação é bem custosa para quem está acostumado com o PHP mas vale muito a pena. Existem coisas como essa abaixo que realmente te deixam feliz.

1
2
3
10.times {
|i| puts i
}

A principalmente dificuldade que acredito que se encontra é realmente essa cara da maioria das coisas do Ruby que se tem que se acostumar a ler e interpretar. Mas depois que se começa a aprender é ótimo.

Gerenciador de pacotes Ruby Gems

Hoje em dia, a maioria das linguagens legais tem seus repositórios de bibliotecas. No PHP usei bastante o PEAR e algumas coisas do PHPClasses. No Ruby extendemos seu poder com o uso de gems e estas tem uma maneira muito legal de rastrear dependências e tudo mais através de um comando muito simplista:

gem install pacote_magico_ou_arquivo_da_gem

Ao contrário do PEAR que exige configurações e alguma coisas que um mortal as vezes não consegue se virar, o comando gem é muito simples e efetivo. Ele com certeza é a coisa mais legal desde o APT-GET. :) Vale avisar que se você seguiu a instalação padrão do rails, ele buscará sempre as coisas do rubygems.org que é o repositório padrão de gems.

O rubygems.org hoje tem trocentas bilhões de gems que ajudam um monte a desenvolver e não re-inventar a roda. :)

A framework Rails

Apesar das trocentas framerworks que temos para o PHP, poucas são realmente maduras como o CodeIgniter (de todas a melhor hoje em dia na minha opinião), CakePHP, Zend, Prado, Symfony e por ai vai. A comunidade Ruby se concentra MUITO em usar e divulgar o Rails, framework que transformou o Ruby num hipe louco de uma hora pra outra.

Todavia, o merecimento é mais que merecido: o Rails desde a versão 2 é uma framework que vai direto ao ponto e permite uma produtividade incrível e se aproveita muito da questão do uso de convenções para ficar ainda mais rápido.

Já trabalhei com frameworks em várias linguagens e posso afirmar que sentir-se à vontade no Rails é uma questão de dias e o vislumbre vem em semanas. Existe CLARO suas “limitações”: entre aspas pois na verdade dentro do escopo de propósito do Rails você as vezes tem que sair das convenções e isso tem seu preço.

A maturidade da framework é outro ponto muito bom: muito conceito e forma de fazer as coisas estão muito bem resolvidas. Ela utiliza uma conjunto muito legal de gems para deixar a framework pronta para subir e meter fogo sem necessitar de bibliotecas adicionais. É instalar, criar o projeto e sair codando e pendurando as gems adicionais SE precisar.

A parte chata (que não é um problema exclusivo dela) é a documentação: existe muita informação pulverizada e espalhada que as vezes você tem que garimpar e testar muito. Ao menos fica o aprendizado no final.

Testes, RSpec e Capybara

O próprio PHP tem uma mania de escrever rápido e ir debugando: conheço pouquíssimas pessoas que trabalham com testes no PHP e a ida para o Rails me deixou ainda mais confiante que sem teste não dá de jeito nenhum. Talvez isso seja mais uma coisa de cultura da comunidade, mas as ferramentas também não ajudam muito.

Um dos pontos que mais me deu desgosto no PHP era a forma precária como as frameworks trabalhavam com testes. Na Giran, tentamos no CakePHP, tentamos no CodeIgniter e já estavamos até fazendo nossos próprios forks e remendos pra conseguir rodar bem os testes unitários, funcionais e de aceitação. Tudo isso com aquela pergunta “Putz cara, será que isso é realmente necessário?”.

O Rails se integra de uma forma perfeita ao RSpec, uma ferramenta brutal de testes, nos permitindo escrever nossos testes de uma forma muito mais legível. A integração feita entre os dois é poderosa o bastante pra tornar a prática de escrever testes uma coisa muito mais natural e legal de ser feita. Isso no PHP estava se tornando algo MUITO dolorido e custoso, coisa que não é nem de longe nosso objetivo ao programar.

Outro lance legal é o Capybara, que permite escrever os testes funcionais bem rápido também. Estamos fazendo coisas nele e gostando dos resultados. É simplesmente impressionante como a cobertura de testes da aplicação está melhor.

Um programador melhor

O mais legal desse tempo é que sem dúvida me tornei um programador melhor. Você começa a ver as coisas com um pouco mais de calma, consegue estudar melhor as aplicações, se preocupa mais com a arquitetura e vem nisso um monte de novas coisas legais para estudar que acabam te levando de volta àquele sentido gostoso de querer saber mais e mais.

Fazia um tempo bom desde que não sentia isso e pensei que que seria algo só no inicio dos estudos do Rails: 5 meses depois cá estou eu lendo mais e mais pra descobrir as sutilezas do Ruby e coisas legais de se fazer no Rails. :)

Então tá tudo perfeito?

Foram 5 meses de muito aprendizado e coisa bacana, mas nesses 5 meses nem tudo foram flores.

  • a adaptação pro Ruby para quem vem de outras linguagens não é muito fácil, embora muito excitante
  • a documentação do Rails não é tão vasta: se rala muito para saber os N jeitos de se resolver as coisas
  • inexiste comunidade Ruby no ES (estamos pensando muito em juntar quem sabe aqui no ES e começar uma)
  • sair da “convenção” do Rails as vezes é bem complexo

E é isso: tem muita coisa nesse meio que vou escrevendo daqui pra frente nas descobertas que for fazendo na Giran com os brothers do time … novos railers que estão devorando livros e livros comigo. :)

Simbora.

Moving to Python/RubyOnRails

setembro 13th, 2010

Salve people,

Estava com saudades de escrever coisas por aqui bacanas mas estava às avessas com Giran, eventos e tudo mais. É claro que que a desculpa “falta de tempo” não existe quando você está motivado e focado em algo. Continuo motivado com muita coisa, principalmente com o crescimento natural e meio que imposto pela velocidade que as coisas estão acontecendo que pedem cada vez mais uma postura e abordagem que exige muita muita MUITA disciplina.

Mas uma coisa que não me motiva à tempos foi o PHP, não pela linguagem e sim mas todo um entorno que acabavam impactando diretamente na melhoria continua disso.

Frameworks

Larguei o CakePHP pelo CodeIgniter em busca de uma framework mais light e customizável. O CodeIgniter serviu muito bem, mas peca em duas coisas muito importante que era o suporte mais integrado à testes e um ORM bacana. Nem o SimpleTest nem o PHPUnit se mostraram muito bem integrados e o ORM mais bacana que achamos foi o Overzealous DataMapper. São duas boas ferramentas, mas que não atingiram totalmente (e juntas) o objetivo que era ter coisas estáveis pra desenvolver.

A pouco tempo palestrei sobre frameworks, mas acho que tem que melhorar muito até chegar num nível de maturidade legal. Ou seja, isso acaba atrapalhando e muito a questão de trabalhar com todas as ferramentas e técnicas possíveis para o desenvolvimento de aplicações com alto nível de qualidade. Para quem não demanda toda a qualidade que estou/estamos buscando, essas ferramentas são show de bola demais.

Existe uma certa carência de um set de ferramentas que possam trabalhar em conjunto para oferecer a sustentabilidade desejada para um projeto de, digamos, qualidade máxima.

Não estou dizendo que as ferramentas são ruins mas cheguei num ponto em que queria me focar mais no negócio e por isso espero ferramentas que ja estejam maduras o suficiente para que eu possa confiar nelas. Num certo ponto estava me preocupando com questões de estabilidade e funcionamento que eu esperava ja terem sido resolvidas pelos projetos.

Desafio

Por conhecer e programar em PHP a MUITO tempo, cheguei num nível que ou me dedicava ao desenvolvimento de uma ferramenta ou algo mais tenso para manter isso aceso ou partiria para a evangelização da linguagem, o que faço em partes como um dos coordenadores do PHP-ES. Desenvolver um projeto novo é legal, mas prefiro contribuir com os que existem com patchs e o que puder … e desenvolver algo novo deve primar pela idéia em si e não pela tecnologia. E se a idéia é nova, porque não brincar com outra coisa nova?

Mas lá no fundo entrei em loop no que tange aprender mais PHP. E isso, dentro do meu universo pessoal onde mudo e toda hora procuro algo pra fazer, chegou a um ponto que ficou insustentável. Como diria o poeta “Já deu …”.

Comunidade

Acredito que faça dois anos que começamos de fato com os eventos com o PHP-ES e estava tudo indo bem exceto por dois pontos:

  • a falta de mobilização da comunidade em prol de algo que não seja discutir salários e questões banais como sindicalização no forum
  • a falta de interesse do próprio time de coordenação em querer fazer as coisas da melhor maneira, ajudando no dia-a-dia e não apenas não-presencialmente

Não julgo ninguém, mas no fundo fui me sentindo meio que lutando e tentando fazer crescer um Mercado onde as pessoas de certa forma ou não se interessem tanto, enquanto comunidade, ou não estão preocupadas com evolução, isso tanto pessoal quando novamente em comunidade.

Me amarro em fazer eventos e ensinar o pouco que sei sempre, seja por blog, por MSN, em eventos ou o que for mas no caso de eventos é um sentimento meio chato não ver as pessoas se movendo em prol de um objetivo mútuo. Deve ser a idade chegando, mas já havia passado por algo em outras áreas de atuação (fiz muitos eventos de heavy metal que rolavam várias coisas do gênero). Se não existe comunidade, você luta pra fazer crescer uma. Quando já existe e você vê o desinteresse das pessoas, você precisa tomar descisões e a minha vibe é de “estou aqui pra ajudar mas tomar a frente não tão cedo”.

Porque Python/Ruby on Rails?

A escolha do Python e Rails foi a mais natural pois ambas são linguagens de script. Além disso, uma penca de coisas me levaram a escolher essas duas também:

  • comunidade irada
  • frameworks maduras
  • ferramental para testes e tudo mais maduros
  • Orientadas a objeto de verdade
  • Preparadas para o que der e vier

O Python/Django foi uma escolha bacana no sentido de que se pode desenvolver tanto para web quanto para uma pá de outras coisas, até pra iPhone. ;)

O Ruby/Rails foi outra escolha bacana por ser atualmente, sem modismo, uma das (se não a melhor) framework para desenvolvimento web, e que segue “por default” uma filosofia voltada à qualidade e agilidade. Vi várias coisas embasbacantes na QCONSP (vou escrever um post bacana sobre essas coisas) e é motivante ver tanta gente correndo atrás da melhora não apenas da ferramenta mas da comunidade toda em si.

Muitas oportunidades sempre rolaram em relação a desenvolver com elas e acho que chegou a hora de me dedicar a isso com força.

Então PHP nunca mais tio???

Deixar de estudar uma linguagem não é um “nunca mais trabalho com ela” nem coisa do tipo. Tive ótimos feedbacks em relação aos posts de TDD com o Simpletest e pretendo continuar (mas com PHPUnit talvez) com mais algo de Selenium … enfim, coisas mais voltadas à qualidade de código final do PHP do que o desenvolvimento dele em si.

Além de continuar falando sobre PHP em relação à isso, pretendo estar ajudando a comunidade seja como palestras, ajudando os amigos da coordenação com os eventos e todos que ainda puder ajudar ensinando algo porque afinal … eu gostcho!

Enquanto isso, vamos seguindo nossas vidas e seja o que Alah quiser.

Hugs!

Review II WORKSHOP PHP-ES

agosto 28th, 2010

Salve people,

Tava com saudades aqui do blog. Ae uhaeuhAEae A correria na Giran ultimamente está pra lá de frenética e estou estudando muito pra escrever algumas coisas legais aqui e de relevância.

Rolou hoje o II Workshop PHP-ES na UVV e posso dizer que por um lado foi muito foda e pelo outro um pouco triste.

O que foi muito foda

As palestras foram altamente maneiras. Um review muito bacana do rolou está no blog do Xiquin (http://www.franciscosouza.com.br/2010/08/28/ii-workshop-de-php-do-espirito-santo-foi-show), que palestrou sobre CodeIgniter com o André Tagliati, vulgo Gligli. A palestra dos dois, inclusive, foi muito bacana assim como as palestras do Marcelo Raposo sobre práticas mágicas no MySQL e de PDO com o mestre Almir M3nd3s.

Outro ponto foi a abertura do evento para assuntos fora do eixo técnico para ir para o entorno no mundo PHP, como a plafatorma Moodle com o Lucas Coradini (nunca pensei que um designer botaria banca num evento de programadores hehehhe zuera sacanagem) e a metodologia Scrum com o Paulo Jeveaux e o Makoto Hashimoto. A escolha dos assuntos não poderia ser mais feliz, porque nas contas finais eu achei as duas palestras mais informativas pelo público presente.

Este público presente foi outra surpresa: a imensa maioria era de pessoas do interior do estado, como Cachoeiro, São Mateus e Pinheiros. Isso nos mostrou o quanto de espaço pode-se ter junto a um público que geralmente só tem acesso a informação desse tipo vindo pra cá. Tivemos alguns contatos e esperamos levar eventos de PHP para lá.

O evento transcorreu muito bem e no geral foi muito bacana até mesmo pra mim que fui sob efeito de muitas drogas anti-gripais. O sorteio no final foi um show a parte de integração e diversão com direito até a contribuição de um brinde por parte da platéia (valew Fabiano!).

Por último, o apoio PRA LÁ DE F*DA da UVV e do prof. Vinicius Rosalen, que não apenas nos cedeu toda a estrutura para a realização do evento como ajudou com café e rosquinhas pela manhã e a tarde. E também da Giran, pela mobilização geral do pessoal no preparo de conteúdo, palestras para o evento e apoio incondicional na organização do evento.

O que foi meio triste

Palestrar, terminar slides, organizar evento e tocar evento doente é foda. Aliás, qualquer coisa nessa situação é foda. Queria ter estado melhor mas no final das contas estar doente foi apenas um empecilho. :P

Ter no cast de palestrantes uma galera da Giran foi uma honra pra gente, mas por outro lado mostrou uma coisa que quase inviabilizou o evento: não tivemos NENHUMA palestra submetida pelo grupo de usuários que povoa o fórum. Parece que as pessoas preferem discutir coisas abstratas como sindicato de programadores PHP (sic) que movimentar e dar apoio aos eventos da própria comunidade.

Seguindo a lógica, de 260 pessoas inscritas não tivemos nem a metade que seria o normal. E dos que compareceram uma galera era do interior e poucas pessoas da Grande Vitória. Agora não sabemos se há um desinteresse total das pessoas da Grande Vitória por PHP, se os tópicos das palestras foram mal escolhidos ou simplesmente as pessoas se cadastram por diversão. (risos) Isso trouxe um efeito bacana que é agora nossa vontade real de levar esses eventos para o interior.

Enfim …

Para um evento que esteve no limiar do cancelamento por falta de ânimo com um cenário onde nem palestras haviam para fazer o evento, foi um PUTA evento e que me recorda o feeling que eu tinha quando tocava heavy metal em shows que as vezes só sobravam 5 pessoas na frente do palco: você está ali pelas pessoas que ainda acreditam no ideal e no que você acredita e por elas VALE MUITO A PENA.

Simbora.

PHPzeiro? Adote um Framework! :)

dezembro 22nd, 2009

É notável a quantidade de aplicações em PHP que ainda utilizam nosso velho e conhecido modo Macarrônico de programar: dezenas de snippets e blocos de código que trabalham com regras de negócio, apresentação e tudo mais espalhados por N lugares na aplicação.

O PHP Macarrônico é assim

O PHP Macarrônico é assim

Esse método é justificável dentro da PHP até certo ponto: a própria linguagem tem por princípio a simplicidade e velocidade na codificação e resolução de problemas. O próprio Rasmus Lerdorf, criador do PHP, já se mostrou bem contrário aos frameworks atuais pois eles são lentos e não escaláveis, culpa do feeling de  ”faz-tudo” que a maioria delas leva no sentido de continuar ostentando a bandeira de “desenvolvimento rápido” da PHP, que muita gente confunde com gambiarras e que transformou a PHP em sinônimo de POG (Programação Orientada à Gambiarras).

» Read more: PHPzeiro? Adote um Framework! :)

Mock Objects no SimpleTest

dezembro 4th, 2009

Olá pessoal,

Continuando nossa sequência de artigos sobre o SimpleTest, já aprendemos como fazer testes unitários e agrupa-los para facilitar a execução em lote: agora vamos falar um pouco sobre mock objects.

Até agora, nossos testes unitários se resumiram a testar métodos e funcionalidades que envolviam apenas uma classe como nossa calculadora: tínhamos um método chamado “somar” que fazia parte da própria classe e recebia como parametro de entrada apenas dois inteiros.

A idéia do teste unitário (ou de unidade), como o próprio nome diz, é isolar e testar apenas aquele ponto e funcionalidade do software: então é imprescindível que possamos isolar da melhor maneira apenas a classe/métodos que desejamos testar para que, caso apresente falha, possamos identificar exatamente onde a falha ocorreu.

Mas e quando nossa classe depende de outra(s) classe(s) para fazer um método funcionar ?

» Read more: Mock Objects no SimpleTest

Problema com IDs alfanuméricos no form->input (select) do CakePHP

novembro 25th, 2009

Para quem já está mexendo com CakePHP a algum tempo, algumas limitações de funcionalidades podem tirar um pouco o sono de quem está muito mal acostumado com a produtividade da framework. Em geral, toda framework tem seus pontos fracos.

A algum tempo, tive um problema curioso: a chave primária de uma tabela teria valores alfanuméricos. Ou seja: valores como “205-A”, “JB02″ e outros bizarros seriam possíveis. Regra de negócio definida, modificação do modelo para o nome de chave fora da convenção e tudo corria bem até que populei um select.
:( Qual não foi minha surpresa em ver que o CakePHP, além de não marcar o valor correto, em certos casos ainda selecionava mais de um valor no select. #fail total.

» Read more: Problema com IDs alfanuméricos no form->input (select) do CakePHP

Agrupando casos de teste no SimpleTest

julho 26th, 2009

Aloha,

Primeiramente, obrigado ao pessoal pelas belas palavras de incentivo e tudo mais: é esse tipo de coisa que nos empolga pra continuar trabalhando e estudando duro.

Em nosso post de iniciação no SimpleTest, criamos um caso de teste completo de uma calculadora. Relembrando nossa telinha bonita do caso de teste…

ishot-1

Agora vejamos … e se por exemplo, tivéssemos não apenas uma calculadora em nossa aplicação, mas também uma agenda de compromissos, uma agenda de contatos, um wiki, um mural de recados e … enfim, se nossa aplicação fosse composta por N classes como faríamos para rodar os casos de teste unitários de TODAS AS CLASSES ?

Na TDD, como vimos antes, escrevemos todos os testes antes de começarmos a implementar nossa aplicação em si: quando pensamos “rodar os testes” isso se aplica à todas as classes e funcionalidades que possam gerar erros em nossa aplicação.

Ai você: “Rapaz, vou ter que acessar teste por teste como fiz com a calculadora? Mamãe, eu tenho 253 casos de uso!!!!”

Imagina só se você executar, URL por URL ou comando por comando, 253 casos de uso. =/

Pensando nisso, a SimpleTest disponibiliza um recurso de agrupamento de casos de teste chamado de Test Suite. Esse recurso permite agrupar vários casos de testes numa só classe, facilitando e permitindo a execução desses testes com uma só chamada.

Seria como um script de checagem, onde cada item seria um caso de teste:

Checagem do carro

  1. Checar Óleo
  2. Checar Rodas
  3. Checar Água Carburador
  4. Checar itens de segurança

A test suite funciona exatamente assim, executando cada caso de teste na ordem que você desejar: o “check list” roda e no final você tem todos as falhas que ocorreram, separadas por caso de test e método. :)

Codando!

Bom, vamos supor que vamos ter uma aplicação composta por 5 classes: ClasseA, ClasseB, ClasseC, ClasseD e ClasseE. Cada uma delas tem suas próprias implementações e vamos ter que fazer casos de testes que testem elas individualmente.

Para ilustrar o funcionamento, vamos escrever um método para todas as classes chamado Dizer: esse método deverá receber a uma string e retornar “Estou dizendo ” concatenado com o que você passou como parâmetro. Exemplificando

1
$obj->Dizer('Muito Bacana'); // Estou Dizendo Muito Bacana

Vamos botar esse método em todas as classes apenas para simularmos as passagens e não passagens de teste delas. hehhehe

Bom, partindo do pressuposto que você esteja com o SimpleTest instalado e com nossa estrutura de arquivos do artigo de iniciação à ele, vamos escrever o caso de teste da ClasseA que será salvo dentro da nossa pasta tests e terá o nome de classe_a_test.php.

1
2
3
4
5
6
7
8
9
10
11
require_once('simpletest/autorun.php');
require_once('../classes/classe_a.php');</code>

class TestOfClasseA extends UnitTestCase {

  function testDizer() {
    $classea = new ClasseA();
    $this->assertIdentical($classea->dizer('Muito Bacana'), 'Estou dizendo Muito Bacana');
  }

}

Relembrando um pouco:

  • Fazemos o include do arquito autorun.php para automatizar nossos testes;
  • Fazemos o include da classe que vai ser testada
  • Implementamos a classe de teste iniciando por “Test” afim de que a SimpleTest execute-a automaticamente;
  • Criamos o método testDizer para testar o método dizer da nossa ClasseA;
  • Fazemos um assertIdentical que executará nosso método dizer passando “Muito Bacana” e esperará como resultado algo IDENTICO à “Estou dizendo Muito Bacana”;

Beleza, agora vamos rodar nosso teste …

Imagem14

Como era esperado (espero) nosso teste deu pau porque não escrevemos nossa ClasseA ainda em arquivo algum. Então, vamos escrevê-la e salva-la dentro da pasta classes com o nome de classe_a.php:

1
2
3
4
5
class ClasseA {
  function dizer($frase) {
    return 'Estou dizendo ' . $frase;
  }
}

Agora, vamos rodar novamente nosso teste:

Imagem15

Massa demais! Fizemos novamente um caso de teste. Até ai nenhuma novidade.

Agora o exercício braçal: crie os casos de teste para a ClasseB. ClasseC, ClasseD e ClasseE lembrando que:

  • Classes da aplicação devem ser salvas dentro da pasta classes
  • Classes dos casos de teste dentro da pasta tests

Após a criação delas, faça os testes (jura?) e veja se está tudo ok.

Criando nossa suite de testes

Agora que executamos todos os testes de forma separada, vamos junta-los em nossa suite para faze-los todos de uma vez só.

Vamos criar nossa suite de testes no arquivo all_tests.php e salva-lo na pasta tests junto com todos os nosses casos de uso.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
require_once('simpletest/autorun.php');
require_once('classe_a_test.php');
require_once('classe_b_test.php');
require_once('classe_c_test.php');
require_once('classe_d_test.php');
require_once('classe_e_test.php');

class AllTests extends TestSuite {
  function AllTests() {
    $this->TestSuite('All tests');
    $this->addTestCase(new TestOfClasseA());
    $this->addTestCase(new TestOfClasseB());
    $this->addTestCase(new TestOfClasseC());
    $this->addTestCase(new TestOfClasseD());
    $this->addTestCase(new TestOfClasseE());
  }
}

Explicando nosso script:

  • fazemos o include de simpletest/autorun.php para fazer rodar nossos testes
  • fazemos os includes de todas os casos de testes que usaremos na suite
  • criamos uma classe AllTests que extende TestSuite, que por sua vez é a classe que será responsável pelo agrupamento e execução de todos os testes
  • criamos um método AllTests que fará a execução dos casos de teste
  • Nomeamos a suite de testes com o nome All tests com o método $this->TestSuite;
  • Adicionamos então todos os nossos casos de teste com o método $this->addTestCase, instanciando o objeto de cada classe de teste

Agora, basta rodar:

Imagem2

Pronto! Nossa suite agrupou nossos testes (que eram cinco ao todo, cada um com um método de teste) e executou todos de uma vez. A lógica da suíte é você inserir os testes conforme seu contexto e sua necessidade de agrupamento de testes. Para incluir, basta repetir o procedimento já feito no arquivo da suíte:

  • faça o require_once do arquivo php do caso de teste
  • inclua o caso de teste com $this->addTestCase

E se algum teste falha-se ? Vamos fazer o teste da ClasseB falhar. Para isso altere a classe B para para retornar algo que não seja “Estou dizendo ” mas sim “Eu vou dizer “: com isso, nosso teste vai falhar. Após alterar a classeB, rode a suite de testes novamente:

Imagem3

Como pode ser visto, nossa suite de testes dá o erro exetamente onde ele aconteceu: no nosso caso, a suite de testes que chamamos de All tests reportou o erro do caso de teste TestOfClasseB no método testDizer. Maneirasso não ?

Nossa suite mostra todas as falhas por caso de teste. Simples e rápido.

E vamos às considerações

A forma que fizemos a construção da nossa suite de testes está diferente da forma em que o próprio site da SimpleTest (http://www.simpletest.org/en/start-testing.html) mostra em sua página inicial no Quick Start dele, que está diferente do link que deveria ser a mesma explicação mais detalhada, mas não é. Se olharmos o script de test suite do quick start teremos, aplicando ao nosso exemplo, teríamos:

1
2
3
4
5
6
7
8
9
require_once('simpletest/autorun.php');

class AllTests extends TestSuite {
  function AllTests() {
    $this->TestSuite('All tests');
    $this->addFile('classe_a_test.php');
    //... outros casos de teste ...
  }
}

Concerteza é um jeito mais prático: ao invés de fazer-mos os includes dos casos de testes e fazermos os instanciamentos dos mesmos no addTestCase, requerendo mais programação, simplesmente podemos incluir o teste com um addFile. E isso realmente funciona. :) Mas infelizmente não sem algumas adaptações no código.

Se quiser re-escrever sua suite de testes nesse formato, se atente ao fato que o SimpleTest aparentemente trabalha com a suite de testes acessando os caminhos absolutos dos arquivos e se perde quando referenciamos nossos arquivos, mesmo que eles estejam na mesma pasta tests. Para contornar isso, coloque a inclusão do arquivo de classe no caso de testes e a referência ao arquivo do caso de teste na suite com seus caminhos absolutos. Vamos isso na classeA por exemplo:

Na classe_a_test.php teríamos:

1
require_once($_SERVER['DOCUMENT_ROOT'] . '/app_tdd/classes/classe_a.php');

E na nossa suite all_tests.php seria re-escrita como:

1
2
3
4
5
6
7
8
require_once('simpletest/autorun.php');

class AllTests extends TestSuite {
  function AllTests() {
    $this->TestSuite('All tests');
    $this->addFile($_SERVER['DOCUMENT_ROOT'] . '/app_tdd/tests/classe_a_test.php');
  }
}

Espero que tenham gostado e no próximo post falaremos um pouco sobre MockObjetcs. ;)

Até lá.

Léo Hackin agora no iMasters

julho 17th, 2009

Olá a todos,

Post rápido sobre uma novidade bacana e que me deixou bem feliz essa semana: fui convidado a ser um articulista no portal iMasters. O primeiro artigo a ser publicado lá foi o Iniciando com o SimpleTest e a idéia é ter alguns dos posts que coloco aqui sendo publicados lá.

Agradeço à equipe da iMasters pela honra e espero que possamos distribuir conteúdo legal e relevante pelos próximos tempos por ai.

Simbora! :D

Iniciando com o SimpleTest

julho 2nd, 2009

Salve people,

Vamos iniciar hoje uma pequena jornada à terras que possivelmente muita gente só viu/leu em sites especializados e muito pouco comentadas em PHP: a terra do desenvolvimento orientado a testes, ou TDD.

Se você não sabe ou nem faz idéia do que é TDD, dê uma procura no Google pois existem dezenas de sites muito bacanas destilando idéias e tudo mais sobre isso.

Em poucas palavras, TDD (Test Driven Development) é um técnica de desenvolvimento de software que nos diz que devemos escrever os testes antes de escrever o código da aplicação propriamente dito.

Inicialmente isso parece meio louco: afinal, você sempre testa DEPOIS de escrever seus programas ou durante, enquanto debuga tudo, correto ? Mas com o passar do tempo, a verdadeira natureza e vantagem do TDD, quando aplicada corretamente, se faz presente.

Você se torna capaz de antecipar a detecção e correção de várias falhas, reduzindo dramaticamente o tempo gasto com correções em cima de implementações muito complexas já praticamente no final do seu cronograma.

Hoje em dia, existem várias frameworks que auxiliam nessa tarefa de escrever testes. O foco aqui é algo que poucos sites (principalmente em português) abordam de forma prática que é o uso da SimpleTest, uma framework para testes unitários que vem ganhando o espaço antes ocupado pelo PHPUnit.

No decorrer dos próximos posts sobre o SimpleTest, você poderá adquirir um pouco de conhecimento que poderá ser útil em seus futuros projetos. Então, vamos simbora.

Instalando o SimpleTest

A instalação do SimpleTest em si é muito fácil.

  1. Baixe a versão mais atual do SimpleTest no site http://www.simpletest.org (a versão que usaremos nessa sequência de tutoriais é a 1.0.1). A framework é composta por uma pasta simples;
  2. Descompacte o arquivo dentro de sua aplicação. Para fins de organização, vamos criar uma pasta “tests” na raíz de nossa aplicação e descompactar o zip/tar do SimpleTest lá: ao descompactar você verá uma pasta chamada simpletest sendo criada.

Em tese, nossa aplicação pode ter qualquer estrutura de diretórios. O SimpleTest funciona tanto com functions como com classes. Vamos abordar o uso de classes, dado que o TDD é amplamente usado em sua maioria em soluções OO (Orientadas a Objeto) e acho que já passou da hora da comunidade PHP pensar OO. :D

Partindo desse pressuposto, vamos criar a pasta “classes” na raíz de nossa aplicação: lá iremos botar todas as nossas classes que serão usadas nos testes.

Teremos então, uma estrutura de arquivos como abaixo:

imagem5

A pasta app_tdd é a pasta onde está nossa aplicação: uma pasta criada dentro do meu htdocs (raíz do Apache).

Se o seu servidor web estiver instalado com configurações padrão, provavelmente você poderá acessar usando: http://localhost/app_tdd

Nosso problema: uma calculadora

Com o SimpleTest “instalado” em nossa aplicação e nossa estrutura de diretórios resolvida, vamos escrever nosso primeiro caso de teste.

O cenário de nossa aplicação é uma calculadora: nossa calculadora conseguirá efetuar apenas a operação de soma.

Com uma análise rápida do problema, já nos vem à cabeça que:

  • Uma classe chamada “Calculadora” com um método chamado “soma”;
  • Nosso método soma recebendo dois números
  • Nosso método retornando o valor da soma entre os dois números

Nossa abordagem não TDD seria: vamos fazer a classe, implementar o método e depois testa-lo em uma página teste. Correto ? Num primeiro momento isso seria ótimo: afinal, o código e complexidade das classes inicialmente são lindos.

Mas imagine agora sua aplicação crescendo e crescendo: classes extendendo e usando outras classes. Você extende a Calculadora, outra classe utiliza o método soma e você vai testando apenas “o que vem depois”.

Num dado momento, você tem um resultado incorreto de soma: uma entrada incorreta de parâmetros, um deles ser uma letra e não um número, termos uma passagem de um objeto ao invés de um número propriamente dito … De quem é a culpa ? Da classe nova, que esqueceu de filtrar a entrada de parametros ? Do designer, que esqueceu de limitar a entrada dos valores no form para apenas números ? Do outro programador, que foi descuidado e não validou se os dados passados eram realmente números antes de chamar a soma ?

Enfim, temos N cenários onde a detecção do erro pode ser muito custosa, seja pelo método para encontra-lo (que varia do debug minucioso ao “achismo”) e/ou pelo custo em termos de tempo para concerta-lo. Tudo isso pode gerar um custo/prejuízo que seria reduzido com a implementação do pensando TDD.

Pensando primeiro em testes

Mentalize: “Quais as situações que podem quebrar meu método soma? Se acontecer, como devo tratar esse erro ?”

Com base nesse pensamento, podemos deduzir:

  • Para somar, nossa calculadora terá que receber sempre dois números;
  • A soma sempre ocorre entre dois números, nunca entre letras, objetos ou qualquer coisa que não seja exatamente um número;
  • Se algo der erro, devo retornar falso;

Interessante! Não implementamos nenhuma linha de nossa solução e já sabemos:

  • Que vamos precisar de uma classe (Calculadora) com um método de soma;
  • Sabemos que o método deverá receber dois parâmetros que deverão ser sempre números;
  • Que se for passado qualquer coisa que não sejam dois números, eu devo retornar falso;

Bom, então vamos implementar a classe ? Não, pequeno gafanhoto: vamos implementar primeiro os testes, porque é com base neles que vamos ter certeza que nossa classe se comportará exatamente como pensamos que ela deve se comportar sob os mais diversos cenários.

Escrevendo nosso primeiro teste

Implementar um teste com SimpleTest é, como o nome já diz, “simples”.

Vamos criar todos os nossos testes dentro da pasta tests. Para cada classe que tivermos que testar, vamos criar um caso de teste (unit test case) que será representado em um arquivo php.

Então, nosso primeiro caso de teste será o calculadora_test.php. O nome do arquivo não tem um padrão de nomenclatura, mas por convenção usa-se sempre nomedaclasse_test.php.

calculadora.php -> calculadora_test.php

A estrutura inicial do nosso arquivo calculadora_test.php será a seguinte:

1
2
3
4
5
6
require_once('simpletest/autorun.php');
require_once('../classes/calculadora.php');

class TestOfCalculadora extends UnitTestCase {
// os testes vão aqui ;)
}

Pronto! Nosso caso de teste da classe Calculadora está feito. Para testa-lo, vamos apontar o browser para http://localhost/app_tdd/tests/calculadora_test.php. O resultado será:

1
2
3
Warning: require_once(../classes/calculadora.php) [function.require-once]: failed to open stream: No such file or directory in /Applications/MAMP/htdocs/app_tdd/tests/calculadora_test.php on line 4

Fatal error: require_once() [function.require]: Failed opening required '../classes/calculadora.php' (include_path='.:/Applications/MAMP/bin/php5/lib/php:/Users/leohackin/PEAR') in /Applications/MAMP/htdocs/app_tdd/tests/calculadora_test.php on line 4

Ops! Não criamos nossa classe ainda, por isso obtemos esse erro. Quando disse que escrevemos testes antes de implementar nossa lógica, estava falando sério. =)

Vamos criar nossa classe Calculadora então.

1
2
3
4
class Calculadora {
function soma($a,$b) {
}
}

Legal, agora vamos acessar nosso caso de teste denovo.

imagem6

Uhu! Funfou!!!

Analisando o código:

  • fazemos o include de dois arquivos:
    • o arquivo autorun.php é o arquivo que faz a “mágica” acontecer: é ele quem roda os testes e exibe os resultados, portanto deverá sempre estar no seu caso de teste;
    • o outro arquivo é a classe que desejamos usar no teste, no caso calculadora.php
  • Criamos uma classe chamada TestOfCalculadora extendendo UnitTestCase, que será a classe que o SimpleTest usará para fazer o teste. É obrigatório que a classe inicie com o nome “test” para que o SimpleTest execute automaticamente a mesma como um caso de teste. Existe uma forma de faze-lo sem iniciar o nome com “test”, mas isso não vem ao caso agora.

Maneiro né ? Mas como puderam notar, nosso caso de teste não testa nada ainda. Hahahah

Vamos adicionar agora um teste: o teste vai verificar se a soma está realmente “somando” dois números. Para isso, devemos adicionar um método à nossa classe de testes. Vamos chamar esse teste de “testSomaDoisNumerosInteiros“, onde vamos passar dois números inteiros esperando que a soma deles esteja correta.

Usar nomes grandes assim no nome do método são uma boa prática, já que deixam os testes mais legíveis na hora de rodar o caso de teste.

1
2
3
4
5
6
7
8
9
10
11
require_once('simpletest/autorun.php');
require_once('../classes/calculadora.php');

class TestOfCalculadora extends UnitTestCase {

function testSomaDoisNumerosInteiros() {
$calculadora = new Calculadora();
$this->assertEqual($calculadora->soma(1,1), 2);
}

}

Como visto, temos nosso método testSomaDoisNumerosInteiros que instancia nossa classe Calculadora e depois executa um método chamado assertEqual. Esse método é o responsável por testar nossa soma. Ele significa:

Verifique se a chamada $calculadora->soma(1,1) retornará um resultado igual à 2

Se a chamada retornar qualquer coisa diferente de dois, nosso teste irá falhar, indentificando que algo de podre está acontecendo em nosso método soma.

Se rodarmos esse script teremos enfim:

imagem1

Tivemos uma falha. Traduzindo a mensagem de forma prática:

O seu teste testSomeDoisNumerosInteiros, do caso de teste TestOfCalculadora, falhou porque NULL (que foi retornado pela chamada ao nosso método soma) não é igual a 2 (que seria nossa resposta esperada).

A resposta para isso é que ainda nem implementamos nosso método soma. Mas vejamos que nesse ponto já sabemos exatamente como deve ser comportar nosso método para o funcionamento com dois números. :)

Vamos implementar nossa classe então:

1
2
3
4
5
class Calculadora {
function soma($a,$b) {
return $a + $b;
}
}

Com nosso método agora implementado, vamos executar nosso caso de teste denovo.

imagem2

Agora sim! Temos um caso de teste funcional que testa uma classe implementada. Parabéns por chegar até aqui.

Nesse ponto, já temos conhecimento suficiente para escrever vários casos de teste para nossas classes. Um caso de teste pode conter vários testes diferentes: cada teste é feito através de um método da classe do caso de teste.

Revisando aquelas possibilidades de cenário que poderiam “quebrar” nossa calculadora, já testamos se a soma está correta. Agora, podemos testar as possibilidades que podem gerar um erro na calculadora.

Uma delas é se passarmos letras no lugar de números: haviamos combinado que nessa situação, devolveriamos falso para o resultado, correto ? Então, vamos escrever o teste: vamos chama-lo de “testSomaNaoNumeros“:

1
2
3
4
function testSomaNaoNumeros() {
$calculadora = new Calculadora();
$this->assertEqual($calculadora->soma(1,'A'), false);
}

Adicionamos essa função à nossa classe. Rodamos nosso teste novamente e …

imagem3

Previsivelmente, temos um erro pois nosso método soma ainda não verifica se os parâmetros recebidos são números válidos. Ai você irá pensar:

Mas eu vou escrevendo os testes e vou implementando toda a minha lógica de negócio ao mesmo tempo ?

A TDD tem uma característica bacana, que anda de mãos dados ao refactoring: a TDD nos diz que devemos SIM escrever os testes primeiro e fazer as classes “passarem no teste” usando o mínimo de código possível: se a lógica for complexa, retorne uma resposta “hardcode” para “enganar” o teste e depois faça o refactory do código.

O refactory deve ser feito apenas depois de todos os testes serem feitos, pois nesse ponto você terá certeza de como o funcionamnento de sua classe atenderá a todos as respostas que são requisitadas nos testes como “corretos”.

Pensando nisso, vamos fazer nosso método soma “passar” no teste:

1
2
3
4
5
6
7
8
9
class Calculadora {
function soma($a,$b) {
if (is_int($a) && is_int($b)){
return $a + $b;
} else {
return false;
}
}
}

Agora, vamos rodar nosso teste.

imagem4

Blz! Nosso teste passou, mas testamos apenas se os valores são inteiros e se forem, efetuamos a soma. Se não forem, a gente retorna false, como nosso teste pediu. Podemos depois refatorar isso: verificar se o valor é uma string com um número dentro e por ai vai.

Finalizando

Você pode estar se perguntando: “Uai, mas podemos ter muito mais ocasiões que podem quebrar a soma! Podemos também extender algumas funcionalidades e exibir mensagens de erro”.

Tivemos uma amostra do que é o SimpleTest em seu cenário mais simples: apesar do tamanho do post, o conceito e a aplicação são bem simples como puderam ver.

Além do assetEqual, a SimpleTest tem um set de ações enorme de validações, além de recursos mais avançados, como suites, mocks e web tests que veremos em breve.

Crie outras classes, pense nos testes, escreva seus casos de teste e vá executando: com a prática isso vai ficar tão automático que o ganho com a diminuição dos testes e bugs no final da aplicação vão ser notórios.

Testes nos tornam programadores melhores. Pense nisso.

Algumas coisas para se pensar quando começar a abordar isso:

  • Não precisamos escrever TODOS os testes: é completamente normal se esquecermos algo ou houver alguma necessidade de mudança de negócio do cliente que nos fará escrever novos testes ou re-escrever os existentes. Tenha em mente que o TDD é para ajudar e não para ser mais uma fase carrancuda e intransponível no desenvolvimento;
  • A análise para chegar aos casos de teste faz bem ao início do projeto: com essa abordagem, você pode fazer perguntas ao cliente (e ele a você) sobre algumas coisas que possívelmente só apareceriam no final do projeto gerando assim muito re-trabalho;

Bom, por enquanto é isso pessoal. No próximo post falaremos um pouco sobre agrupamentos de teste e partir para um exemplo mais complexo. :)

Espero que tenham gostado do post.

Simbora! :D

Convite 1º Workshop PHP-ES

maio 14th, 2009

É com muita alegria que a comunidade PHP do Espírito Santo – PHP-ES – convida a toda a comunidade capixaba de desenvolvedores, gerentes de TI, estudantes, curiosos e a quem interessar para participar do 1º Workshop PHP-ES.

O Workshop PHP-ES é um evento regional totalmente dedicado à divulgação e disseminação da linguagem de programação PHP no ES. O evento acontece pela primeira vez, fruto da vontade dos usuários de grupo de PHP?ES em ter um evento exclusivo sobre PHP, afim de promover o interesse regional pela linguagem.

O Workshop PHP-ES será realizado no dia 30/05/2009, sábado, no período de 13h até as 18h no Anfiteatro da UVV – Centro Universitário de Vila Velha – Campus Boa Vista.

As inscrições são GRATUITAS e OBRIGATÓRIAS, pois o número de vagas é limitado, e dão direito ao recebimento do certificado de participação e aos SORTEIOS de vários brindes. Convocamos todos os participantes a trazerem 1kg de alimento não-perecível que será doado a uma instituição.

Segue a grade do evento:

13:00h – 13:40h – Credenciamento
13:40h – 13:50h – Abertura
13:50h – 14:50h – Nadando em Dinheiro com AJAX e jQuery [Reinaldo de Souza "JuniorZ"]
15:00h – 16:00h – Desenvolvimento ágil com Smarty [Gerson Novais]
16:00h – 16:30h – Intervalo
16:30h – 17:30h – CakePHP [Leonardo "Hackin" Freire]
17:30h – Fechamento

Informações e inscrições podem ser feitas em: http://www.php-espiritosanto.com.br/

Equipe organizadora do Workshop PHP-ES

Get Adobe Flash playerPlugin by wpburn.com wordpress themes