python3+selenium 自动化测试框架初探

python3+selenium 自动化测试框架初探

首先,对于软件测试行业的人员技术发展。
我的个人看法是:不能一味的追求自动化测试、性能测试、压力测试的技术,而忽略了功能测试 !
不过对于大公司肯定是各司其职效率上肯定会有很大提升。
功能测试虽然是入门门槛低,但是其中涉及到的用例设计是需要很长一个时间的经验积累,并且需要的知识广度是非常之广的。希望用人单位不要忽视这个问题~
自动化测试能节省更多的回归时间,但对于小型企业,测试人员少,项目更新快,改动大的前期项目,建议不要轻易窥探。

背景

为了更好的发展自身的测试技能,应对测试行业以及互联网行业的迭代变化。自学python以及自动化测试。
虽然在2017年已经开始接触了selenium,期间是断断续续执行自动化测试,因为还有其他测试任务,琐事要执行…
前期建议大家能够学习python基本语法(python基础教程)

任务

搭建自动化测试框架,并能有效方便的进行测试,维护成本也要考虑其中。

过程

我的自动化框架可能不成熟,因为是自学的。请多包涵。也请大佬指导~ 共勉!进步!

结构目录

目录结构

  • common

包含:基本的公共方法类,比如HTML报告、Log处理、发送邮件、基本页面对象等

其中pageObject里面是对各个测试系统操作页面的一个封装,以后用例的方法直接继承即可。可多次调用,维护起来比较方便。

  • conf

基本的系统参数配置信息,可以包含url,正确用户的信息,简单日志级别,某些输出位置,邮件信息等

  • data

对于数据驱动或者其他测试用例中需要测试的数据,之后测试用例流程不变,可以直接在文档中进行测试数据的修改。暂时采用excel。也可以采用csv,xml等等方法

  • log

日志输出,暂时包括了 log输出,htmlreport输出以及img的保存。

  • test

其中包含testcase以及testsuite两个模块

  1. testcase 负责编写测试用例如果某个功能有多个py文件编写可以再新建一个目录。
  2. testsuite 就是测试套件,可以按需求进行选择需要的测试项(包含测试用例以及测试类)
注意:使用ddt则不可以再使用addTest方式单独添加测试用例了。  

代码部分

- common中的BasePage

(去掉了帮助信息)

class BasePage():
    global logg
    logg = LogHandler().logger
    def __init__(self,driver,url=None):
        self.wd = driver
        self.wd.implicitly_wait(5)
        self.actions = ActionChains(self.wd)
        if url :
            self.url = url
        else:
            self.url = self.server_url_conf()
    #浏览器行为的一些方法
    def get_conf_url(self):
		self.wd.get(self.url)
        self.wd.maximize_window()
        logg.debug("enter conf_url : " + str(self.url))
    def brower_close(self):
        return self.wd.close()
    def brower_quit_all(self):
        return self.wd.quit()
... 	下面还有刷新,前进后退等

    #定位 这里通过 By.xx 方法
    def find_web_element(self,*loc):
        #self.wd.find_element(*loc)
        return self.wd.find_element(*loc)

    #元素操作
    def type_text(self,loc,text):
        return  self.wd.find_element(*loc).send_keys(text)
        
    def clear_text(self,*loc):
        return self.wd.find_element(*loc).clear()
        
    def submit_func(self,*loc):
        return self.wd.find_element(*loc).submit()

    def click_btn(self,*loc):
        return self.wd.find_element(*loc).click()
        
	#鼠标相关
    def mouse_move_to_element(self,*loc):
        elem = self.find_web_element(*loc)
        self.actions.move_to_element(elem).perform()
... 下面还有点击,双击,右击的一些方法       

    #获取信息行为
    def get_web_url(self):
        return self.wd.current_url
    def get_title(self):
        return  self.wd.title
    def get_element_text(self,*loc):
        return self.find_web_element(*loc).text

    #元素是否存在 是 True
    def check_element_isexist(self,loc):
        isexist = False
        try:
            EC.presence_of_element_located(loc)(self.wd)
            isexist = True
        except Exception as e:
            isexist = False
            logg.debug(' isexist or not  :',exc_info = True)
        return isexist
    def check_element_has_text(self,loc,text):
		pass  #省略
  
    def check_element_isdisplayed(self,*loc):
     	pass  #省略
     	
    #生成图
    def __inser_img(self,passorfailed,imgname):
        time_loc = time.strftime("%m%d_%H%M%S",time.localtime())
        file_path = os.path.abspath(__file__)
        file_path = os.path.join(file_path+"/../../log/%s_%s.png" %(imgname,time_loc))
        self.wd.get_screenshot_as_file(file_path)
        logg.debug('insert_%s_img %s ' %(passorfailed,(file_path)))

    def insert_error_img(self,imgname):
        self.__inser_img("error",imgname)
    def insert_success_img(self,imgname):
        self.__inser_img("success",imgname)
    def insert_debug_img(self,imgname):
        self.__inser_img("debug",imgname)


    def server_url_conf(self):
        self.host = readconfig.ReadConfig().getserver('host')
        self.port = readconfig.ReadConfig().getserver('port')
        urlvalue = self.host + ":" + self.port

        return urlvalue

if __name__ == '__main__':
    test = BasePage(webdriver.Chrome())
    test.get_conf_url()
  • common中登录页的页面对象
    包含了页面的一些方法比如
    输入用户名,输入密码,点击登录

  • test中的 logintestcase
    则直接使用 登录页面对象的 输入用户名,输入密码,点击登录即可
    后期维护,如果元素变动,则只需要修改页面对象代码而对用例则无需修正

loginbasepage

class AioLogin(BasePage):
    global logg
    logg = LogHandler().getlog()
    username_loc = (By.NAME, "username")
    password_loc = (By.CSS_SELECTOR, "input[type='password']")
    login_loc = (By.CLASS_NAME, "login-btn")
    login_loc_oem = (By.ID,"submit")
    check_login_loc = (By.CLASS_NAME,"error-tip")
    elements = [username_loc,password_loc,login_loc,check_login_loc]
    log_menu = (By.CSS_SELECTOR,"[name='log']")
    logg.debug(elements)
    
    def set_username(self,username):
        self.clear_text(*self.username_loc)   #直接使用BasePage的方法
        self.type_text(self.username_loc,username)
        logg.info('Enter username: ' + username)
        sleep(0.1)
... 其他

logintest
这里使用了ddt数据驱动方法
from ddt import data,ddt,unpack

@ddt
class TestLogin(unittest.TestCase):
    global logg
    logg = LogHandler().getlog()
    
    @classmethod        #该类方法,执行中只会启动一次。区别于setUp的 每个用例都执行一遍
    def setUpClass(cls):
        cls.test = aiologinpage.AioLogin(webdriver.Chrome())
        cls.test.get_conf_url()
       # print('start TestSearch')
       
    @classmethod
    def tearDownClass(cls):
        # TestLogin().logg.info("brower quit")
        TestLogin().test.brower_close()
        pass
    logindata = ReadExcel().getValue('login')
    
    @data(*logindata)
    @unpack        #当有多组数据时,需要unpack
    def testcase2(self,username,passwd,result):
        logg.info(username+" " + passwd +" " +str(result))
        self.test.set_username(username)   #用例直接使用登录页面对象,后期除了修改测试用例,否则无需变动
        self.test.set_password(passwd)
        self.test.type_login_btn()
        
        # 断言登录结果和预期结果是否一致
        self.assertTrue(self.test.check_login_result(result),
                        msg="\r  login_test fail \r  username :%s \r    passwd : %s " %(username,passwd))

if __name__ == '__main__':
    unittest.main()

其他页面
比如我有个 创建设备分组的页面
我必须要先登录才可以执行下面的操作
此时,可以从conf中获取成功登录的用户名和密码,把correct_login方法写在登录页面对象中。

def correct_login(self):
        self.get_conf_url()
        self.userpasswd = self.correct_userpasswd_conf()
        self.set_username(self.userpasswd[0])
        self.set_password(self.userpasswd[1])
        self.type_login_btn()  
        

之后,其他页面初始化时候直接调用这个correct_login即可登录

  • 测试套件添加方法

TestSuite方法
#添加一个类
st1 = unittest.makeSuite(TestLogin)
#单独添加多个用例
st = unittest.TestSuite(map(TestClassName,[‘testcase1’,‘testcase2’]))
st = unittest.TestSuite(TestClaseeName(‘testcase1’))

#添加一个或者多个测试用例
st2 = unittest.TestSuite()
st2.addTests(map(TestCaseClassName,[‘testcase2’,‘testcase1’]))
st2.addTest(TestCaseClassName(‘testcase1’))
#添加一个类
st2.addTest(unittest.makeSuite(TestClassName))

TestLoader 方法
discovery 发现脚本
st = unittest.TestLoader().discovery(“dir_path”,pattern=“a*.py”)

#loadTestFromTestCase 加载 测试类
st1 = unittest.TestLoader().loadTestsFromTestCase(TestLoginCheck)
st2 = unittest.TestLoader().loadTestsFromTestCase(TestLogin)
stt = unittest.TestSuite()
stt.addTests([st1,st2])

其他说明

这个脚本还有很多需要优化的地方,算是自己的一个试探入门文吧。后期根据项目需求再多多巩固。
大家可以一起讨论哦,想学学大厂的测试思维~ 嘻嘻
加油

  • 3
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值