.. .. META INFORMATION OF TRANSLATION .. .. $TranslationStatus: Done, waiting for revision. $ .. $OriginalRevision: 11268 $ .. $TranslationAuthors: Luiz Fernando Barbosa Vital, Robson Mendonça $ .. .. INFO OF THIS FILE (DO NOT EDIT! UPDATED BY SUBVERSION) .. .. $HeadURL: http://django-l10n-portuguese.googlecode.com/svn/branches/docs-1.0.X/topics/testing.txt $ .. $LastChangedRevision: 371 $ .. $LastChangedBy: robsonmwoc $ .. $LastChangedDate: 2009-07-22 01:59:35 -0300 (Wed, 22 Jul 2009) $ .. .. _topics-testing: ========================== Testando aplicações Django ========================== .. module:: django.test :synopsis: Ferramentas de teste de aplicações Django. O teste automatizado é uma ferramenta extremamente útil para eliminar bugs utilizada pelo desenvolvedor Web moderno. Você pode usar uma coleção de testes -- uma **test suite** -- para resolver, ou evitar, vários problemas: * Quando você está escrevendo um código novo, pode usar os testes para verificar se seu código funciona como esperado. * Quando está refatorando ou modificando um código antigo, você pode usar os testes para garantir que suas mudanças não afetaram inesperadamente o comportamento de sua aplicação. Testar uma aplicação Web é uma tarefa complexa, porque uma aplicação Web é feita de várias camadas de lógica -- da manipulação de uma requisição em nível HTTP, para a validação e processamento de formulário, para a renderização de template. Com o framework de teste-execução do Django e outros utilitários, você pode simular requisições, inserir dados de teste, inspecionar a saída de sua aplicação e freqüentemente verificar se seu código está fazendo o que deveria. A melhor parte é que isso tudo é muito fácil. Este documento é dividido em duas duas seções. Na primeira, explicamos como escrever testes com Django e, posteriormente, explicamos como rodá-los. Escrevendo testes ================= Existem duas maneiras de se escrever testes com Django, correspondendo com os dois frameworks de teste que estão na biblioteca padrão do Python, que são: * **Doctests** -- os testes estão embutidos nas docstrings (strings de documentação) de suas funções e são escritas de tal maneira a emular uma sessão do interpretador interativo do Python. Por exemplo:: def my_func(a_list, idx): """ >>> a = ['larry', 'curly', 'moe'] >>> my_func(a, 0) 'larry' >>> my_func(a, 1) 'curly' """ return a_list[idx] * **Unit tests** -- (Testes unitários) são testes que são expressados como métodos em uma classe Python que é uma subclasse de ``unittest.TestCase``. Por exemplo:: import unittest class MyFuncTestCase(unittest.TestCase): def testBasic(self): a = ['larry', 'curly', 'moe'] self.assertEquals(my_func(a, 0), 'larry') self.assertEquals(my_func(a, 1), 'curly') Você pode escolher o framework de teste que te agrade, dependendo da sintaxe que preferir, ou você pode misturar os dois, utilizando um framework para parte de seu código e outro framework para outra parte. Você também pode usar qualquer *outro* framework de testes Python, como explicaremos adiante. Escrevendo doctests ------------------- Os doctests usam o módulo doctest_ padrão do Python, que procura em suas docstrings por instruções que se pareçam com uma sessão do interpretador interativo do Python. Uma explicação completa de como funciona o doctest está fora do escopo deste documento; leia a documentação oficial do Python para maiores detalhes. .. admonition:: O que é uma **docstring**? Uma boa explicação de docstrings (e algumas diretrizes para utilizá-la de maneira completa) pode ser encontrada em :pep:`257`: Uma docstring é uma literal de string que ocorre como a primeira instrução em um módulo, função, classe, ou definição de método. Esta docstring torna-se o atributo especial ``__doc__`` do objeto em questão. Por exemplo, esta função possui uma docstring que descreve o que ela faz:: def add_two(num): "Retorna o resultado da adição de dois ao número informado." return num + 2 Pelo motivo de que testes freqüentemente geram uma boa documentação, colocar testes diretamente nas suas docstrings é uma maneira eficiente de documentar *e* testar o seu código. Para uma dada aplicação Django, o executor de testes procura por doctests em dois lugares: * No arquivo ``models.py``. Você pode definir doctests para o módulo todo e/ou um doctest para cada modelo. É uma pratica comum colocar doctests de nível de aplicação numa docstring do módulo e doctests de nível de modelo em docstrings de modelos. * Um arquivo chamado ``tests.py`` no diretório da aplicação -- ou seja, o diretório que contém ``models.py``. Esse arquivo é um ``hook`` para todos e quaisquer doctests que você queira escrever que não sejam necessariamente relacionados a modelos. Aqui vai um exemplo de doctest de modelo:: # models.py from django.db import models class Animal(models.Model): """ An animal that knows how to make noise # Create some animals >>> lion = Animal.objects.create(name="lion", sound="roar") >>> cat = Animal.objects.create(name="cat", sound="meow") # Make 'em speak >>> lion.speak() 'The lion says "roar"' >>> cat.speak() 'The cat says "meow"' """ name = models.CharField(max_length=20) sound = models.CharField(max_length=20) def speak(self): return 'The %s says "%s"' % (self.name, self.sound) Quando você :ref:`roda seus testes `, o executor de testes irá encontrar essa docstring -- note que pedaços dela parecem uma sessão interativa de Python -- e executar suas linhas verificando se os resultados batem. No caso de testes de modelo, note que o executor de testes cuida de criar seu próprio banco de dados. Ou seja, qualquer teste que acesse banco de dados -- criando e gravando instâncias de modelos, por exemplo -- não afetará seu banco de dados em produção. Cada doctest inicia com um banco de dados novo contendo uma tabela vazia para cada modelo. (Veja a seção de fixtures, abaixo, para mais detalhes.) Note que para usar esse recurso, o usuário que o Django utiliza para se conectar ao banco de dados deve ter direito de criar novos bancos ``CREATE DATABASE``. Para mais detalhes sobre como funciona o doctest, veja a `documentação da biblioteca padrão para doctest`_ .. _doctest: http://docs.python.org/lib/module-doctest.html .. _documentação da biblioteca padrão para doctest: doctest_ Escrevendo testes unitários --------------------------- Como doctests, os testes unitários do Django usam um módulo da biblioteca padrão: unittest_. Esse módulo usa uma maneira diferente de definir testes, utilizando um método baseado em classes. Como nos doctests, para uma dada aplicação Django, o executor de testes procura por testes unitários em dois lugares: * O arquivo ``models.py``. O executor de testes procura por qualquer subclasse de ``unittest.TestCase`` nesse módulo. * Um arquivo chamado ``tests.py`` no diretório da aplicação -- o mesmo que contém ``models.py``. Novamente, o executor de testes procura por qualquer subclasse de ``unittest.TestCase`` nesse módulo. Este exemplo de subclasse de ``unittest.TestCase`` é equivalente ao exemplo dado na seção de doctest acima:: import unittest from myapp.models import Animal class AnimalTestCase(unittest.TestCase): def setUp(self): self.lion = Animal.objects.create(name="lion", sound="roar") self.cat = Animal.objects.create(name="cat", sound="meow") def testSpeaking(self): self.assertEquals(self.lion.speak(), 'The lion says "roar"') self.assertEquals(self.cat.speak(), 'The cat says "meow"') Quando você :ref:`roda seus testes `, o comportamento padrão do utilitário de teste é encontrar todos os test cases (ou seja, subclasses de ``unittest.TestCase``) nos arquivos ``models.py`` e ``tests.py``, automaticamente montar uma test suite (conjunto de testes) destes test cases, e rodá-la. Há uma segunda maneira de se definir um test suite para um módulo: se você define uma função chamada ``suite()`` seja em ``models.py`` ou ``tests.py``, o executor de testes do Django usará essa função para construir a test suite para o módulo. Isso segue a `organização sugerida`_ para testes unitários. Veja a documentação do Python para mais detalhes de como construir uma test suite complexa. Para mais detalhes sobre ``unittest``, veja a `documentação de unittest da biblioteca padrão`_. .. _unittest: http://docs.python.org/lib/module-unittest.html .. _documentação de unittest da biblioteca padrão: unittest_ .. _organização sugerida: http://docs.python.org/lib/organizing-tests.html Qual devo usar? --------------- Pelo motivo de o Django suportar ambos os frameworks de testes padrão do Python, cabe a você, de acordo com seu gosto, decidir qual utilizar. Você pode até mesmo decidir usar *ambos*. Para desenvolvedores novatos em testes, essa escolha pode parecer confusa. Aqui estão algumas diferenças chave para ajudá-lo a decidir qual método é melhor: * Se você já utiliza Python por algum tempo, o ``doctest`` provavelmente parecerá mais "pythônico". Ele foi projetado para tornar a escrita de testes o mais fácil possível, então não requer nenhum esforço extra de escrever classes ou métodos. Você simplesmente coloca seus testes em docstrings. Isso tem a vantagem adicional de servir como documentação (e documentação correta!). Se você está iniciando com testes, utilizar doctests farão com que você obtenha resultados mais rapidamente. * O framework ``unittest`` provavelmente será bem familiar para desenvolvedores vindos do Java. O ``unittest`` é inspirado pelo JUnit do Java, então você se sentirá em casa com esse método se você já usou o JUnit ou qualquer outro framework de testes inspirado no JUnit. * Se você precisa escrever muitos testes que compartilham código parecido, então você vai gostar da organização baseada em classes e métodos do framework ``unittest``. Ele facilita abstrair tarefas comuns em métodos comuns. O framework também suporta configuração explícita e/ou limpeza de rotinas, que te dão um alto nível de controle sobre o ambiente no qual seus testes são executados. De novo, lembre-se de que você pode usar ambos os sistemas lado a lado (até mesmo em uma mesma aplicação). No final, a maioria dos projetos provavelmente acabará utilizando ambos. Cada um se destaca em diferentes circunstâncias. .. _running-tests: Rodando os testes ================= Uma vez que você escreveu os testes, execute-os utilizando o utilitário do seu projeto ``manage.py``:: $ ./manage.py test Por padrão, isso executará cada teste em cada aplicação em :setting:`INSTALLED_APPS`. Se você só quer rodar os testes para uma aplicação em particular, adicione o nome da aplicação à linha de comando. Por exemplo, se seu :setting:`INSTALLED_APPS` contém ``'myproject.polls'`` e ``'myproject.animals'``, você pode rodar somente os testes unitários de ``myproject.animals`` com este comando:: # ./manage.py test animals Note que utilizamos ``animals``, e não ``myproject.animals``. .. versionadded:: 1.0 Agora você pode escolher qual teste rodar. Se você utiliza testes unitários, em vez de doctests, você pode ser ainda *mais* específico na escolha de quais testes executar. Para rodar um único teste em uma aplicação (por exemplo, o ``AnimalTestCase`` descrito na seção "Escrevendo testes unitários"), adicione o nome do test case à linha de comando:: $ ./manage.py test animals.AnimalTestCase E pode ficar ainda mais granular que isso! Para rodar um *único* método de teste dentro de um test case, adicione o nome do método de teste:: $ ./manage.py test animals.AnimalTestCase.testFluffyAnimals O banco de dados de teste ------------------------- Testes que necessitam de uma base de dados (nomeadamente, testes de modelo) não usarão seu banco de dados "real" (produção). Um banco de dados vazio é criado em separado para os testes. Independentemente de os testes passarem ou falharem, o banco de dados de teste é destruído quando todos os testes forem executados. Por padrão, o nome deste banco de dados de teste é o valor da configuração :setting:`DATABASE_NAME` adicionando o prefixo ``test_``. Quando um banco de dados SQLite é utilizado, os testes usarão bancos de dados na memória (ou seja, todo o banco será criado somente na memória, não utilizando nada do sistema de arquivos). Se você quiser usar um nome diferente para o banco de dados de teste, especifique o parâmetro de configuração :setting:`TEST_DATABASE_NAME`. Além de utilizar um banco de dados separado, o executor de testes usará os mesmos parâmetros de banco de dados do seu arquivo de configuração: :setting:`DATABASE_ENGINE`, :setting:`DATABASE_USER`, :setting:`DATABASE_HOST`, etc. O banco de dados de teste é criado pelo usuário especificado em :setting:`DATABASE_USER`, então é necessário garantir que esta conta de usuário tem privilégios suficientes para criar um novo banco de dados no sistema. .. versionadded:: 1.0 Para um controle apurado sobre a codificação de caractere de seu banco de dados de teste, use o parâmetro de configuração :setting:`TEST_DATABASE_CHARSET`. Se você está utilizando MySQL, você pode também usar o parâmetro :setting:`TEST_DATABASE_COLLATION` para controlar uma collation particular utilizada pelo banco de dados de teste. Veja a :ref:`documentação de configurações ` para mais detalhes dessas configurações avançadas. Outras condições de testes -------------------------- Independentemente do valor do :setting:`DEBUG` do seu arquivo de configuração, todos os testes do Django rodam com :setting:`DEBUG=False`. Isto é para assegurar que a saída observada de seu código seja igual ao da aplicação em produção. .. _configurações: ../settings/ Entendendo a saída do teste --------------------------- Quando roda seus testes, você visualiza um número de mensagens à medida que o executor de testes se prepara. Você pode controlar o nível de detalhe dessas mensagens com a opção de linha de comando ``verbosity``:: Creating test database... Creating table myapp_animal Creating table myapp_mineral Loading 'initial_data' fixtures... No fixtures found. Isso informa que o executor de testes está criando um banco de teste, como descrito na seção anterior. Uma vez que o banco de testes foi criado, o Django rodará os seus testes. Se tudo correr bem, você verá algo do tipo:: ---------------------------------------------------------------------- Ran 22 tests in 0.221s OK Se existirem falhas, entretanto, você verá os detalhes completos sobre quais testes falharam:: ====================================================================== FAIL: Doctest: ellington.core.throttle.models ---------------------------------------------------------------------- Traceback (most recent call last): File "/dev/django/test/doctest.py", line 2153, in runTest raise self.failureException(self.format_failure(new.getvalue())) AssertionError: Failed doctest test for myapp.models File "/dev/myapp/models.py", line 0, in models ---------------------------------------------------------------------- File "/dev/myapp/models.py", line 14, in myapp.models Failed example: throttle.check("actor A", "action one", limit=2, hours=1) Expected: True Got: False ---------------------------------------------------------------------- Ran 2 tests in 0.048s FAILED (failures=1) Uma explicação completa sobre essa saída de erro está fora do escopo deste documento, mas ela é bem intuitiva. Você pode consultar a documentação da biblioteca ``unittest`` do Python para maiores detalhes. Note que o código retornado pelo script executor de testes é o número total de testes que falharam. Se todos os testes passarem, o código de retorno é 0. Este recurso é útil se você está usando script executor de testes em um script shell e precisa verificar o sucesso ou falha naquele nível. Ferramentas de teste ==================== O Django provê um pequeno conjunto de ferramentas que são uma verdadeira mão- na-roda na hora de escrever os testes. O cliente de teste ------------------ .. module:: django.test.client :synopsis: Django's test client. O cliente de teste é uma classe Python que age como um navegador Web, permitindo a você testar suas views e interagir com suas aplicações feitas em Django programaticamente. Algumas das coisas que você pode fazer com o cliente de teste são: * Simular requisições GET e POST em uma URL e observar a resposta -- tudo desde o nível baixo do HTTP (os cabeçalhos de resultado e códigos de status) até o conteúdo da página. * Testar se a view correta é executada para uma dada URL. * Testar que uma dada requisição é gerada por um determinado template, com um determinado contexto de template que contém certos valores. Note que este cliente de teste não tem o propósito de ser um substituto para Twill_, Selenium_, ou outros frameworks "in-browser". O cliente de teste do Django tem um foco diferente. Em resumo: * Use o cliente de teste do Django para atestar que a view correta está sendo chamada e que a view está recebendo os dados de contexto corretos. * Use frameworks in-browser como Twill e Selenium para testar HTML gerados e *comportamento* de páginas Web, ou seja, funcionalidade JavaScript. Uma test suite completa deve usar uma combinação de ambos tipos de testes. .. _Twill: http://twill.idyll.org/ .. _Selenium: http://www.openqa.org/selenium/ Visão geral e um exemplo rápido ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Para usar o cliente de teste, instancie ``django.test.client.Client`` e acesse páginas Web:: >>> from django.test.client import Client >>> c = Client() >>> response = c.post('/login/', {'username': 'john', 'password': 'smith'}) >>> response.status_code 200 >>> response = c.get('/customer/details/') >>> response.content '>> c.get('/login/') E isto incorreto:: >>> c.get('http://www.example.com/login/') O cliente de testes não é capaz de acessar páginas Web que não fazem parte do seu projeto Django. Se você precisa acessar outras páginas Web, utilize algum módulo da biblioteca padrão do Python como urllib_ ou urllib2_. * Para resolver URLs, o cliente de testes usa o URLconf que está especificado no parâmetro de configuração :setting:`ROOT_URLCONF`. * Apesar de o exemplo acima funcionar no interpretador interativo do Python, algumas funcionalidades do cliente de teste, notadamente as relacionadas a templates, somente estão disponíveis *enquanto os testes estão sendo rodados*. O motivo disso é porque o executor de testes do Django faz um pouco de magia negra para determinar qual template foi carregado por uma determinada view. Essa magia negra (essencialmente um patch no sistema de templates na memória) acontece somente durante a execução dos testes. .. _urllib: http://docs.python.org/lib/module-urllib.html .. _urllib2: http://docs.python.org/lib/module-urllib2.html Fazendo requisições ~~~~~~~~~~~~~~~~~~~ Use a classe ``django.test.client.Client`` para fazer as requisições. Ela não requer argumentos em sua contrução: .. class:: Client() Uma vez que você tenha uma instância de ``Client``, você pode chamar qualquer um dos seguintes métodos: .. method:: Client.get(path, data={}, **extra) Faz uma requisição GET no ``path`` informado e devolve um objeto ``Response``, que está documentado abaixo. Os pares de chave-valor no dicionário ``data`` são usados para criar os dados que serão enviados via GET. Por exemplo:: >>> c = Client() >>> c.get('/customers/details/', {'name': 'fred', 'age': 7}) ...resultará em uma requisição GET equivalente a:: /customers/details/?name=fred&age=7 The ``extra`` keyword arguments parameter can be used to specify headers to be sent in the request. For example:: >>> c = Client() >>> c.get('/customers/details/', {'name': 'fred', 'age': 7}, ... HTTP_X_REQUESTED_WITH='XMLHttpRequest') ...will send the HTTP header ``HTTP_X_REQUESTED_WITH`` to the details view, which is a good way to test code paths that use the :meth:`django.http.HttpRequest.is_ajax()` method. .. method:: Client.post(path, data={}, content_type=MULTIPART_CONTENT, **extra) Faz uma requisição POST no ``path`` informado e devolve um objeto ``Response``, que está documentado abaixo. Os pares de chave-valor no dicionário ``data`` são usados para enviar os dados via POST. Por exemplo:: >>> c = Client() >>> c.post('/login/', {'name': 'fred', 'passwd': 'secret'}) ...resultará em uma requisição POST a esta URL:: /login/ ...com estes dados de POST:: name=fred&passwd=secret Se você informa o ``content_type`` (ex: ``text/xml`` para um XML), o conteúdo de ``data`` será enviado como está na requisição POST, utilizando ``content_type`` no cabeçalho HTTP ``Content-Type``. Se você não informa um valor para ``content_type``, os valores em ``data`` serão transmitidos como um tipo de conteúdo ``multipart/form-data``. Nesse caso, os pares chave-valor em ``data`` serão codificados como uma mensagem multipart e usados para criar os dados de POST. Para enviar múltiplos valores para uma chave -- por exemplo, para especificar as seleções para um ``