幾個(gè)使用UnitTest創(chuàng)建自動(dòng)化測(cè)試框架的小想法

在使用當(dāng)使用Unittest進(jìn)行自動(dòng)化測(cè)試框架構(gòu)建時(shí),會(huì)根據(jù)測(cè)試的種類和需要對(duì)測(cè)試用的class進(jìn)行封裝。所以,如何進(jìn)行封轉(zhuǎn)更為用戶友好很重要,下面以u(píng)rl接口測(cè)試為需求,提出一些想法。

  • 動(dòng)態(tài)創(chuàng)建繼承于tasecase的類。
import unittest
import requests
from types import MethodType 

class TestFactroy():

    def run_all_cases(self):
        unittest.main()

    def url_test(self, url, method='get', status_code=200):
        def do_set_up():
            def setUp(self):
                pass
            return setUp

        def extra_test(self, resp, status_code):
            self.assertEqual(resp.status_code, status_code, 'url test status_code fail')
            return

        def do_test_case(url, method, status_code):
            def test_case(self):
                resp = requests.request(url=url,method=method)
                self.extra_test(resp, status_code)
            return test_case

        def add_url_case(cls, url, method='get', status_code=200):
            def one_test_case(self):
                resp = requests.request(url=url,method=method)
                self.assertEqual(resp.status_code, status_code, 'url test status_code fail')
            setattr(cls, "test_case_%s" % cls.case_num, one_test_case)
            cls.case_num += 1
            return

        class TestUrlCase(unittest.TestCase):
            pass
        TestUrlCase.setUp = do_set_up()
        TestUrlCase.test_case = do_test_case(url, method, status_code)
        TestUrlCase.case_num = 1
        TestUrlCase.extra_test= extra_test
        TestUrlCase.add_url_case = MethodType(add_url_case, TestUrlCase)
        return TestUrlCase


if __name__ == "__main__":
    test_factory = TestFactroy()
    test_case_1 = test_factory.url_test("http://www.acfun.cn")
    test_case_2 = test_factory.url_test("http://www.bilibili.com")
    test_case_1.add_url_case("http://www.tucao.tv")
    test_factory.run_all_cases()
  • 構(gòu)建一個(gè)繼承于unittest.TestCase的類用于接口測(cè)試。使用時(shí)繼承該類。
import unittest
import requests
from enum import Enum


class UA(Enum):
    Opera = "User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36 OPR/46.0.2597.39"
    Firefox = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0"
    chrome = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36"


def url_required(func):
    def _url_required(self, *args, **kwargs):
        if self.url is None:
            raise(UrlRequiredException())
        else:
            return func(self, *args, **kwargs)
    return _url_required


class UrlRequiredException(Exception):
    def __init__(self):
        Exception.__init__(self, 'url cannot be None')


class RequestException(Exception):
    def __init__(self, e, http_options):
        msg = "http request failed\n%s\n%s" % \
            (('\n').join([(': ').join(item) for item in http_options.items()]), \
             e.message)
        Exception.__init__(self, msg)

class UrlTestModule(object):

    method = "get"
    url = None
    authentication = False
    encode =False
    user_agent = None
    headers = {}
    params = {}
    data = ""
    ua = None
    response = None
    
    clear_response = False
    
    assert_status_code = 200
    
    exception_list = []
    
    @staticmethod
    def run_test_case():
        unittest.main()
    
    @classmethod
    def set_response(cls, response):
        cls.response = response
    
    @classmethod
    def remove_response(cls):
        cls.response = None
    
    @classmethod
    def get_response(cls):
        return cls.response

    def setUp(self):
        self._initialization()
        self._do_request()
        
    @url_required
    def _do_request(self):
        if self.response is not None:
            return
        http_options = {
            'method': self.method,
            'url': self.url,
            'params': self.params,
            'data': self.data
        }
        headers = {}
        if self.ua:
            headers.update({'User-Agent':self.ua})
        if self.authentication:
            headers.update(self._auth())
        headers.update(self.headers)
        http_options['headers'] = headers
        if self.encode:
            http_options = self._encode(http_options)
        try:
            response = requests.request(**http_options)
            self.set_response(response)
        except Exception as e:
            raise( RequestException(e, http_options))

    @url_required
    def tearDown(self):
        self._finish()
        self._clear_response()
    
    def _initialization(self):
        if hasattr(self,'initialization'):
            m = getattr(self,'initialization')
            if hasattr(m, '__call__'):
                m()
        return
        
    def _finish(self):
        if hasattr(self,'finish'):
            m = getattr(self,'finish')
            if hasattr(m, '__call__'):
                m()
        return
    
    def _clear_response(self):
        if self.assert_status_code:
            self.remove_response()
    
    def _auth(self, *args, **kwargs):
        return {}
        
    def _encode(self, http_options):
        return http_options
    
    def _assert_response_status_code(self):
        if self.assert_status_code:
            if not isinstance(self.assert_status_code, int):
                status_code = 200
            else:
                status_code = self.assert_status_code
            self.assertEqual(self.response.status_code, status_code)

    def _raiseExceptions(self):
        if len(self.exception_list):
            raise(Exception(('\n').join([e.message for e in self.exception_list])))
    
    @url_required   
    def test_script(self):
        self._assert_response_status_code()
        assert_list = [attr for attr in dir(self) \
             if ('check' == attr[:5]) and hasattr(getattr(self, attr),'__call__')]
        assert_list.sort() 
        for m in assert_list:
            try:
                getattr(self, m)()
            except Exception as e:
                self.exception_list.append(e)
        self._raiseExceptions()
                
            
class TestFactory(object):
    @property
    def UrlTest(self):
        class UrlTestClass(UrlTestModule, unittest.TestCase):pass
        return UrlTestClass

    def run_test_case(self):
        unittest.main()
        

test_factory = TestFactory()


if __name__ == "__main__":
    class TestCase(test_factory.UrlTest):

        url= "http://www.bilibili.com"

        def initialization(self):
            print("initialization start")

        def check_if_the_site_is_BiliBili(self):
            print('check if the site is BiliBili start')
            self.assertRegex(self.response.content, "嗶哩嗶哩".encode('utf-8'))
            
        def check_if_return_html(self):
            print('check if return html start')
            self.assertEqual(self.response.headers.get('Content-Type'), "text/html")

        def finish(self):
            print('finish start')
    
    test_factory.run_test_case()

一些問題

  • 當(dāng)使用unittest.main()運(yùn)行所有的 test cases 時(shí), 會(huì)將所有class繼承于unittest.TestCase的類全數(shù)測(cè)試一遍。使用繼承類的方式生成測(cè)試用例,應(yīng)采用方法生成的方式,避免繼承時(shí)被再次調(diào)用。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容