测试、性能优化与部署指南
1. 测试Web服务
若已在GitHub上克隆应用的Git仓库,可运行
git checkout 15b
来检出该版本的应用。Flask测试客户端也可用于测试RESTful Web服务。以下是一个包含两个测试的单元测试类示例:
# tests/test_api.py: RESTful API testing with the Flask test client
import unittest
from flask import url_for
import json
from base64 import b64encode
from app.models import Role, User, db
class APITestCase(unittest.TestCase):
# ...
def get_api_headers(self, username, password):
return {
'Authorization':
'Basic ' + b64encode(
(username + ':' + password).encode('utf-8')).decode('utf-8'),
'Accept': 'application/json',
'Content-Type': 'application/json'
}
def test_no_auth(self):
response = self.client.get(url_for('api.get_posts'),
content_type='application/json')
self.assertTrue(response.status_code == 401)
def test_posts(self):
# add a user
r = Role.query.filter_by(name='User').first()
self.assertIsNotNone(r)
u = User(email='john@example.com', password='cat', confirmed=True,
role=r)
db.session.add(u)
db.session.commit()
# write a post
response = self.client.post(
url_for('api.new_post'),
headers=self.get_api_headers('john@example.com', 'cat'),
data=json.dumps({'body': 'body of the blog post'}))
self.assertTrue(response.status_code == 201)
url = response.headers.get('Location')
self.assertIsNotNone(url)
# get the new post
response = self.client.get(
url,
headers=self.get_api_headers('john@example.com', 'cat'))
self.assertTrue(response.status_code == 200)
json_response = json.loads(response.data.decode('utf-8'))
self.assertTrue(json_response['url'] == url)
self.assertTrue(json_response['body'] == 'body of the *blog* post')
self.assertTrue(json_response['body_html'] ==
'<p>body of the <em>blog</em> post</p>')
API测试的
setUp()
和
tearDown()
方法与常规应用相同,但无需配置cookie支持,因为API不使用它。
get_api_headers()
方法是一个辅助方法,返回所有请求都需发送的通用头信息,包括认证凭证和MIME类型相关头信息。
-
test_no_auth()测试确保不包含认证凭证的请求会被拒绝,并返回错误代码401。 -
test_posts()测试向数据库添加用户,然后使用RESTful API插入博客文章并读取。发送数据的请求必须使用json.dumps()进行编码,响应体也以JSON格式返回,需使用json.loads()解码后才能检查。
2. 端到端测试与Selenium
Flask测试客户端无法完全模拟运行中应用的环境,例如依赖客户端浏览器中JavaScript代码运行的应用就无法正常工作。此时,可使用Selenium进行端到端测试。
首先,安装Selenium的Python接口:
(venv) $ pip install selenium
测试时,应用需在监听真实HTTP请求的Web服务器中运行。此方法在后台线程中使用开发服务器启动应用,同时在主线程上运行测试。Selenium在测试控制下启动Web浏览器并连接到应用执行操作。
为了在测试完成后优雅地停止Flask服务器,可实现一个服务器关闭路由:
# _app/main/views.py: Server shutdown route
from flask import request, abort, current_app
from . import main
@main.route('/shutdown')
def server_shutdown():
if not current_app.testing:
abort(404)
shutdown = request.environ.get('werkzeug.server.shutdown')
if not shutdown:
abort(500)
shutdown()
return 'Shutting down...'
以下是一个使用Selenium配置测试用例的框架:
# tests/test_selenium.py: Framework for tests using Selenium
import unittest
from selenium import webdriver
import threading
from app import create_app, db
from app.models import Role, User
class SeleniumTestCase(unittest.TestCase):
client = None
@classmethod
def setUpClass(cls):
# start Firefox
try:
cls.client = webdriver.Firefox()
except:
pass
# skip these tests if the browser could not be started
if cls.client:
# create the application
cls.app = create_app('testing')
cls.app_context = cls.app.app_context()
cls.app_context.push()
# suppress logging to keep unittest output clean
import logging
logger = logging.getLogger('werkzeug')
logger.setLevel("ERROR")
# create the database and populate with some fake data
db.create_all()
Role.insert_roles()
User.generate_fake(10)
Post.generate_fake(10)
# add an administrator user
admin_role = Role.query.filter_by(permissions=0xff).first()
admin = User(email='john@example.com',
username='john', password='cat',
role=admin_role, confirmed=True)
db.session.add(admin)
db.session.commit()
# start the Flask server in a thread
threading.Thread(target=cls.app.run).start()
@classmethod
def tearDownClass(cls):
if cls.client:
# stop the flask server and the browser
cls.client.get('http://localhost:5000/shutdown')
cls.client.close()
# destroy database
db.drop_all()
db.session.remove()
# remove application context
cls.app_context.pop()
def setUp(self):
if not self.client:
self.skipTest('Web browser not available')
def tearDown(self):
pass
以下是一个使用Selenium的单元测试示例:
# tests/test_selenium.py: Example Selenium unit test
import unittest
import re
from selenium import webdriver
class SeleniumTestCase(unittest.TestCase):
# ...
def test_admin_home_page(self):
# navigate to home page
self.client.get('http://localhost:5000/')
self.assertTrue(re.search('Hello,\s+Stranger!',
self.client.page_source))
# navigate to login page
self.client.find_element_by_link_text('Log In').click()
self.assertTrue('<h1>Login</h1>' in self.client.page_source)
# login
self.client.find_element_by_name('email').\
send_keys('john@example.com')
self.client.find_element_by_name('password').send_keys('cat')
self.client.find_element_by_name('submit').click()
self.assertTrue(re.search('Hello,\s+john!', self.client.page_source))
# navigate to the user's profile page
self.client.find_element_by_link_text('Profile').click()
self.assertTrue('<h1>john</h1>' in self.client.page_source)
此测试使用
setUpClass()
中创建的管理员账户登录应用,然后打开个人资料页面。与Flask测试客户端不同,Selenium测试向Web浏览器发送命令,不直接与应用交互,命令与真实用户使用鼠标或键盘执行的操作相似。
3. 性能优化
3.1 记录缓慢的数据库性能
应用性能随时间下降,可能是由于数据库查询缓慢,且随着数据库规模增大而恶化。优化数据库查询可简单到添加更多索引,也可复杂到在应用和数据库之间添加缓存。
Flask - SQLAlchemy可记录请求期间发出的数据库查询统计信息。以下是记录慢查询的示例:
# app/main/views.py: Report slow database queries
from flask.ext.sqlalchemy import get_debug_queries
from . import main
from flask import current_app
@main.after_app_request
def after_request(response):
for query in get_debug_queries():
if query.duration >= current_app.config['FLASKY_SLOW_DB_QUERY_TIME']:
current_app.logger.warning(
'Slow query: %s\nParameters: %s\nDuration: %fs\nContext: %s\n' %
(query.statement, query.parameters, query.duration,
query.context))
return response
get_debug_queries()
函数返回请求期间发出的查询列表,每个查询的信息如下表所示:
| 名称 | 描述 |
|---|---|
| statement | SQL语句 |
| parameters | SQL语句使用的参数 |
| start_time | 查询发出的时间 |
| end_time | 查询返回的时间 |
| duration | 查询持续的时间(秒) |
| context | 指示查询发出的源代码位置的字符串 |
为了在生产模式下启用数据库查询性能记录,需进行以下配置更改:
# config.py: Configuration for slow query reporting
class Config:
# ...
SQLALCHEMY_RECORD_QUERIES = True
FLASKY_DB_QUERY_TIMEOUT = 0.5
# ...
3.2 源代码分析
另一个可能的性能问题来源是高CPU消耗,由执行大量计算的函数引起。源代码分析器有助于找到应用中最慢的部分。
Flask的开发Web服务器可选择为每个请求启用Python分析器。以下是添加启动分析器的命令行选项示例:
# manage.py: Run the application under the request profiler
from flask_script import Manager
from werkzeug.contrib.profiler import ProfilerMiddleware
from app import app
manager = Manager(app)
@manager.command
def profile(length=25, profile_dir=None):
"""Start the application under the code profiler."""
app.wsgi_app = ProfilerMiddleware(app.wsgi_app, restrictions=[length],
profile_dir=profile_dir)
app.run()
当使用
python manage.py profile
启动应用时,控制台将显示每个请求的分析器统计信息,包括最慢的25个函数。可使用
--length
选项更改报告中显示的函数数量,使用
--profile-dir
选项将每个请求的分析数据保存到指定目录的文件中。
4. 部署
Flask自带的Web开发服务器在生产环境中不够健壮、安全或高效。部署Flask应用时,无论使用何种托管方法,在生产服务器上安装应用时都需执行一系列任务,如创建或更新数据库表。
可在
manage.py
中添加一个命令来执行所有必需的任务:
# manage.py: deploy command
from flask_script import Manager
from flask.ext.migrate import upgrade
from app.models import Role, User
from app import app
manager = Manager(app)
@manager.command
def deploy():
"""Run deployment tasks."""
# migrate database to latest revision
upgrade()
# create user roles
Role.insert_roles()
# create self-follows for all users
User.add_self_follows()
总结
测试是确保应用质量的重要环节,应设计高效的测试策略,并编写易于测试的代码。性能优化能提升应用响应速度,提高用户体验。合理的部署流程可确保应用在生产环境中稳定运行。通过以上方法,可有效提升应用的质量、性能和可靠性。
测试、性能优化与部署指南
5. 关键操作流程总结
为了更清晰地展示各个部分的操作流程,下面将以流程图和列表的形式进行总结。
5.1 测试流程
graph LR
A[克隆应用仓库] --> B[切换到指定版本]
B --> C{选择测试方式}
C -->|Flask测试客户端| D[编写API测试用例]
C -->|Selenium| E[安装Selenium]
E --> F[启动应用服务器]
F --> G[启动浏览器并执行测试]
D --> H[执行测试并检查结果]
G --> H
具体步骤如下:
1. 克隆应用仓库:
git clone <repository_url>
2. 切换到指定版本:
git checkout <version>
,如
git checkout 15b
3. 若使用Flask测试客户端:
- 编写API测试用例,参考
tests/test_api.py
中的示例代码。
- 执行测试命令,检查测试结果。
4. 若使用Selenium:
- 安装Selenium:
pip install selenium
- 启动应用服务器:在后台线程中使用开发服务器启动应用。
- 启动浏览器并执行测试,参考
tests/test_selenium.py
中的示例代码。
5.2 性能优化流程
graph LR
A[开启查询统计记录] --> B[运行应用并处理请求]
B --> C[记录查询信息]
C --> D{查询是否缓慢}
D -->|是| E[记录慢查询到日志]
D -->|否| F[继续处理请求]
G[启动应用并开启分析器] --> H[执行请求并记录函数信息]
H --> I[分析函数性能]
具体步骤如下:
1. 记录缓慢的数据库性能:
- 配置
config.py
,开启查询统计记录:
class Config:
SQLALCHEMY_RECORD_QUERIES = True
FLASKY_DB_QUERY_TIMEOUT = 0.5
- 运行应用,处理请求时记录查询信息。
- 检查查询是否缓慢,若缓慢则记录到日志。
-
源代码分析:
-
启动应用并开启分析器:
python manage.py profile - 执行请求,记录函数信息。
- 分析函数性能,找出慢函数。
-
启动应用并开启分析器:
5.3 部署流程
graph LR
A[克隆应用仓库] --> B[切换到指定版本]
B --> C[执行部署命令]
C --> D[迁移数据库]
D --> E[创建用户角色]
E --> F[添加用户自关注]
具体步骤如下:
1. 克隆应用仓库:
git clone <repository_url>
2. 切换到指定版本:
git checkout <version>
,如
git checkout 16a
3. 执行部署命令:
python manage.py deploy
4. 迁移数据库到最新版本。
5. 创建用户角色。
6. 为所有用户添加自关注。
6. 注意事项与最佳实践
在进行测试、性能优化和部署的过程中,有一些注意事项和最佳实践需要遵循。
6.1 测试方面
- 对于简单的数据库模型和应用逻辑,应编写简单、聚焦的测试用例,确保核心逻辑的正确性。
- 端到端测试虽然必要,但由于编写复杂度较高,应仅用于无法孤立测试的功能。
- 应用代码应进行合理组织,将业务逻辑尽可能推到数据库模型或其他辅助类中,以便于测试。
6.2 性能优化方面
- 数据库查询优化可从简单的添加索引开始,逐步尝试更复杂的方法,如添加缓存。
- 源代码分析应在开发环境中进行,避免在生产环境中使用可能影响性能的分析器。
- 配置日志记录时,根据实际需求选择合适的日志级别,如将慢查询日志级别设置为“error”可通过邮件接收通知。
6.3 部署方面
-
每次部署前,确保所有依赖项已正确安装,可使用
pip install -r requirements/dev.txt进行安装。 - 部署命令应包含所有必要的任务,如数据库迁移、角色创建等,避免手动操作带来的错误。
通过遵循这些注意事项和最佳实践,可以提高应用的质量、性能和可靠性,为用户提供更好的体验。
总结
本文围绕应用的测试、性能优化和部署展开,详细介绍了使用Flask测试客户端和Selenium进行测试的方法,记录缓慢数据库查询和进行源代码分析的性能优化策略,以及部署应用的具体步骤。通过流程图、列表和代码示例,清晰地展示了各个环节的操作流程。同时,还给出了相关的注意事项和最佳实践,希望能帮助开发者更好地开发和维护高质量的应用。在实际应用中,应根据具体情况选择合适的方法和策略,不断优化应用,提升用户体验。
超级会员免费看
1921

被折叠的 条评论
为什么被折叠?



