针对 Python 的本地单元测试一文介绍了如何为您的应用运行单元测试。虽然单元测试非常适合分别测试代码的各个单元,但应用的运行离不开这些代码单元的集成 - 因此集成测试同样很重要。
对于 App Engine 应用,请求处理程序是关键的集成点。当 WSGI 应用将请求路由到正确的处理程序时,处理程序本身会处理请求数据并生成响应(详细了解请求处理程序)。请求处理程序是普通的 Python 对象(就像任何其他函数或类一样),这使得它们易于在自动化测试中使用。但是,由于 WSGI 应用会像 shell 一样封装这些处理程序,因此我们将在测试中使用类似的 shell。
WebTest
对于我们的测试,我们将使用 WebTest 框架。WebTest 是一个库,它为您提供了一个简单的界面来测试基于 WSGI 的应用,从而测试请求处理程序。为此,它会将 WSGI 应用封装在一个随后可用于测试的特殊测试应用中。借助 WebTest,您可以在没有完整 App Engine 环境的情况下与处理程序互动;您可以轻松发出请求并修改请求环境。响应也有一个便于测试的界面。您并不是必须使用 WebTest,但它确实可以让测试容易很多。
在开始之前,请在本地机器上或打算运行处理程序测试的任何位置安装 WebTest。http://webtest.pythonpaste.org/#installation 提供了说明
测试简单的“Hello World”处理程序
我们首先测试一个简单的“Hello World!”处理程序,该处理程序使用纯文本回复来响应用户请求。处理程序的响应是“Hello World!”,内容类型为“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!')
接下来,创建测试用例并初始化使用您的处理程序的测试应用:
... 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')
如您所见,WebTest 可让您通过简单的 get() 调用来发出 GET 请求(其他请求方法具有类似的方法)。返回值是一个响应对象,您可以使用该对象来测试状态代码、正文、内容类型等等。请查看 WebTest 首页,以了解您可以执行的所有操作的详细说明。
创建使用 App Engine 服务的处理程序测试
下面,我们来看看如何测试使用 App Engine 服务的处理程序。这意味着我们现在必须处理可能会影响我们测试的两个组件:处理程序和我们正在使用的服务。如针对 Python 的本地单元测试一文中所述,在测试中处理服务的最佳方法是使用 testbed。
以下示例使用 Memcache,但原则上对于其他服务(如 Datastore 或任务队列)也是如此。
我们测试的处理程序会缓存给定的键和值。请注意,我们从求参数中解析这两个值。
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)
和以前一样,首先在测试中创建一个应用并使用 WebTest 封装该应用。另外,还要激活 Testbed 实例并注意在测试后停用该实例。
... 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))
设置测试框架
如果您愿意,可以设置测试框架。针对使用 WebTest 的处理程序的测试,可以像针对 App Engine 的单元测试一样执行。唯一的区别是,您需要确保已安装 WebTest。