conceitos e práticas de testes em PHP

as práticas comuns, alguns conceitos e como isso se aplica na leroy merlin

O que testar?

O que testar?

Unit testing is about testing the observable behaviors of a class! Observable from the outside! Nobody cares about the internal state of a class if it never changes the outcome of a method call

O que testar?

  • classes, não métodos

  • o que é público

  • regras de negócio.

O que NÃO testar?

  • Métodos privados e protegidos

  • getter's e setter's que não tenham lógica dentro

  • Não teste o php ou o framework

    • Parece óbvio, mas é bem comum encontrar algo do tipo. Exemplo: testar se os parâmetros do construtor estão sendo passados corretamente pelo DI do Laravel

testsuite rápida

testsuite rápida

If it takes to long to run your tests, you won't do it

testsuite rápida?

  • scrutinizer: mais de 5 minutos

  • local: ? (Provavelmente estoura memória)

separar suites

  • por diretório

  • por convenção de nome + phpunit

boot do framework

  • utilização de helpers do framework desnecessariamente dentro do nosso domínio

  • app()->make(Some::class)
  • array_*

criando bootstraps mais leves

  • Criar bootstrap específicos para testes que dependam de algumas poucas funcionalidades, sem levantar todo o framework.

Assertions específicas

  • Utilizar assertions específicas, além de uma melhor leitura, garantem uma resposta mais legível e melhor compreensão sobre o porquê o teste falhou. 

Alguns exemplos errados

$this->assertEquals(null, $some->return());
// 12 ocorrências
$this->assertEquals([], $some->return());
// 25 ocorrências
$this->assertEquals(false, $some->return());
// 8 ocorrências

Assertions - array

// Array
assertArrayHasKey()
assertContains()
assertContainsOnly()
assertContainsOnlyInstancesOf()
assertCount()
assertEmpty()
assertSame()

Assertions - JSON

// JSON
assertJsonFileEqualsJsonFile()
assertJsonStringEqualsJsonFile()
assertJsonStringEqualsJsonString()

Assertions - string

// String
assertRegExp()
assertStringMatchesFormat()
assertStringMatchesFormatFile()
assertStringEndsWith()
assertStringEqualsFile()
assertStringStartsWith()

Assertions - xml

// XML
assertEqualXMLStructure()
assertXmlFileEqualsXmlFile()
assertXmlStringEqualsXmlFile()
assertXmlStringEqualsXmlString()

mais Assertions

assertInstanceOf()
assertAttributeEquals()
assertFileExists()
assertThat()

Custom assert

<?php
class MyCustomConstraint 
    extends \PHPUnit_Framework_Constraint
{
    public function matches($other) { /* Code */ }
}
<?php

use PHPUnit_Framework_TestCase as TestCase;

class MyTestCase extends TestCase
{
    public function assertCustom($expectation) {  
        $this->assertThat($expectation, new MyCustomConstraint());
    }
}

testando traits

  • criando stub

  • utilizando a trait de fato nos testes

testando traits

  • criando stub

  • utilizando a trait de fato nos testes

UTILIZANDO TRAIT DE FATO NOS TESTES

fixtures

fixtures - Files

public function getCsv()
{
    return file_get_contents(
        __DIR__ . '/data-fixtures/sale_orders.csv'
    );
}
Número do Pedido|Criado em|Status|Última atualização de status|Cliente|CPF|E-mail|Assistida pelo Televendas|Assessor do Televendas|Valor dos Itens|Valor do Frete|Desconto|Valor Final|Tipo de Entrega|Transportadora|Serviço|Cartão 1 - Bandeira|Cartão 1 - Parcelas|Cartão 1 - Valor|Cartão 2 - Bandeira|Cartão 2 - Parcelas|Cartão 2 - Valor
E123|10/10/2014 16:00:00|DESPACHADO|20/11/2014 17:00:00|John Doe|12345678901|john@doe.com|Não||50|20|10|40|Rápida|TEX COURIER|TOTAL EXPRESS|VISA|2|40|
E456|11/10/2014 13:00:00|ENTREGUE|21/11/2014 14:00:00|Another John|10987654321|another@john.com|Sim|Jane Doe|300|45.5|50.9|380.86|Agendada|CORREIOS|PAC|MASTERCARD|2|280.86|AMEX|1|100|

sale_orders.csv

fixtures - Files

public function testExportShouldGenerateASuccessCSVFile()
{
    $this->assertStringEqualsFile(
        __DIR__.'/fixtures/expected_sale_orders.csv', 
        $this->saleOrders->toString();
    );
}
Número do Pedido|Criado em|Status|Última atualização de status|Cliente|CPF|E-mail|Assistida pelo Televendas|Assessor do Televendas|Valor dos Itens|Valor do Frete|Desconto|Valor Final|Tipo de Entrega|Transportadora|Serviço|Cartão 1 - Bandeira|Cartão 1 - Parcelas|Cartão 1 - Valor|Cartão 2 - Bandeira|Cartão 2 - Parcelas|Cartão 2 - Valor
E123|10/10/2014 16:00:00|DESPACHADO|20/11/2014 17:00:00|John Doe|12345678901|john@doe.com|Não||50|20|10|40|Rápida|TEX COURIER|TOTAL EXPRESS|VISA|2|40|
E456|11/10/2014 13:00:00|ENTREGUE|21/11/2014 14:00:00|Another John|10987654321|another@john.com|Sim|Jane Doe|300|45.5|50.9|380.86|Agendada|CORREIOS|PAC|MASTERCARD|2|280.86|AMEX|1|100|

expected_sale_orders.csv

@depends

@depends

Os testes devem ser isolados; devem permitir ser executados separada e independentemente. Mas se precisar...

@depends

public function testAddShouldAppendAnItemInArray()
{
    $bag  = new Bag();
    $item = new Item('some name');
    $bag->add($item);

    $this->assertEquals([$item], $bag->all());

    return [$bag, $item];
}

/**
 * @depends testAddShouldAppendAnItemInArray
 */
public function testRemoveShouldDeleteGivenItemFromBag(
    $bag, 
    Item $item
) {
    $bag->remove($item);
    $this->assertEmpty($bag->all());
}

design de código guiado a testes

arquitetura dos testes

Conceitos e Práticas de testes em PHP

By Ricardo Plansky Jr.

Conceitos e Práticas de testes em PHP

Algumas práticas comuns e conceitos sobre testes em PHP e como isso de aplica para a Leroy Merlin

  • 283