zoukankan      html  css  js  c++  java
  • Flask 学习 十四 测试

    获取代码覆盖报告

    安装代码覆盖工具

    pip install coverage

    manage.py 覆盖检测

    COV = None
    if os.environ.get('FLASK_COVERAGE'):
        import coverage
        COV = coverage.coverage(branch=True,include='app/*')
        COV.start()
    @manager.command
    def test(coverage=False):
        '''启动单元测试'''
        if coverage and not os.environ.get('FLASK_COVERAGE'):
            import sys
            os.environ['FLASK_COVERAGE']='1'
            os.execvp(sys.executable,[sys.executable] + sys.argv) # 设定完环境变量重启脚本
    
        import unittest
        tests=unittest.TestLoader().discover('tests')
        unittest.TextTestRunner(verbosity=2).run(tests)
    
        if COV:
            COV.stop()
            COV.save()
            print('覆盖总计:')
            COV.report()
            basedir = os.path.abspath(os.path.dirname(__file__))
            covdir = os.path.join(basedir,'tmp/coverage')
            COV.html_report(directory=covdir)
            print('HTML 版本:file://%s/index.html'% covdir)
            COV.erase()

     Flask测试客户端

    测试web程序

    tests/test_client.py 使用Flask测试客户端编写的测试框架

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import unittest
    from app import create_app,db
    from app.models import User,Role
    from flask import url_for
    import re
    class FlaskClientCase(unittest.TestCase):
        def setUp(self):
            self.app = create_app('testing')
            self.app_context = self.app.app_context()
            self.app_context.push()
            db.create_all()
            Role.insert_roles()
            # 测试客户端对象,use_cookies可保存cookies记住上下文
            self.client = self.app.test_client(use_cookies=True)
    
        def tearDown(self):
            db.session.remove()
            db.drop_all()
            self.app_context.pop()
    
        def test_home_page(self):
            response = self.client.get(url_for('main.index'))
            # as_text = True得到易于处理的字符串而不是字节数组
            self.assertTrue('访客' in response.get_data(as_text = True))
    
        def test_register_and_login(self):
            # 注册新账户
            respose = self.client.post(url_for('auth.register'),data = {'email':'papapa@qq.com','username':'papapa','password':'abc','password2':'abc'})
            self.assertTrue(respose.status_code ==302)
    
            # 使用新注册的账户登陆
            respose = self.client.post(url_for('auth.login'),data ={'email':'papapa@qq.com','password':'abc'},follow_redirects=True)
            data = respose.get_data(as_text=True)
            self.assertTrue(re.search('你好,s+papapa!',data))
            self.assertTrue('你还没有确认你的邮件信息' in data)
    
            # 发送确认令牌
            user = User.query.fliter_by(email ='papapa@qq.com').first()
            token = user.generate_confirmation_token()
            respose = self.client.get(url_for('auth.confirm',token=token),follow_redirects = True)
            data = respose.get_data(as_text=True)
            self.assertTrue('你已经确认了你的账户' in data)
    
            # 退出
            respose = self.client.get(url_for('auth.logout'),follow_redirects = True)
            data = respose.get_data(as_text=True)
            self.assertTrue('你已经退出' in data)

    config.py 在测试配置中禁用CSRF保护

    class Config:
        WTF_CSRF_ENABLED=False # 测试中禁用CSRF保护

    测试web api服务

    tests/test_api.py 使用Flask 测试客户端测试REST API

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import unittest
    from app import create_app,db
    from app.models import User,Role
    from flask import url_for
    import re,json
    import base64
    
    class APITestCase(unittest.TestCase):
        def setUp(self):
            self.app = create_app('testing')
            self.app_context = self.app.app_context()
            self.app_context.push()
            db.create_all()
            Role.insert_roles()
            self.client = self.app.test_client()
    
        def tearDown(self):
            db.session.remove()
            db.drop_all()
            self.app_context.pop()
    
        def get_api_headers(self,username,password):
            return {
                'Authorization':'Basic' + base64.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):
            # 添加一个用户
            r = Role.query.fliter_by(name = 'User').first()
            self.assertIsNotNone(r)
            u = User(email = 'bababa@qq.com',password = 'abc',confirmed = True,role = r)
            db.session.add(u)
            db.session.commit()
    
            # 写一篇文章
            response = self.client.post(url_for('api.new_post'),
                                        headers = self.get_api_headers('bababa@qq.com','abc'),
                                        data = json.dumps({'body':'body of the blog'}) )
            self.assertTrue(response.status_code ==201)
            url = response.headers.get('Location')
            self.assertIsNotNone(url)
    
            # 获取刚发布文章
            response = self.client.get(url,headers = self.get_api_headers('bababa@qq.com','abc'))
            self.assertTrue(response.status_code ==200)
            # 测试客户端不会自动json编码解码
            json_response = json.loads(response.data.decode('utf-8'))
            self.assertTrue(json_response['url']==url)
            self.assertTrue(json_response['body']=='body of the blog')
            self.assertTrue(json_response['body_html'=='<p>body of blog post</p>'])

    使用Selenium 进行端到端测试

    pip install selenium

    app/main/views.py 关闭服务器的路由

    # 当所有测试完成之后关闭服务器的路由
    @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....'

    tests/test_selenium.py 使用Selenium运行测试的框架

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import unittest
    from selenium import webdriver
    from app import create_app,db
    from app.models import User,Role,Post
    from flask import url_for
    import re,json,time
    import base64
    import threading
    
    class SeleniumTestCase(unittest.TestCase):
        client =None
    
        @classmethod
        def setUpClass(cls):
            # 启动Firefox
            try:
                cls.client = webdriver.Firefox()
            except:
                pass
            # 如果无法启动浏览器则跳过这些测试
            if cls.client:
                # 创建程序
                cls.app = create_app('testing')
                cls.app_context = cls.app.app_context()
                cls.app_context.push()
    
                # 禁止日志,保持输出简洁
                import logging
                logger = logging.getLogger('werkzeug')
                logger.setLevel('ERROR')
    
                # 创建数据库,并使用一些虚拟数据填充
                db.create_all()
                Role.insert_roles()
                User.generate_fake(10)
                Post.generate_fake(10)
    
                # 添加管理员
                admin_role = Role.query.filter_by(permission=0xff).first()
                admin = User(email = 'bababa@qq.com',username = 'bababa',password = 'abc',role = admin_role,confirmed = True)
                db.session.add(admin)
                db.session.commit()
    
                # 在一个线程中启动Flask服务器
                threading.Thread(target=cls.app.run).start()
    
                time.sleep(1)
    
        @classmethod
        def tearDownClass(cls):
            if cls.client:
                # 关闭Flask服务器和浏览器
                cls.client.get('http://localhost:5000/shutdown')
                cls.client.close()
    
                # 销毁数据库数据
                db.drop_all()
                db.session.remove()
    
                # 删除程序上下文
                cls.app_context.pop()
    
        def setUp(self):
            if not self.client:
                self.skipTest('web 浏览器无效')
        def tearDown(self):
            pass
    
        def test_admin_home_page(self):
            # 进入首页
            self.client.get('http://localhost:5000/')
            self.assertTrue(re.search('你好,s+访客',self.client.page_source))
    
            # 进入登陆页面
            self.client.find_element_by_link_text('登陆').click()
            self.assertTrue('<h1>登陆</h1>' in self.client.page_source)
    
            # 登陆
            self.client.find_element_by_name('邮箱').send_keys('bababa.qq.com')
            self.client.find_element_by_name('密码').send_keys('abc')
            self.client.find_element_by_name('提交').click()
            self.assertTrue(re.search('你好,s+bababa!',self.client.page_source))
    
            # 进入用户个人资料页面
            self.client.find_element_by_link_text('个人资料').click()
            self.assertTrue('<h1>bababa</h1>' in self.client.page_source)
  • 相关阅读:
    Linux chattr 文件保护
    ArcGIS案例学习笔记-批处理擦除挖空挖除相减
    ArcGIS案例学习笔记-手动编辑擦除挖空挖除相减
    GIS案例学习笔记-CAD数据分层导入现有模板实例教程
    GIS案例学习笔记-ArcGIS整图大图出图实例教程
    Arcgis map export or print Error: Cannot map metafile into memory. Not enough memory
    [图解tensorflow源码] 入门准备工作附常用的矩阵计算工具[转]
    GIS案例学习笔记-明暗等高线提取地理模型构建
    地理处理模型、案例、教程、培训低价发送
    GIS工具-shp浏览器
  • 原文地址:https://www.cnblogs.com/Erick-L/p/6960942.html
Copyright © 2011-2022 走看看