软件测试之 Unittest 实现多账号切换登录及使用Page Object 设计模式对代码进行分离

使用 Jmeter 实现对云服务器进行 3000+ 并发压测

对 Unittest 和 Page Object 设计模式进行简单的了解:

Unitest 是 Python 自带的一个单元测试框架,它可以用来做自动化测试框架的用例组织执行框架

  • 优点:为我们提供用例组织与执行方法、提供比较方法、提供丰富的日志和清晰的报告等

Unitest 操作的大致流程:

  1. TestCase 就是大家常说的测试用例
  2. 然后由TestLoader来加载TestCase到TestSuite(就是过个测试用例集合在一起)
  3. 最后由TextTestRunner来运行TestSuite,并把运行的结果保存到TextTestResult中
  4. 通过命令行或者 unittest.main() 来执行时,main()会调用TextTestRunner中的run()方法来执行,也可以直接通过 TextTestRunner来执行测试用例。在Runner执行时,会默认将执行的结果输出到控制台中,为了方便查看输出的结果,我们可以使用 logging 日志来对输出的结果进行管理,可以把结果直接输出到指定的文件中。

而 Page Object 是Selenium自动化测试开发实践的最佳设计模式之一,通过对界面元素的封装来减少代码的冗余,同时在后期维护中,元素的定位一旦发生变化,我们只需要调整页面元素封装的代码,这样可以提高测试用例的可维护性。

针对前面书写的关于豌豆荚的登录测试用例使用 Page Object 设计模式对书写的代码进行重构,重构的思路如下:

  1. 将一些常用的内容,(如一些取消更新、跳过元素定位等)抽离出来
  2. 将元素定位的方法和元素的属性值与业务的代码进行分离
  3. 将登录功能独立封装成一个模块
  4. 最后使用unittest来进行综合统筹

代码实现:

1、对 豌豆荚App 的启动信息进行单独的封装

xgCaps.py

from appium import webdriver
import yaml, logging, logging.config

log_file = '../log.conf'
logging.config.fileConfig(log_file)
logging = logging.getLogger()

def appium_caps():
    file = open('../appium_two/wdj_capability.yaml', 'r')
    data = yaml.load(file, Loader=yaml.FullLoader)

    xg_caps = {}
    xg_caps['platformName'] = data['platformName']
    xg_caps['platformVersion'] = data['platformVersion']
    xg_caps['deviceName'] = data['deviceName']

    xg_caps['appPackage'] = data['appPackage']
    xg_caps['appActivity'] = data['appActivity']

    xg_caps['noReset'] = data['noReset']
    xg_caps['unicodeKeyboard'] = data['unicodeKeyboard']
    xg_caps['resetKeyboard'] = data['resetKeyboard']

    logging.info('start app ......')
    driver = webdriver.Remote('http://'+str(data['ip'])+':'+str(data['port'])+'/wd/hub', xg_caps)

    driver.implicitly_wait(6)
    return driver

if __name__ == '__main__':
    appium_caps()

2、封装一个基类 baseView.py 

在这个基类里面主要是对 driver 的初始化和元素的定位方式进行一些封装

class BaseView(object):
    def __init__(self, driver):
        self.driver = driver

    def find_element(self, *location):
        return self.driver.find_element(*location)

    def find_elements(self, *location):
        return self.driver.find_elements(*location)

    def get_window_size(self):
        return self.driver.get_window_size()

    def swipe(self, st_x, st_y, end_x, end_y, duration):
        return self.driver.swipe(st_x, st_y, end_x, end_y, duration)

3、封装一个公共类 general_class.py

在这个公共类里主要是对后面实现多账号切换登录准备的,因为在多账号登录时都有可能会遇到更新和跳过的画面

from page_unit.baseView import BaseView
from selenium.common.exceptions import NoSuchElementException
from page_unit.xgCaps import appium_caps
from selenium.webdriver.common.by import By
import logging, time

class general_view(BaseView):
    cancelBtn = (By.ID, 'com.wandoujia.phoenix2:id/s5')
    jumpBtn = (By.ID, 'com.wandoujia.phoenix2:id/v8')

    def click_cancelBtn(self):
        logging.info('*' * 10 + 'cancelBtn' + '*' * 10)
        try:
            cancel_element = self.driver.find_element(*self.cancelBtn)
        except NoSuchElementException:
            logging.info('cancelBtn is not found !')
        else:
            logging.info('click cancelBtn')
            cancel_element.click()

    def click_jumpBtn(self):
        logging.info('——' * 10 + 'jumpBtn' + '——' * 10)
        try:
            jump_element = self.driver.find_element(*self.jumpBtn)
        except NoSuchElementException:
            logging.info('jumpBtn is not fond !')
        else:
            logging.info('click jumpBtn')
            jump_element.click()

    def getTime(self):
        self.currentTime = time.strftime("%Y-%m-%d %H_%M_%S")
        return self.currentTime

    def get_screenSzie(self):
        x = self.get_window_size()['width']
        y = self.get_window_size()['height']
        return (x, y)

if __name__ == '__main__':
    driver = appium_caps()
    general = general_view(driver)
    general.click_cancelBtn()
    general.click_jumpBtn()

4、对登录操作进行封装

在这一步的操作中,会用到一个 By 模块,它里面的内容比较简单,很容易看懂的哦,只需要指定用的哪一种定位的方式,然后在后面跟上这个元素的定位方式对应的内容即可

by.py  内容

class By(object):
    """
    Set of supported locator strategies.
    """

    ID = "id"
    XPATH = "xpath"
    LINK_TEXT = "link text"
    PARTIAL_LINK_TEXT = "partial link text"
    NAME = "name"
    TAG_NAME = "tag name"
    CLASS_NAME = "class name"
    CSS_SELECTOR = "css selector"

至于,By 这个类的具体使用,可以看下面的 login_view.py 

from page_unit.general_class import general_view
from page_unit.xgCaps import appium_caps
from selenium.webdriver.common.by import By
import logging

class login_view(general_view):
    # 主导航菜单
    navigation_element = (By.ID, 'com.wandoujia.phoenix2:id/w4')
    # 设置菜单
    setting_element = (By.ID, 'com.wandoujia.phoenix2:id/pp_item_setting')
    # 登录
    login_element = (By.ID, 'com.wandoujia.phoenix2:id/ow')
    # 用户名、密码
    username_element = (By.ID, 'com.wandoujia.phoenix2:id/l_')
    password_element = (By.ID, 'com.wandoujia.phoenix2:id/la')
    # 复选框
    checkBox_element = (By.ID, 'com.wandoujia.phoenix2:id/mw')
    # 登录按钮
    loginBtn_element = (By.ID, 'com.wandoujia.phoenix2:id/mf')

    def login_action(self, username, password):
        self.click_jumpBtn()
        self.click_cancelBtn()
        logging.info('=' * 10 + 'login_action' + '=' * 10)
        self.driver.find_element(*self.navigation_element).click()
        self.driver.find_element(*self.setting_element).click()
        self.driver.find_element(*self.login_element).click()
        logging.info('username is:%s' % username)
        self.driver.find_element(*self.username_element).send_keys(username)
        logging.info('password is:*************')
        self.driver.find_element(*self.password_element).send_keys(password)
        logging.info('check the box')
        self.driver.find_element(*self.checkBox_element).click()
        logging.info('click loginBtn')
        self.driver.find_element(*self.loginBtn_element).click()

if __name__ == '__main__':
    driver = appium_caps()
    login = login_view(driver)
    login.login_action('用户名', '密码')

5、使用 unittest 用例 封装

5.1 对用例启动和结束时的配置进行封装

xgunit.py

from page_unit.xgCaps import appium_caps
import unittest, logging
from time import sleep

class startAndEnd(unittest.TestCase):

    def setUp(self):
        logging.info('-' * 10 + 'setUp' + '-' * 10)
        self.driver = appium_caps()

    def tearDown(self):
        logging.info('=' * 10 + 'tearDown' + '=' * 10)
        sleep(5)
        self.driver.close_app()

5.2 对多个账号的登录进行封装

xg_login.py

from page_unit.login_view import login_view
from page_unit.xgUnit import startAndEnd
import logging, unittest

class TestLogin(startAndEnd):

    def test_login_first(self):
        logging.info('-' * 10 + 'first' + '-' * 10)
        first = login_view(self.driver)
        first.login_action('用户名', '密码')

    def test_login_second(self):
        logging.info('=' * 10 + 'second' + '=' * 10)
        second = login_view(self.driver)
        second.login_action('用户名', '密码')

    def test_login_third(self):
        logging.info('*' * 10 + 'third' + '*' * 10)
        third = login_view(self.driver)
        third.login_action('用户名', '密码')

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

6、执行过程及结果

执行的日志及控制台打印情况:

发布了37 篇原创文章 · 获赞 63 · 访问量 9669

猜你喜欢

转载自blog.csdn.net/xiao66guo/article/details/100525299