用flask开发个人博客(40)—— Flask中三种测试方法

来源:互联网 发布:matlab交易程序源码 编辑:程序博客网 时间:2024/04/28 11:06

一、单元测试并统计测试的覆盖率

1.1 Flask中的单元测试

        在之前的文章中介绍过在flask中进行单元测试的方法,目前我们的代码中存在下面的单元测试:

classBasicTestCase(unittest.TestCase):    def Setup(self):        self.app=create_app('testing')        self.app_context=self.app.app_context()        self.app_context.push()        db.create_all()     def teardown(self):        db.session.remove()        db.drop_all()        self.app_context.pop()     def test_app_exits(self):        self.assertFalse(current_app is None)     def test_app_is_testing(self):       self.assertFalse(current_app.config['TESTING'])

        并且,我们在manager的命令行中增加了运行单元测试的命令:

@manager.command def test():     """Run the unittests"""     import unittest    tests=unittest.TestLoader().discover('test')    unittest.TextTestRunner(verbosity=2).run(tests)

        可以通过命令行,按照下面的方式进行单元测试:

(flasky)hyman@hyman-VirtualBox:~/Github/flaskTs$ python manager.py testtest_app_exits(test_basic.BasicTestCase) ... oktest_app_is_testing(test_basic.BasicTestCase) ... ok ----------------------------------------------------------------------Ran 2 tests in0.005s OK 

1.2 使用coverage进行单元测试覆盖率的统计

        Flask中可以使用coverage模块来统计进行单元测试的代码覆盖率,其安装方式如下:

pip installcoverage

        安装完成后,我们将coverage作为一个自定义命令的选项附加到test命令中:

COV=Noneifos.environ.get('COVERAGE'):    import coverage    COV=coverage.coverage(branch=True,include='*')    COV.start() @manager.command deftest(coverage=False):     """Run the unittests"""    if coverage and notos.environ.get('COVERAGE'):        import sys        os.environ['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('Coverage:')        COV.report()        COV.erase()

        首先在全局的范围内,我们先检查是否具有'COVERAGE'环境变量,如果定义了该变量,就利用coverage的coverage函数构造一个coverage对象COV。coverage函数有两个参数,第一个参数branch设置为True表示检查的模块包含指定目录下的子目录,而第二个参数include是在指定目录,设置成’*’的意思就是设置当前目录和当前目录下的模块位检查模块。

        而在test()函数中,附加的命令行参数coverage会作为test()函数的一个bool类型的参数,如果命令行附加了该参数,coverage将会等于True。在函数内部,先判断是否coverage已经是否定义了'COVERAGE'环境变量。因为我们定义以及执行COV的代码为全局代码,在执行test命令行之前已经执行过,所以在判断完之后,调用了os.execvp重新执行了程序。接下来COV变量不再是None,就可进行if COV后面的操作。

        执行的程序结果如下,由于将当前目录下以及子目录下所有的模块都作为了统计对象,所以结果中包含了flask本身自带的一些模块。


二、使用Flask Web测试客户端进行测试   

        Flask中的成员函数test_client()可以返回一个客户端对象,可以模拟Web客户端,用来同Web服务端进行交互。它可以测试Web程序,也可以用来测试Rest API,下面就该客户端的使用进行讨论。

2.1 测试Web程序

        新建一个FlaskClientTest单元测试类如下:

classFlaskClientTest(unittest.TestCase):    def setUp(self):        self.app=create_app('testing')        self.app_context=self.app.app_context()        self.app_context.push()        db.create_all()        self.client=self.app.test_client()       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'))        self.assertTrue('Home' inresponse.get_data(as_text=True))       def test_register(self):       response=self.client.post(url_for('main.register'),data={            'email':'879651072@qq.com',            'name':'Hyman',            'password1':'123',            'password2':'123'})       self.assertTrue(response.status_code==302)

        test_home_page是用来进行测试主页的测试用例,这里使用self.client.get(url_for('main.index'))的方法,使用GET方法访问相应的url,并获取响应结果。然后调用response的get_data()获取响应结果,这里面设置as_text=True,会把结果格式化成一个字符串,进而判断‘Home’是否在这个字符串中。

        test_register用来模拟注册用户过程,对注册的路由进行测试。这里采用了POST的方法发送了一个表单,而data中是对表单各个字段的赋值,这里面的key值一定要和我们定义的注册表单的字段名称一致。由于注册路由最终向主页进行了重定向,届时服务端回返回给浏览器302的状态码,我们通过判断响应的status_code是否是302而判断测试是否通过。

2.2 测试Rest API

        接下来,测试下上篇文章编写的一个用来增加新博客的Rest API:

deftest_posts(self):        response=self.client.post(            url_for('main.new_post'),            data=json.dumps({'body':'I am a newpost'}),            content_type='application/json')       self.assertTrue(response.status_code==200)

        这里面需要注意的就是,测试Rest API时需要在client的post方法中显示的指定传送的数据类型content_type为'application/json',而且传送的data需要用json.dumps()方法将数据格式化成json的格式。assertTrue中还是检验响应的status_code,如果文章创建成功,服务端会返回200的状态码,所以在这里同200进行了比较。

三、使用selenium进行自动化测试

        Selenium可以自动启动浏览器,模拟用户点击浏览器的连接,selenium的安装方法如下:

pip install selenium

        我们进行测试的思路时,利用后台线程启动服务端,然后在主线程中利用selenium自动操作firefox进行自动化的测试。在使用selenium之前,我们先要定义一个路由可以关闭服务端的运行,以使在测试结束后服务端自动结束运行。

@main.route('/shutdown')defserv_shutdown():   shutdown=request.environ.get('werkzeug.server.shutdown')    shutdown()    return 'shuting down'

         werkzeug服务器提供了一个shutdown函数供外部使用,在上述的视图函数中,我们获取到了这个函数,并进行调用,这样通过访问http://localhost:5000/shutdown这个url我们就可以实现关闭服务端。

        接下来是使用selenium进行自动化测试的代码:

#coding:utf-8import unittestfrom flaskimport current_app,url_for,jsonfrom app importcreate_app,dbfrom seleniumimport webdriver classSeleniumTestCase(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()            db.create_all()           threading.Thread(target=cls.app.run).start()    @classmethod    def tearDownClass(cls):        if cls.client:           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('Firefox isinvailable')       def tearDown(self):        pass       def test_home_page(self):       self.client.get('http://localhost:5000/')        self.assertTrue(re.search('Home',self.client.page_source))

        通过修饰器classmethod定义了setUpClass()和tearDownClass()两个成员函数,分别在该类中的所有的测试用例执行之前和之后运行,而setUp()和tearDown()是在每个测试用例执行前后都运行。在setUpClass()中,通过webdriver.Firefox()获取到了Firefox()浏览器对象,并在threading.Thread(target=cls.app.run).start()中在后台线程运行服务端,然后在测试用例test_home_page中我们通过这个浏览器对象访问'http://localhost:5000/',并利用正则表达式判断返回的结果中是否包含'Home'字符串。在所有的测试完成之后,在tearDownClass()中访问'http://localhost:5000/shutdown'从而完成了服务端的关闭。至此,一个完整的selenium测试流程完成。

        Selenium的强大在于,它可以操作浏览器实现自动化的测试,仿佛就像有人在浏览器上点击一样,它创建的Firefox客户端对象提供了很多方法可以在Web界面找到相关的元素并进行后续的操作。比如find_element_by_link_text()方法,可以根据超链接的名称找到该链接,并在调用其Click()方法模拟点击超链接;find_element_by_name()方法根据根据名字找到对应的字段,然后可以使用期send_keys()的方法在各个字段中填入值。



Github位置:
https://github.com/HymanLiuTS/flaskTs
克隆本项目:
Git clone Git@github.com:HymanLiuTS/flaskTs.Git
获取本文源代码:
Git checkout FL40

    

0 0
原创粉丝点击