接口測試 開源~自研接口測試平臺 Django2+Bootstrap3+Unittest

轉載  https://testerhome.com/topics/15657

 

python3.6.4 Django2.0 框架

文檔更新

第一篇:https://testerhome.com/topics/13269 
第二篇:https://testerhome.com/topics/14801
第三篇:https://testerhome.com/topics/15352

版本更新

V1.8 引入mongo對於返回結果值存儲,實現接口依賴功能。
V1.7 優化斷言模塊,採用json方法多層級遍歷,增加斷言比較方法
V 1.6 修復環境配置取消必須綁定端口號,接口測試取消必須連接數據庫,優化定時模塊
V 1.5 實現可選擇郵箱發送
V 1.4 實現日誌模塊和報告數據分析模塊
V 1.3 引入任務概念,實現定時模塊(雙環境)的控制
V 1.2 定義生成腳本規則,實現自動生成腳本,動態引入sql,增加unittest的失敗重跑機制
V 1.1 實現配置化管理,環境配置,數據庫配置,郵箱配置
V 1.0 實現用例步驟維護,實現3種http調用,引入django和unittest

數據庫結構

 

登錄模塊

 

項目和模塊頁面

 

 

用例

用例中的用例名需要設置成英文,api不需要帶上http://。
如果是狀態爲false的用例不支持任務添加,支持用例新增,修改,以及批量升級

 

 

步驟

一個用例對應多個步驟,步驟名需要使用中文,目前可以使用前3種方式請求。
信息頭、參數、斷言都可以使用變量,變量格式爲${}
支持步驟新增,修改,以及批量升級

 

 

斷言

斷言例如可以採用['result']['data'][0]['id']這樣的方式作爲對返回值的獲取,可採用的方法也有多種
當按鈕關閉時表示不使用斷言

 

接口依賴

一個步驟可以去依賴另一個步驟,可以多層級依賴,也可以選擇依賴多個或被多個依賴,需要配置依賴那個步驟,依賴步驟返回值的路徑(跟斷言取值方法一致),以及變量名
當按鈕關閉時表示不使用接口依賴

 

配置頁面

 

 

 

生成腳本

在用例頁面勾選對應的用例去生成任務,任務名設置爲英文,對應的執行結果task目錄下生成以任務名命名的文件夾,文件夾下testcase目錄以及report目錄,前者存放生成的腳本,後者生成日誌和郵件報告

定時任務

如果選擇單次執行,那麼關閉定時任務就可以。定時任務input框可以點擊進入,配置方法採用crontab。狀態是配置了定時時間之後纔去判斷狀態的,false表示不啓動。

 

報告分析

5次內執行結果,失敗數,斷言失敗數,成功數等等,也會將反饋和今日錯誤反饋給出。

 


這裏有個地方需要配置,我默認用的message,如果你接口第一層返回值定義的是其他信息時,需要修改make_testcase.py的兩個地方

安裝步驟

依賴庫安裝:
Django 2.0.2
django-bootstrap3
pymysql,pymssql,DBUtils
Requests
bs4
apscheduler
pymongo
兩個環境的前提,修改uniitest源碼:
1.新增unittest的case.py文件中TestCase類加入一個方法

#自主添加的方法
    def chooseAssertWay(self,response,assertway,assert_response):
        if assertway=="assertEqual":
            self.assertEqual(response,assert_response)
        elif assertway=="assertNotEqual":
            self.assertNotEqual(response,assert_response)
        elif assertway=="assertRegexpMatches":
            self.assertRegexpMatches(response,assert_response)
        elif assertway=="assertNotRegexpMatches":
            self.assertNotRegexpMatches(response,assert_response)
        elif assertway=="assertGreater":
            self.assertGreater(response,assert_response)
        elif assertway=="assertGreaterEqual":
            self.assertGreaterEqual(response,assert_response)
        elif assertway=="assertLess":
            self.assertLess(response,assert_response)
        elif assertway=="assertLessEqual":
            self.assertLessEqual(response,assert_response)
        elif assertway=="assertIn":
            self.assertIn(response,assert_response)
        elif assertway=="assertNotIn":
            self.assertNotIn(response,assert_response)

2.更改unittest的loader.py文件中TestLoader類一個方法discover

def discover(self, start_dir,case_names_weights, pattern='test*.py', top_level_dir=None):
    """Find and return all test modules from the specified start
    directory, recursing into subdirectories to find them and return all
    tests found within them. Only test files that match the pattern will
    be loaded. (Using shell style pattern matching.)

    All test modules must be importable from the top level of the project.
    If the start directory is not the top level directory then the top
    level directory must be specified separately.

    If a test package name (directory with '__init__.py') matches the
    pattern then the package will be checked for a 'load_tests' function. If
    this exists then it will be called with (loader, tests, pattern) unless
    the package has already had load_tests called from the same discovery
    invocation, in which case the package module object is not scanned for
    tests - this ensures that when a package uses discover to further
    discover child tests that infinite recursion does not happen.

    If load_tests exists then discovery does *not* recurse into the package,
    load_tests is responsible for loading all tests in the package.

    The pattern is deliberately not stored as a loader attribute so that
    packages can continue discovery themselves. top_level_dir is stored so
    load_tests does not need to pass this argument in to loader.discover().

    Paths are sorted before being imported to ensure reproducible execution
    order even on filesystems with non-alphabetical ordering like ext3/4.
    """
    set_implicit_top = False
    if top_level_dir is None and self._top_level_dir is not None:
        # make top_level_dir optional if called from load_tests in a package
        top_level_dir = self._top_level_dir
    elif top_level_dir is None:
        set_implicit_top = True
        top_level_dir = start_dir

    top_level_dir = os.path.abspath(top_level_dir)

    if not top_level_dir in sys.path:
        # all test modules must be importable from the top level directory
        # should we *unconditionally* put the start directory in first
        # in sys.path to minimise likelihood of conflicts between installed
        # modules and development versions?
        sys.path.insert(0, top_level_dir)
    self._top_level_dir = top_level_dir

    is_not_importable = False
    is_namespace = False
    tests = []
    if os.path.isdir(os.path.abspath(start_dir)):
        start_dir = os.path.abspath(start_dir)
        if start_dir != top_level_dir:
            is_not_importable = not os.path.isfile(os.path.join(start_dir, '__init__.py'))
    else:
        # support for discovery from dotted module names
        try:
            __import__(start_dir)
        except ImportError:
            is_not_importable = True
        else:
            the_module = sys.modules[start_dir]
            top_part = start_dir.split('.')[0]
            try:
                start_dir = os.path.abspath(
                   os.path.dirname((the_module.__file__)))
            except AttributeError:
                # look for namespace packages
                try:
                    spec = the_module.__spec__
                except AttributeError:
                    spec = None

                if spec and spec.loader is None:
                    if spec.submodule_search_locations is not None:
                        is_namespace = True

                        for path in the_module.__path__:
                            if (not set_implicit_top and
                                not path.startswith(top_level_dir)):
                                continue
                            self._top_level_dir = \
                                (path.split(the_module.__name__
                                     .replace(".", os.path.sep))[0])
                            tests.extend(self._find_tests(path,
                                                          pattern,
                                                          namespace=True))
                elif the_module.__name__ in sys.builtin_module_names:
                    # builtin module
                    raise TypeError('Can not use builtin modules '
                                    'as dotted module names') from None
                else:
                    raise TypeError(
                        'don\'t know how to discover from {!r}'
                        .format(the_module)) from None

            if set_implicit_top:
                if not is_namespace:
                    self._top_level_dir = \
                       self._get_directory_containing_module(top_part)
                    sys.path.remove(top_level_dir)
                else:
                    sys.path.remove(top_level_dir)

    if is_not_importable:
        raise ImportError('Start directory is not importable: %r' % start_dir)

    if not is_namespace:
        tests = list(self._find_tests(start_dir, pattern))
    #print (tests)
    #正則提取用例名,排序
    regex=re.compile(r'testcase\.(.+?)\.')
    for i in range(0, len(tests) - 1):
        for j in range(2, len(tests) - 1 - i):
            try:
                if case_names_weights[regex.findall(str(tests[j]))[0]] > case_names_weights[regex.findall(str(tests[j+1]))[0]]:
                    c = tests[j]
                    tests[j] = tests[j + 1]
                    tests[j + 1] = c
            except:
                # 方法爲空時不變
                pass
    return self.suiteClass(tests)

windows部署:
1.根據testhome安裝python3.6和對應的python庫(還需要添加HTMLTestRunner.py)
2.選擇一個mysql數據庫新建一個request數據庫作爲測試庫,在django的setting.py文件的86行配置數據庫的信息(ip,端口,數據庫名稱,用戶名,密碼)
3.選擇一個mongo數據庫作爲測試庫,在django的setting.py文件的103行配置數據庫的信息(ip,端口,集合,一張表)
4.進入到項目根目錄,數據庫遷移:python manage.py makemigrations在request應用下的migrations目錄下創建了一個 0001_initial.py 文件,執行python manage.py migrate,執行完成庫表生成
5.創建第一個用戶python manage.py createsuperuser
6.django的setting.py文件的28行,因爲是本地啓動保持ALLOWED_HOSTS = []就好了
7.配置編譯器啓動方式,選擇django server啓動,HOST填寫127.0.0.1,port填寫8000,運行
8.訪問127.0.0.1:8000,能訪問到就ok了

linux部署
1.根據testhome安裝python3.6和對應的python庫(還需要添加HTMLTestRunner.py)
2.把源代碼放到linux下(我創建了pj目錄,項目放在/home/pj下)
3.選擇一個mysql數據庫新建一個request數據庫作爲測試庫,在django的setting.py文件的86行配置數據庫的信息(ip,端口,數據庫名稱,用戶名,密碼)
4.選擇一個mongo數據庫作爲測試庫,在django的setting.py文件的103行配置數據庫的信息(ip,端口,集合,一張表)
5.進入到項目根目錄,數據庫遷移:python manage.py makemigrations在request應用下的migrations目錄下創建了一個 0001_initial.py 文件,執行python manage.py migrate,執行完成庫表生成
6.創建第一個用戶python manage.py createsuperuser,之後的用戶登錄http://192.168.100.158:8000/admin/去創建用戶組和用戶以及分配權限
7.在pj目錄下創建logs目錄,下面創建request.log文件存放項目日誌文件
8.在django的setting.py文件的28行,添加自己linux的ip(我的是ALLOWED_HOSTS = ['192.168.100.158'])
9.把啓動shell和關閉shell放在根目錄下(requestnew),sh start.sh,項目就啓動了;項目關閉則執行sh shutdown.sh
10.如果目錄結構想要有所調整或者啓動端口(默認8000)有所調整,需要修改啓動和關閉文件
11.其他機子能訪問到(配置的ip:8000)就成功了。

老用戶部署會涉及到數據庫遷移的問題,建議百度學習,將老項目requestnew\request\migrations除了init.py都刪除先數據庫遷移,然後將這個新生成的0001_initial.py文件放到新工程下的同目錄下的地方在對新工程做數據庫遷移。

github代碼暫時停更,遇到了上傳不了代碼的問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章