Teste de gerenciador do Python 2

No artigo Teste de unidade local do Python (em inglês), descrevemos como executar testes de unidade do aplicativo. Os testes de unidade são ótimos para testar as unidades separadas do código, mas a integração dessas unidades de código é o que faz o aplicativo ser executado. Dessa maneira, o teste de integração é igualmente importante.

Para aplicativos do App Engine, os gerenciadores de solicitação são pontos de integração críticos. Um aplicativo WSGI encaminha solicitações para o gerenciador certo e o próprio gerenciador processa os dados da solicitação e gera uma resposta (leia mais sobre gerenciadores de solicitação). Os gerenciadores de solicitação são objetos normais do Python, como qualquer outra função ou classe, o que facilita o uso deles em testes automatizados. Mas, como um aplicativo WSGI os encapsula como um shell, usaremos um shell semelhante nos testes.

WebTest

Em nossos testes, utilizaremos a biblioteca WebTest. WebTest é uma biblioteca que oferece uma interface simples para testar aplicativos baseados em WSGI e, portanto, os gerenciadores de solicitação. Ela faz isso encapsulando um aplicativo WSGI em um app de teste especial que pode ser usado em testes. O WebTest permite interagir com os gerenciadores sem um ambiente do App Engine completo. Você pode emitir facilmente solicitações e modificar o ambiente de solicitação. As respostas também têm uma interface amigável. Você não precisa usar o WebTest, mas ele certamente facilita muito mais a vida.

Antes de começar, instale o WebTest em sua máquina local ou onde pretende executar os testes de gerenciador. As instruções podem ser encontradas em http://webtest.pythonpaste.org/#installation.

Como testar um gerenciador "Hello World" simples

Comece testando um gerenciador "Hello World!" simples que responde a uma solicitação do usuário com uma resposta de texto simples. A resposta do manipulador é "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 caso de teste e inicialize um aplicativo de teste que use o gerenciador:

...
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 você pode ver, WebTest permite fazer solicitações GET com uma chamada get() simples (outros métodos de solicitação têm métodos semelhantes). O valor de retorno é um objeto de resposta com que você pode testar o código de status, o corpo, o tipo de conteúdo e muito mais. Consulte a página inicial do WebTest para uma descrição detalhada de todas as coisas que você pode fazer.

Como criar um teste de gerenciador que usa um serviço do App Engine

Vamos dar uma olhada em como testar um gerenciador que usa um serviço do App Engine. Isso significa que agora precisamos processar dois componentes que podem afetar nossos testes: o gerenciador e o serviço que estamos usando. Conforme descrito no artigo Teste de unidade local para Python, a melhor maneira de processar serviços em testes é usando o testbed.

O exemplo a seguir usa Memcache, mas tem o mesmo princípio de outros serviços, como Datastore ou Task Queue.

O gerenciador que testamos armazena em cache a chave e o valor fornecidos. Analisamos ambos os valores dos parâmetros de solicitação.

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, assim como antes, primeiro crie um aplicativo e o encapsule com WebTest. Além disso, ative uma instância de Testbed e tenha o cuidado de desativá-la 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))

Como configurar uma estrutura de teste

Você poderá configurar uma estrutura de teste se quiser. Os testes para gerenciadores que usam WebTest podem ser executados como os testes de unidade do App Engine. A única diferença é que você precisa ter certeza de que o WebTest está instalado.