Testes de processadores para Python 2

O artigo Testes de unidades locais para Python descreveu como executar testes de unidades para a sua aplicação. Embora os testes unitários sejam excelentes para testar as unidades separadas do seu código, a integração dessas unidades de código é o que faz a sua aplicação funcionar. Por isso, os testes de integração são igualmente importantes.

Para as aplicações do App Engine, os controladores de pedidos são pontos de integração críticos. Embora uma aplicação WSGI encaminhe os pedidos para o controlador certo, o próprio controlador processa os dados dos pedidos e gera uma resposta (saiba mais sobre os controladores de pedidos). Os controladores de pedidos são objetos Python normais, como qualquer outra função ou classe, o que os torna fáceis de usar em testes automatizados. No entanto, como uma aplicação WSGI as envolve como um shell, vamos usar um shell semelhante nos nossos testes.

WebTest

Para os nossos testes, vamos usar a estrutura WebTest. O WebTest é uma biblioteca que lhe dá uma interface simples para testar aplicações baseadas em WSGI e, por conseguinte, os controladores de pedidos. Para tal, envolve uma aplicação WSGI numa app de teste especial que pode ser usada para testes. O WebTest permite-lhe interagir com os seus controladores sem um ambiente completo do App Engine. Pode emitir facilmente pedidos e modificar o ambiente de pedidos. As respostas também têm uma interface fácil de testar. Não tem de usar o WebTest, mas este torna a sua vida muito mais fácil.

Antes de começar, instale o WebTest na sua máquina local ou onde quer que pretenda executar testes de controladores. Pode encontrar instruções em: http://webtest.pythonpaste.org/#installation

Testar um controlador "Hello World" simples

Vamos começar por testar um controlador simples "Hello World!" que responde a um pedido do utilizador com uma resposta de texto simples. A resposta do controlador é "Hello World!" e o tipo de conteúdo é "text/plain":

import webapp2
import webtest

class HelloWorldHandler(webapp2.RequestHandler):
   def get(self):
       # Create the handler's response "Hello World!" in plain text.
       self.response.headers['Content-Type'] = 'text/plain'
       self.response.out.write('Hello World!')

Em seguida, crie o exemplo de teste e inicialize uma aplicação de teste que use o seu controlador:

...
class AppTest(unittest.TestCase):
    def setUp(self):
        # Create a WSGI application.
        app = webapp2.WSGIApplication([('/', HelloWorldHandler)])
        # Wrap the app with WebTest’s TestApp.
        self.testapp = webtest.TestApp(app)

    # Test the handler.
    def testHelloWorldHandler(self):
        response = self.testapp.get('/')
        self.assertEqual(response.status_int, 200)
        self.assertEqual(response.normal_body, 'Hello World!')
        self.assertEqual(response.content_type, 'text/plain')

Como pode ver, o WebTest permite-lhe fazer pedidos GET com uma simples chamada get() (outros métodos de pedidos têm métodos semelhantes). O valor de retorno é um objeto de resposta com o qual pode testar o código de estado, o corpo, o tipo de conteúdo e muito mais. Consulte a página inicial do WebTest para ver uma descrição detalhada de tudo o que pode fazer.

Criar um teste de controlador que usa um serviço do App Engine

Vejamos agora como testar um controlador que usa um serviço do App Engine. Isto significa que temos de lidar com dois componentes que podem afetar os nossos testes: o controlador e o serviço que estamos a usar. Conforme descrito no artigo Testes unitários locais para Python, a melhor forma de lidar com os serviços nos testes é usar o testbed.

O exemplo seguinte usa o Memcache, mas é o mesmo em princípio para outros serviços, como o Datastore ou a fila de tarefas.

O controlador que testamos armazena em cache a chave e o valor fornecidos. Tenha em atenção que analisamos ambos os valores dos parâmetros de pedido.

from google.appengine.api import memcache
from google.appengine.ext import testbed
import webapp2
import webtest

class CacheHandler(webapp2.RequestHandler):
  def post(self):
    key = self.request.get('key')
    value = self.request.get('value')
    memcache.set(key, value)

No teste, tal como antes, comece por criar uma aplicação e envolva-a com WebTest. Além disso, ative uma instância do Testbed e certifique-se de que a desativa após o teste.

...
class AppTest(unittest.TestCase):

  def setUp(self):
    app = webapp2.WSGIApplication([('/cache/', CacheHandler)])
    self.testapp = webtest.TestApp(app)
    self.testbed = testbed.Testbed()
    self.testbed.activate()

  def tearDown(self):
     self.testbed.deactivate()

  def testCacheHandler(self):
    # First define a key and value to be cached.
    key = 'answer'
    value = '42'
    self.testbed.init_memcache_stub()
    params = {'key': key, 'value': value}
    # Then pass those values to the handler.
    response = self.testapp.post('/cache/', params)
    # Finally verify that the passed-in values are actually stored in Memcache.
    self.assertEqual(value, memcache.get(key))

Configurar uma framework de testes

Se quiser, pode configurar uma framework de testes. Os testes para controladores que usam WebTest podem ser executados como os testes de unidades para o App Engine. A única diferença é que tem de se certificar de que tem o WebTest instalado.