Cairo Noleto

Behavior Driven Development em PHP com PHPSpec

| Comments

Comecei a ler muito sobre TDD, depois na comunidade rails-br descobri o BDD li e me pareceu mais simples do que TDD.

Para fazer TDD no rails é bem mais simples do que parece, é só executar os scripts de criação de models, controllers e views que o framework já cria os arquivos básicos para fazer TDD, bastando apenas escrever os casos de testes e executar o comando rake para tudo funcionar.

Para fazer BDD em rails é necessário a instalação de um plugin chamado RSPec, esse plugin é responsável pela criação das especificações em BDD.

Em rails é muito simples fazer TDD e BDD, já que o próprio ambiente te prepara para desenvolver se utilizando dessas técnicas, diferente dos frameworks PHP que poucos deles possuem facilidades como rails (Na sua última versão, o CodeIgniter introduziu TDD em seu core, ainda não tive tempo para dar uma olhada de como funciona. No cakePHP, pelo que eu vi na comunidade, é capaz de se fazer TDD.

Para se fazer TDD e BDD no PHP é necessário a instalação de frameworks para o mesmo, no meu caso eu escolhi o PHPUnit para testes unitários e para BDD eu escolhi o PHPSpec. Só que essa escolha foi por livre e espontânea pressão, é que somente existe esse framework para se trabalhar com BDD em PHP.

Ele foi escrito após o desenvolvedor (Pádraic Brady) ter se aventurado por Ruby e Rails e conhecido RSpec, ele resolveu desenvolver o “RSpec” para PHP e o batizou de PHPSpec.

A documentação é bastante simples e fácil de ler, usei algumas horas e li toda a documentação, e agora estou planejando para utiliza-los nos projetos que faço parte.

Agora vou explicar um pouco de como funciona com um exemplo.

Primeiro, antes da gente começar, devemos especificar o problema, no caso, como um usuário irá fazer um comentário.

Usuário deverá colocar seu nome, depois ele deverá colocar seu email.
Se o usuário tiver um site, poderá coloca-lo.
Então depois o usuário coloca o conteúdo do comentário e clica em enviar.

Agora que temos a especificação, vamos criar nosso primeiro exemplo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
require_once "Post.php";

class DescribeNewPostInBlog extends PHPSpec_Context {
  private $post = null;
  public function before() {
    $this->post = new Post;
  }
  
  public function itShouldSetName() {
    $this->post->setName("Cairo Noleto");
    $this->spec($this->post->getName())->should->beEqualTo("Cairo Noleto");
  }
  
  public function itShouldSetEmail() {
    $this->post->setEmail("caironoleto@gmail.com");
    $this->spec($this->post->getEmail())->should->beEqualTo("caironoleto@gmail.com");
  }
  
  public function itShouldSetWebSite() {
    if ("user set as website") {
      $this->post->setWebSite("http://www.caironoleto.com/");
    }
    $this->spec($this->post->getWebSite())->should->beEmpty();
  }
  
  public function itShouldSetContent() {
    $this->post->setContent("Aqui vai o comentário do post :P");
    $this->spec($this->post->getContent())->should->be("Aqui vai o comentário do post :P");
  }
}

Se rodarmos no terminal, teremos o resultado:

1
2
3
4
5
cairo@angus:~/BDDonPHP$ phpspec DescribeNewPostInBlog

E

Fatal error: Call to undefined method Post::setName() in /home/cairo/BDDonPHP/DescribeNewPostInBlog.php on line 15

Da erro por que nossa classe Post não contém o método setName, e vai da erro a cada um dos métodos que não funciona, então irei cria-los:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class Post {

  private $name;
  private $email;
  private $website;
  private $content;
  
  public function setName($name) {
    $this->name = $name;
  }
  
  public function setEmail ($email) {
    $this->email = $email;
  }
  
  public function setWebSite($website) {
    $this->website = $website;
  }
  
  public function setContent($content) {
    $this->content = $content;
  }
  
  public function getName() {
    return $this->name;
  }

  public function getEmail() {
    return $this->email;
  }
  
  public function getWebSite() {
    return $this->website;
  }

  public function getContent() {
    return $this->content;
  }
}

Agora rode mais uma o código e veja tudo rodando perfeitinho :D

Algumas considerações:

A primeira e mais importante é que o framework está na versão 0.2.3 e ainda não saiu nenhuma versão release, todas as versões são betas.

Por ser beta, falta alguns métodos (Como os “Matchers” beAnInstaceOf, beString, beOfType). Por assinar a lista, foi resolvido hoje e inserido o método beString, ainda não sei como faço pra pegar a versão do SVN que seria bem mais interessante, vou colocar um email na lista perguntando como faço e blogo aqui.

O Framework como está funcionando já da pra escrever muita especificação, então é bola pra frente.

Até a próxima!

Comments