Como testar código que depende do sistema de arquivos com PHPUnit e vfsStream

Já faz um tempo que me interesso por testes unitários e em especial por TDD. Utilizo o PHPUnit, o principal framework da família xUnit para PHP. Neste post vou fazer uma rápida apresentação do vfsStream, um stream wrapper que permite simular um sistema de arquivos no PHP, facilitando muito a escrita de testes para código que manipula ou depende do sistema de arquivos.

Abaixo segue uma classe que utilizaremos como exemplo (para simplificar ela somente apresenta os elementos que interessam para este post):

<?php

class File
{
	/**
	 * Path to the file
	 * @var string
	 */
	protected $path;

	/**
	 * 
	 * @param string $path
	 * @return null
	 */
	public function __construct($path)
	{
		$this->path = $path;
	}
	
	/**
	 * Add a string to the end of the file
	 * @param string $string
	 * @return null
	 */
	public function append($string)
	{
		file_put_contents($this->path, $string, FILE_APPEND);
	}
	
	/**
	 * Return file contents as a string
	 * @return string
	 */
	public function get()
	{
		return file_get_contents($this->path);
	}
}

Se formos testar essa classe somente com os recursos oferecidos pelo PHPUnit, teríamos que criar e destruir os arquivos utilizando os métodos setUp() e tearDown() respectivamente. Isso funciona porém tem algumas complicações. Por exemplo, se por algum motivo a execução do teste for abortada, os arquivos criados não serão removidos do sistema de arquivos. Outro problema dessa abordagem é a manutenção dos testes quando o código a ser testado trabalha com múltiplos arquivos e/ou diretórios.

Utilizando o vfsStream não é necessário utilizar o tearDown() já que tudo é criado na memória e você tem mais controle e garantias sobre o ambiente de teste já que este é completamente virtual e não está sujeito a influência de outras operações que podem ocorrer enquanto os testes são executados.

Veja abaixo uma classe de testes que utiliza o vfsStream para testar os métodos descritos acima:

<?php

require_once('File.php');
require_once('vfsStream/vfsStream.php');

class FileTest extends PHPUnit_Framework_TestCase
{
	protected $obj;
	
	protected $file;
	
	protected $string;
	
	protected function setUp()
	{
		$this->string = "first line\n";
		
		$root = vfsStream::setup();
		
		$this->file = new vfsStreamFile('file.txt');
		$this->file->setContent($this->string);
		$root->addChild($this->file);
		
		$this->obj = new File(vfsStream::url('file.txt'));
	}
	
	public function testAppend()
	{
		$string = "second line\n";
		$expectedResult = "first line\n" . $string;
		 
		$this->obj->append($string);
		
		$this->assertEquals($expectedResult, $this->file->getContent());
	}
	
	public function testGet()
	{
		$this->assertEquals($this->string, $this->obj->get());
	}
}

No método FileTest::setUp(), a chamada ao vfsStream::setup() cria o diretório raiz do sistema de arquivos virtual e retorna um objeto do tipo vfsStreamDirectory. Na sequência, nas linhas 20 e 21, é criado um novo objeto do tipo vfsStreamFile e definido seu conteúdo inicial. Por fim na linha 22 o novo arquivo é adicionado a raiz do sistema de arquivos virtual e na linha 24 uma instância da classe que vamos testar é gerada recebendo como argumento o caminho para o arquivo.

O restante do código é auto explicativo para quem está acostumado com o PHPUnit, com exceção da linha 34 onde para verificar se o arquivo foi mesmo modificado é utilizado o método vfsStreamFile::getContent().

Para mais informações veja sobre o vfsStream sugiro:

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *