O teste de unidade permitirá verificar a qualidade do código depois que você escrevê-lo, mas também é possível usá-lo para melhorar o processo de desenvolvimento à medida que avança. Em vez de gravar testes depois de concluir o desenvolvimento do aplicativo, considere a possibilidade de gravar os testes conforme você avança. Isso ajuda você a projetar unidades de código pequenas, de fácil manutenção e reutilizáveis. Isso também facilita o teste rápido e completo do código.
Ao fazer o teste de unidade local, você executa testes que permanecem dentro do ambiente de desenvolvimento sem envolver componentes remotos. O App Engine oferece utilitários de teste que usam implementações locais de armazenamento de dados e outros serviços do App Engine. Isso significa ser possível fazer o código usar esses serviços localmente, sem implantá-lo no App Engine, usando-se stubs de serviço.
Stub de serviço é um método que simula o comportamento do serviço. Por exemplo, o stub de serviço do armazenamento de dados mostrado em Como escrever testes de Datastore e Memcache permite testar o código do armazenamento de dados sem fazer solicitações para o armazenamento de dados real. Qualquer entidade armazenada durante um teste de unidade do armazenamento de dados é mantida na memória, e não no armazenamento de dados, e será excluída depois da execução do teste. É possível executar testes pequenos e rápidos sem dependência do próprio armazenamento de dados.
Neste documento, descrevemos como criar testes de unidade em vários serviços locais do Google App Engine e, em seguida, fornecemos algumas informações sobre como configurar uma estrutura de teste.
Apresentação dos utilitários de teste para Python 2
Um módulo Python do App Engine chamado
testbed
disponibiliza stubs de serviço para testes de unidade.
Os stubs de serviço estão disponíveis para os seguintes serviços:
- App Identity
init_app_identity_stub
- Blobstore (use
init_blobstore_stub
) - Capacidade (use
init_capability_stub
) - Armazenamento de dados (use
init_datastore_v3_stub
) - Arquivos (use
init_files_stub
) - Imagens (somente para
dev_appserver.
Use
init_images_stub
) - LogService (use
init_logservice_stub
) - E-mail (use
init_mail_stub
) - Memcache (use
init_memcache_stub
) - Task Queue (use
init_taskqueue_stub
) - Busca de URL (use
init_urlfetch_stub
) - Serviço de usuário (use
init_user_stub
)
Para inicializar todos os stubs ao mesmo tempo, é possível usar init_all_stubs
.
Como escrever testes de armazenamento de dados e memcache
Nesta seção, você verá um exemplo de como gravar um código que testa o uso dos serviços de armazenamento de dados e Memcache.
Verifique se o executor de teste tem as bibliotecas apropriadas no caminho
de carregamento do Python, incluindo as bibliotecas do App Engine, yaml
(incluídas no SDK
do App Engine), a raiz do aplicativo e outras modificações
esperadas pelo código do aplicativo (como um diretório ./lib
local, se você tiver
um). Exemplo:
import sys
sys.path.insert(1, 'google-cloud-sdk/platform/google_appengine')
sys.path.insert(1, 'google-cloud-sdk/platform/google_appengine/lib/yaml/lib')
sys.path.insert(1, 'myapp/lib')
Importe o módulo Python unittest
e os módulos do App Engine que são relevantes
para os serviços testados, neste caso memcache
e ndb
, que usa o
armazenamento de dados e o memcache. Importe também o
módulo
testbed
.
Em seguida, crie uma classe TestModel
. Neste exemplo, uma função verifica
se uma entidade está armazenada no memcache. Se não for encontrada uma entidade, ela verificará se há uma
entidade no armazenamento de dados. Muitas vezes, isso pode ser redundante na vida real, já que ndb
usa o próprio Memcache por trás das cortinas, mas ainda é um padrão aceitável para um
teste.
Em seguida, crie um caso de teste. Não importa os serviços testados, o caso de teste
precisa criar uma instância de Testbed
e ativá-la. O caso de teste também precisa
inicializar os stubs de serviço relevantes, neste caso usando
init_datastore_v3_stub
e init_memcache_stub
. Os métodos para inicializar
outros stubs de serviço do App Engine estão listados em Introdução aos utilitários
de teste do Python.
O método init_datastore_v3_stub()
sem argumento usa um armazenamento de dados na memória
que é inicialmente vazio. Se você quiser testar uma entidade atual do armazenamento
de dados, inclua seu nome de caminho como argumento para init_datastore_v3_stub()
.
Além de setUp()
, inclua um método tearDown()
para desativar o
testbed. Isso restaura os stubs originais para que os testes não interfiram uns nos outros.
Em seguida, implemente os testes.
Agora é possível usar TestModel
para criar testes que usam stubs de serviço do
armazenamento de dados ou do memcache em vez de usar serviços reais.
Por exemplo, o método mostrado abaixo cria duas entidades: a primeira entidade usa
o valor padrão para o atributo number
(42) e a segunda usa o valor não
padrão para number
(17). O método então constrói uma consulta
para entidades TestModel
, mas apenas para as que têm o valor padrão de number
.
Depois de recuperar todas as entidades correspondentes, o método testa se exatamente uma entidade foi
encontrada e se o valor do atributo number
dessa entidade é o valor
padrão.
Como outro exemplo, o método a seguir cria uma entidade e a recupera
usando a função GetEntityViaMemcache()
que criamos acima. O método
testa se uma entidade foi retornada e se o valor number
dela é o mesmo da
entidade criada anteriormente.
Por fim, invoque unittest.main()
.
Para executar os testes, consulte Como executar testes.
Como escrever testes do Cloud Datastore
Se o app usar o Cloud Datastore, será possível escrever
testes que verifiquem o comportamento do app diante de uma consistência
eventual.
db.testbed
expõe opções que tornam isso
fácil:
A classe PseudoRandomHRConsistencyPolicy
permite que você controle a probabilidade de uma
gravação se aplicar antes de cada consulta global (não ancestral). Ao definir a
probabilidade como 0%, instruímos o stub do armazenamento de dados a operar com a
quantidade máxima de consistência eventual. Consistência eventual máxima significa que haverá commit das gravações, mas elas sempre deixarão de ser aplicadas. Dessa maneira, consultas globais (não de ancestral) sempre deixarão de ver alterações. É claro que isso não representa a quantidade de
consistência eventual que seu aplicativo vê ao ser executado na
produção, mas para fins de teste é muito útil poder configurar
o armazenamento de dados local para se comportar sempre dessa maneira. Se você usa uma
probabilidade diferente de zero, PseudoRandomHRConsistencyPolicy
faz uma sequência
determinística de decisões de consistência, então os resultados do teste são consistentes:
As APIs de teste são úteis para verificar se seu aplicativo se comporta adequadamente
diante de consistência eventual, mas lembre-se que o modelo de consistência de leitura de Alta
replicação local é uma aproximação do modelo de consistência de leitura de Alta
replicação de produção, não uma réplica exata. No ambiente
local, executar um get()
de um Entity
que pertence a um grupo de entidades
com uma gravação não aplicada sempre tornará os resultados da gravação não aplicada
visíveis para as consultas globais subsequentes. Isso não ocorre na produção.
Como escrever testes de e-mail
Você pode usar o stub de serviço de e-mail para testar o serviço de e-mail. Semelhante a outros serviços compatíveis com testbed, primeiro você inicializa o stub, invoca o código que usa a API de e-mail e finalmente testa se as mensagens corretas foram enviadas.
Como escrever testes de fila de tarefas
Você pode usar o stub de fila de tarefas para gravar testes que usam o serviço de fila de tarefas. Semelhante a outros serviços compatíveis com testbed, primeiro você inicializa o stub, invoca o código que usa a API de fila de tarefas e, finalmente, testa se as tarefas foram adequadamente adicionadas à fila.
Como definir o arquivo de configuração queue.yaml
Se você quiser executar testes no código que interage com uma fila não padrão, será
necessário criar e especificar um arquivo queue.yaml
para o aplicativo usar.
Veja um exemplo queue.yaml
abaixo.
Para mais informações sobre as opções disponíveis de queue.yaml, consulte configuração da fila de tarefas.
O local do queue.yaml
é especificado ao inicializar o stub:
self.testbed.init_taskqueue_stub(root_path='.')
Na amostra, queue.yaml
está no mesmo diretório que os testes. Se ele estivesse em
outra pasta, esse caminho precisaria ser especificado em root_path
.
Como filtrar tarefas
O stub da fila de tarefas get_filtered_tasks
permite que você filtre tarefas enfileiradas.
Isso facilita a gravação de testes que precisam verificar o código que enfileira
várias tarefas.
Como escrever testes de tarefa adiada
Se o código do aplicativo usar a biblioteca
adiada, será possível usar o stub taskqueue junto com deferred
para verificar se as funções adiadas estão na fila e executadas corretamente.
Como alterar as variáveis de ambiente padrão
Os serviços do App Engine geralmente dependem de variáveis de ambiente. O método activate()
de classe testbed.Testbed
usa valores padrão para eles, mas é possível definir valores
personalizados com base nas necessidades de teste com o método setup_env
de classe testbed.Testbed
.
Por exemplo, digamos que você tem um teste que armazena diversas entidades
no armazenamento de dados, todas elas ligadas ao mesmo ID de aplicativo. Agora você quer executar
os mesmos testes novamente, mas usando um ID de aplicativo diferente
daquele ligado às entidades armazenadas. Para fazer isso, passe o novo valor para
self.setup_env()
como app_id
.
Exemplo:
Como simular o login
Outro uso frequente para setup_env
é simular um usuário que está sendo conectado,
com ou sem privilégios de administrador, para verificar se seus manipuladores operam
corretamente em cada caso.
Agora, seus métodos de teste podem chamar, por exemplo, self.loginUser('', '')
para
simular que nenhum usuário está conectado, self.loginUser('test@example.com', '123')
para
simular que um usuário não administrador está conectado, self.loginUser('test@example.com',
'123', is_admin=True)
para simular que um usuário administrador está conectado.
Como configurar um framework de testes
Os utilitários de teste do SDK não estão associados a uma biblioteca específica. É possível executar os testes de unidade com qualquer executor disponível no App Engine, como nose- gae ou ferrisnose. Você também pode criar um executor de testes simples por conta própria ou usar o que é mostrado abaixo.
Os scripts a seguir usam o módulo unittest do Python.
Você pode dar o nome que quiser ao script. Ao executá-lo, forneça o caminho para a Google Cloud CLI ou a instalação do Google App Engine SDK e o caminho para os módulos de teste. O script descobrirá todos os testes no caminho fornecido e
imprimirá os resultados no fluxo de erros padrão. Os arquivos de teste seguem a convenção
de ter o prefixo test
no nome.
Como executar os testes
É possível executar esses testes simplesmente executando o script runner.py
, é
descrito em detalhes em Como configurar um framework de teste:
python runner.py <path-to-appengine-or-gcloud-SDK> .