目录

1.复杂用例的前置条件 、测试步骤

2.basepage

 

正文  83 28min

 1.复杂用例的前置条件 、测试步骤---------以  投资用例 为例子来详细说明

 根据测试步骤来进行编写

①编写投资的测试用例 test_invest.py  ------之前的test_login.py测试用例编写的是TestLogin类,在投资测试用例中换个方式,直接写成函数

"""投资用例"""

def test_invest_fail_not_10_times():
    """投资失败:输入金额不是10的整数倍 的测试用例
    测试步骤:
    1.前置条件:先登录 conftest
         ---账户有余额
         ---有标
    2.首页:点击 【抢投标】
    3.投标详情页:输入投标金额
    4.详情页:获取结果
    """

根据test_invest_fail_not_10_times()函数的docstring,投标之前的前置条件,除了登录,还需要:账户必须有余额(充值),系统有标可以投(建标、审核),那么这些条件是否都需要通过web自动化去实现???

---------不需要!!!

可以实现前置条件的方式比如:接口实现、修改数据库、手工添加、web自动化等

web自动化实现:可以每次执行之前,都自动化充值、或者加标或者,一次性充值足够的钱。但是,用web自动化实现这些前置条件,比较麻烦又比较困难,

所以,可以通过手工的方式实现前置条件。

总之一句话,这些前置条件能够满足,就OK了。------------(只要能够实现这个前置条件,就可以)

 

①-1前置条件--登录

在conftest中,封装登录的前置条件--------在login测试用例中,实现了test_login_success()的方法,在前置封装的登录方法中直接调用即可

"""固定文件名conftest.py,存储所有的测试夹具fixture"""
import pytest
from middware import handler
from middware.pages.login import LoginPage
from data.login_data import data_success

@pytest.fixture()
def driver():
    from selenium import webdriver

    ##前置条件
    #打开浏览器
    driver = webdriver.Chrome()

    # 设置隐性等待 等待的时间就可以放在config中,直接参数调用
    wait_time = handler.HandlerMiddle.yaml_data["selenium"]["wait_time"]
    driver.implicitly_wait(wait_time)

    yield driver

    #后置清理
    driver.quit()

@pytest.fixture()
def login(driver):
    """登录"""

    #前置条件:登录成功
    user_info = data_success[0] #登录成功数据的第一条,实现登录即可
    #登录成功后进入首页
    index_page = LoginPage(driver).get().login_success(username=user_info["username"],
                                          password=user_info["password"])
    #返回首页
    yield index_page

    #无后置清理工作

 

继续按测试步骤执行第二步:抢投标

但是并没有封装抢投标的方法,则返回到index页面进行抢投标方法的封装

②首页 点击:抢投标

定位【抢投标】按钮,来确定元素定位方式:

 

 

 index.py文件中封装抢投标的方法:

"""登录成功页面"""
from selenium.webdriver.common.by import By
from middware.handler import HandlerMiddle


class IndexPage:
    """登录成功"""

    #首页的URL
    URL  =HandlerMiddle.yaml_data["host"] + "/Index.html"

    #用户账号locator
    user_accout_locator = (By.XPATH,'//a[@href="/Member/index.html"]')

    #抢投标按钮locator
    invest_btn_locator = (By.CLASS_NAME,'btn-special')

    #初始化driver
    def __init__(self,driver):
        self.driver = driver

    #打开首页
    def get(self):
        self.driver.get(self.URL)
        return self

    #获取登录成功的用户名
    def get_account_name(self):
        web_element=self.driver.find_element(*self.user_accout_locator)
        return web_element.text

    #点击抢投标
    def click_invest_btn(self):
        self.driver.find_element(*self.user_accout_locator).click()
        # 返回投标详情页
        return InvestPage(self.driver)

点击抢投标进入的是投标详情页----》所以抢投标的方法,返回的是投标详情页

投标详情页 没有封装,下面进行投标详情页的封装:----invest.py

 

③页面详情页-输入用户金额、点击投标

 invest.py中 封装的类InvestPage中:

不需要URL -----因为每个详情页是不一样的,详情页是动态变化的(URL是变化的)

不需要get()方法----因为无法直接访问该详情页

 

下面进行投标金额输入框的元素定位:输入用户金额 ----->定位【投标】按钮并点击

 

 

 

定位投标按钮(不是10的整数倍)进行断言

 

 

invest.py封装好如下:

"""登录成功页面"""
from selenium.webdriver.common.by import By
from middware.handler import HandlerMiddle


class InvestPage:
    """投资详情页"""
    #输入用户金额
    user_invest_input_locator = (By.CLASS_NAME,'form-control')

    #投标 按钮
    invest_btn_locator = (By.CLASS_NAME,'btn-special')

    #初始化driver
    def __init__(self,driver):
        self.driver = driver

    def enter_user_money(self,money):
        self.driver.find_element(*self.user_invest_input_locator).send_keys(money)
        return self

    def get_error_info(self):
        """错误信息:输入金额不是10的整数倍"""
        ele = self.driver.find_element(*self.invest_btn_locator)
        return ele.text

 

 再次回到test_invest.py完善测试用例:

"""投资用例"""

from middware.pages.index import IndexPage
from middware.handler import HandlerMiddle

def test_invest_fail_not_10_times(login):
    """投资失败:输入金额不是10的整数倍 的测试用例
    测试步骤:
    1.前置条件:先登录 conftest
         ---账户有余额
         ---有标
    2.首页:点击 【抢投标】
    3.投标详情页:输入投标金额
    4.详情页:获取结果
    """
    # driver = login
    # actual_result = IndexPage(driver).click_invest_btn().enter_user_money(8).get_error_info()

    actual_result = IndexPage(login).click_invest_btn().enter_user_money(8).get_error_info()

    #断言
    try:
        assert  actual_result == "请输入10的整数倍"
    except AssertionError as e:
        HandlerMiddle.logger.error("测试用例不通过!")
        raise e

 

 

84 节 

运行上面的代码,出现【抢投标】按钮元素定位成功,但是点击【抢投标】按钮,并没有生效。

原因:是前后2个页面,定位class属性的value值是一样的,value=‘btn-special’

总结:

如何避免出现上下2个页面,同样的元素定位方式重合的问题?

①等待  即等待下一个页面加载完成(在下一个页面进行操作时,在初始化中加入加入等待)

    ----time.sleep()

    ----get(),调用get(),但是不是每个页面都有get()方法,比如投资详情页是变化的,每页get()方法,就无法用

    ----显性等待

         已经加载这个页面,在初始化中完成这个页面

②检查相邻页面的元素定位方式是不是一样的。 ------需要重复查询元素,比较麻烦,不建议使用

在login 、index、invest的页面初始化中,添加显性等待:

比如:indexpage中:

title_contains:表示页面标题包含的内容

"""登录成功页面"""
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait

from middware.handler import HandlerMiddle
from middware.pages.invest import InvestPage


class IndexPage:
    """登录成功"""
    title = "项目详情"

    #首页的URL
    URL  =HandlerMiddle.yaml_data["host"] + "/Index.html"

    #用户账号locator
    user_accout_locator = (By.XPATH,'//a[@href="/Member/index.html"]')

    #抢投标按钮locator
    invest_btn_locator = (By.CLASS_NAME,'btn-special')

    #初始化driver
    def __init__(self,driver):
        self.driver = driver
        try:
            WebDriverWait(self.driver,timeout=20).until(
                expected_conditions.title_contains(self.title)
            )
        except:
            HandlerMiddle.logger.error("您的操作可能没有进入对应的页面:{},可能会有异常!".format(self.title))

 

 

2.BasePage     ---  每个页面的通用方法放在一个公共页面类当中

1)页面行为的分类:

    ---某个页面的特定的行为    定位登录元素   

    ----每个页面的通用行为     定位某个元素可见

比如等待某个元素可见,就属于通用行为:

    def wait_element_visible(self,locator,timeout = 20,poll = 0.5):
        """显式等待元素可见
        :return elem
        """
        ele = WebDriverWait(self.driver,timeout=timeout,poll_frequency=poll).until(
            expected_conditions.visibility_of_element_located(locator)
        )
        return ele

单独放在某个页面里面,就不合理。应该放在通用类basepage中更为合理

 

2)搭建basepage框架

 在pages中新建basepage.py文件,将属于的通用方法移至basepage.py中。

如下:如果别的页面要调用wait_element_visible方法,只要调用该页面的方法即可。

"""通用的方法"""
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait


class BasePage:

    def __init__(self,driver):
        self.driver = driver

    def wait_element_visible(self,locator,timeout = 20,poll = 0.5):
        """显式等待元素可见
        :return elem
        """
        ele = WebDriverWait(self.driver,timeout=timeout,poll_frequency=poll).until(
            expected_conditions.visibility_of_element_located(locator)
        )
        return ele

那么,别的页面调用的时候,之前写的是页面自己的方法,用的是self.wait_element_visible(),-----如何继续实现这样的调用?======继承

在需要调用wait_element_visible()方法的页面中,直接继承basepage类即可。

其次,将login、index、invest页面中初始化----->等待页面加载,也可以移至basepage,

但是要注意,basepage里面只是一个公共类,不能进行初始化页面,那么这个title怎么获取?

将title设置为basepage类中的类属性即可。

公共的方法basepage就是所谓的selenium_handler.py中的SeleniumHandler,既然是公共方法,不以项目为转移的,那么就可以放在common中了。

这里的BasePage类就是SeleniumHandler啦

 common中的selenium_handler.py:如下

"""通用的方法"""
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait

from middware.handler import HandlerMiddle


class BasePage:
    title = None

    def __init__(self,driver):
        self.driver = driver

        try:
            WebDriverWait(self.driver,timeout=20).until(
                expected_conditions.title_contains(self.title)
            )
        except:
            HandlerMiddle.logger.error("您的操作可能没有进入对应的页面:{},可能会有异常!".format(self.title))

    def wait_element_visible(self,locator,timeout = 20,poll = 0.5):
        """显式等待元素可见
        :return elem
        """
        ele = WebDriverWait(self.driver,timeout=timeout,poll_frequency=poll).until(
            expected_conditions.visibility_of_element_located(locator)
        )
        return ele

 

85节

总结basePage:----思想:类的继承

①不以项目为转移,每个页面都能直接调用,的页面的封装;放在一个类中,这个类就是basepage

②basepage是每个页面的父类(可以直接通过self直接调用basepage类中的方法)

下面在basepage中继续封装一些通用的方法:等待元素可以被点击、鼠标操作、窗口滚动等

"""通用的方法"""
from selenium.webdriver import ActionChains
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait

from middware.handler import HandlerMiddle


class BasePage:
    title = None

    def __init__(self,driver):
        self.driver = driver

        try:
            WebDriverWait(self.driver,timeout=20).until(
                expected_conditions.title_contains(self.title)
            )
        except:
            HandlerMiddle.logger.error("您的操作可能没有进入对应的页面:{},可能会有异常!".format(self.title))

    def wait_element_visible(self,locator,timeout = 20,poll = 0.5):
        """显式等待元素可见
        :return elem
        """
        ele = WebDriverWait(self.driver,timeout=timeout,poll_frequency=poll).until(
            expected_conditions.visibility_of_element_located(locator)
        )
        return ele

    def wait_element_clickable(self,locator,timeout = 20,poll = 0.5):
        """等待某个元素被点击"""
        ele = WebDriverWait(self.driver,timeout=timeout).until(expected_conditions.element_to_be_clickable(locator))
        return self

    def wait_element_presence(self,locator,timeout = 20,poll = 0.5):
        """等待某个元素可见"""
        ele = WebDriverWait(self.driver,timeout=timeout).until(expected_conditions.presence_of_all_elements_located(locator))
        return self

    def click(self,locator):
        """点击某个元素"""
        ele=self.wait_element_visible(locator).click()
        return self

    def enter_info(self,locator,value=None):
        """输入信息"""
        ele = self.wait_element_presence(locator).send_keys(value)
        return self


    def window_scroll(self,width=None,height=None):
        """窗口滚动"""
        if width==None:
            width="0"
        if height == None:
            height="0"

        js_code = "window.scrollTo({},{})".format(width,height)
        self.driver.execute_script(js_code)
        return self

    def mouse_moveto(self,locator):
        """鼠标操作 移动到某个元素"""
        ele= self.driver.find_element(*locator)
        ActionChains(self.driver).move_to_element(ele).perform()
        return self

    def switch_iframe(self,locator,timeout=20):
        """切换到iframe"""
        WebDriverWait(self.driver,timeout=timeout).until(expected_conditions.frame_to_be_available_and_switch_to_it(locator))
        return self