<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          測試工具coverage的高階使用

          共 11631字,需瀏覽 24分鐘

           ·

          2023-08-22 08:26

          ??在文章Python之單元測試使用的一點心得中,筆者介紹了自己在使用Python測試工具coverge的一點心得,包括:

          1. 使用coverage模塊計算代碼測試覆蓋率

          2. 使用coverage api計算代碼測試覆蓋率

          3. coverage配置文件的使用

          4. coverage badge的生成

          ??本文在此基礎(chǔ)上,將會介紹coverage的高階使用,包括:

          • Flask API測試

          • coverage多文件測試

          • coverage的Gitlab CI/CD集成

          • coverage badge生成

          ??本文中使用coverage的版本均為7.3.0。

          Flask API測試

          ??在unittest測試框架如果對Flask API進(jìn)行測試時使用HTTP請求,那么將無法得到代碼覆蓋率。
          ??我們有如下的示例Flask服務(wù):

          # -*- coding: utf-8 -*-
          from flask import Flask

          app = Flask(__name__)


          @app.route('/')
          def index():
              return "Hello index"


          @app.route('/test')
          def test():
              return "Hello test"


          if __name__ == '__main__':
              app.run(host="0.0.0.0", port=5000, debug=True)

          ??正確的測試代碼如下:

          # -*- coding: utf-8 -*-
          import unittest

          from flask_app import app


          class AppTestCase(unittest.TestCase):
              def setUp(self):
                  self.ctx = app.app_context()
                  self.ctx.push()
                  self.client = app.test_client()

              def tearDown(self):
                  self.ctx.pop()

              def test_case1(self):
                  response = self.client.get("/")
                  self.assertEqual(response.status_code, 200)
                  self.assertEqual(response.text, "Hello index")

              def test_case2(self):
                  response = self.client.get("/test")
                  self.assertEqual(response.status_code, 200)
                  self.assertEqual(response.text, "Hello test")


          if __name__ == "__main__":
              suite = unittest.TestSuite()
              suite.addTest(AppTestCase('test_case1'))
              suite.addTest(AppTestCase('test_case2'))
              run = unittest.TextTestRunner()
              run.run(suite)

          coverage多文件測試

          ??我們有如下的實現(xiàn)兩個變量相加的代碼(func_add.py):

          # -*- coding: utf-8 -*-
          def add(a, b):
              if isinstance(a, str) and isinstance(b, str):
                  return a + '+' + b
              elif isinstance(a, list) and isinstance(b, list):
                  return a + b
              elif isinstance(a, (int, float)) and isinstance(b, (int, float)):
                  return a + b
              else:
                  return None

          ??兩個測試文件test_func_add1.pytest_func_add2.py,內(nèi)容如下:

          # -*- coding: utf-8 -*-
          import unittest

          from func_add import add


          class TestAdd(unittest.TestCase):
              def setUp(self):
                  pass

              def test_add_case1(self):
                  a = "Hello"
                  b = "World"
                  res = add(a, b)
                  print(res)
                  self.assertEqual(res, "Hello+World")

              def test_add_case2(self):
                  a = 1
                  b = 2
                  res = add(a, b)
                  print(res)
                  self.assertEqual(res, 3)


          if __name__ == '__main__':

              # 部分用例測試
              # 構(gòu)造一個容器用來存放我們的測試用例
              suite = unittest.TestSuite()
              # 添加類中的測試用例
              suite.addTest(TestAdd('test_add_case1'))
              suite.addTest(TestAdd('test_add_case2'))
              run = unittest.TextTestRunner()
              run.run(suite)
          # -*- coding: utf-8 -*-
          import unittest

          from func_add import add


          class TestAdd(unittest.TestCase):
              def setUp(self):
                  pass

              def test_add_case3(self):
                  a = [12]
                  b = [3]
                  res = add(a, b)
                  print(res)
                  self.assertEqual(res, [123])

              def test_add_case4(self):
                  a = 2
                  b = "3"
                  res = add(a, b)
                  print(None)
                  self.assertEqual(res, None)


          if __name__ == '__main__':

              # 部分用例測試
              # 構(gòu)造一個容器用來存放我們的測試用例
              suite = unittest.TestSuite()
              # 添加類中的測試用例
              suite.addTest(TestAdd('test_add_case3'))
              suite.addTest(TestAdd('test_add_case4'))
              run = unittest.TextTestRunner()
              run.run(suite)

          使用命令進(jìn)行測試:

          coverage run test_func_add1.py
          coverage run test_func_add2.py
          coverage report

          生成的代碼測試覆蓋率如下:

          Name          Stmts   Miss  Cover
          ---------------------------------
          func_add.py       8      2    75%
          ---------------------------------
          TOTAL             8      2    75%

          這是不符合我們預(yù)期的,因為在這兩個測試文件中我們對所有的代碼都進(jìn)行了測試,理論上測試覆蓋率應(yīng)該為100%,之所以這樣,是因為coverage run命令運行時每一次都會覆蓋掉之前的測試。正確的測試命令(以文件追加的形式)如下:

          coverage run test_func_add1.py
          coverage run --append test_func_add2.py
          coverage report

          此時代碼覆蓋率如下:

          Name          Stmts   Miss  Cover
          ---------------------------------
          func_add.py       8      0   100%
          ---------------------------------
          TOTAL             8      0   100%

          coverage的Gitlab CI/CD集成

          ??在文章Gitlab CI/CD入門(一)Python項目的CI演示中,筆者介紹了Gitlab CI/CD的入門。在此基礎(chǔ)上,我們將集成coverage。
          ??首先我們的test目錄如下:

          .
          ├── __init__.py
          ├── func_add.py
          └── test_func_add.py

          func_add.py為實現(xiàn)兩個變量相加的代碼,如前述。test_func_add.py為測試代碼,如下:

          # -*- coding: utf-8 -*-
          import unittest

          from func_add import add


          class TestAdd(unittest.TestCase):
              def setUp(self):
                  pass

              def test_add_case1(self):
                  a = "Hello"
                  b = "World"
                  res = add(a, b)
                  print(res)
                  self.assertEqual(res, "Hello+World")

              def test_add_case2(self):
                  a = 1
                  b = 2
                  res = add(a, b)
                  print(res)
                  self.assertEqual(res, 3)

              def test_add_case3(self):
                  a = [12]
                  b = [3]
                  res = add(a, b)
                  print(res)
                  self.assertEqual(res, [123])

              def test_add_case4(self):
                  a = 2
                  b = "3"
                  res = add(a, b)
                  print(None)
                  self.assertEqual(res, None)


          if __name__ == '__main__':

              # 部分用例測試
              # 構(gòu)造一個容器用來存放我們的測試用例
              suite = unittest.TestSuite()
              # 添加類中的測試用例
              suite.addTest(TestAdd('test_add_case1'))
              suite.addTest(TestAdd('test_add_case2'))
              suite.addTest(TestAdd('test_add_case3'))
              suite.addTest(TestAdd('test_add_case4'))
              run = unittest.TextTestRunner()
              run.run(suite)

          CI/CD依賴.gitlab-ci.yml,配置如下:

          stages:
            - build
            - unittest

          build-job:
            stage: build
            script:
              - echo `date`
              - echo "Hello, $GITLAB_USER_LOGIN!"
              - echo "This job deploys something from the $CI_COMMIT_BRANCH branch."

          unit_test_job:
            stage: unittest
            image: python:3.9-alpine3.17
            script:
              - pip3 install coverage==7.3.0
              - coverage run test/test_func_add.py
              - coverage report
            coverage: '/TOTAL.*\s+(\d+%)$/'

          ??運行CI/CD,結(jié)果如下圖:

          31b57482f68e0be4ed4ff9900161e02d.webpunittest_job運行結(jié)果
          ??在Gitlab項目中的Settings -> CI/CD -> General pipelines中點擊Expand,會顯示CI/CD已內(nèi)置Pipeline status, Coverage report, Latest release,其中Coverage repor如下圖:
          320a4daf5bb8be8414709abf0d9f10bc.webpCoverage report
          ??最后我們要在項目中加入coverage badge(徽章),在Gitlab項目中的Settings -> General -> Badge中點擊Expand,再點擊Add badge,coverage徽章的配置如下:
          df684e98a60b82a2f4222905545fa035.webpAdd badge
          本項目中只有main分支,因此不需要設(shè)置變量,實際在使用過程中,需要配置變量如default_branch等。
          ??以上配置完畢后,項目徽章顯示如下: 97053db9165293c1cc54f545678cb8e4.webp成功加入徽章!
          ??以上配置過程已開源,項目網(wǎng)址為:https://gitlab.com/jclian91/gitlab_ci_test 。

          coverage badge生成

          ??coverage badge生成方式分為靜態(tài)和動態(tài)。
          ??動態(tài)的話,可使用coverage-badge或者genbadge模塊。
          ??靜態(tài)的話,可使用網(wǎng)站:https://shields.io/badges/static-badge .
          ??比如我們生成編程語言的徽章,如下圖:

          6baeb176e71342fcd22770feeee1e95d.webp示例徽章生成
          之后我們就可以用該網(wǎng)址訪問徽章了。

          總結(jié)

          ??本文介紹了測試工具coverage的高階使用,希望能對讀者有所啟發(fā)~

          瀏覽 65
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  玖玖精品视频一区二区三区四区 | 黄色动漫成人视频在线观看 | 人人爱人人操 | AV在线亚洲天堂 | 国产一级性爱片 |