Automação Web com Python+Selenium — análise de padrões e casos de PageObject

1. Modo PO

O padrão Page Object (PO, abreviadamente) é o mais popular na prática do Selenium e é o padrão de design mais familiar e respeitado em testes automatizados. Ao projetar testes automatizados, abstraia os elementos da página e seus métodos de operação de acordo com a página, separe-os em determinados objetos e depois organize-os.

Um dos problemas mais problemáticos na automação web é que a página muda.Se o padrão de design PO não for usado, uma mudança na página significa que o posicionamento anterior do elemento e até mesmo o método de operação do elemento não podem ser usados ​​e precisam ser revisados . Você precisa descobrir os métodos de posicionamento de elementos e métodos de operação de elementos que precisam ser modificados um por um no script de teste e, em seguida, modificá-los um por um. Esses scripts automatizados não são apenas complicados, mas também extremamente caros de manter.

O modo de objeto de página pode resolver esse problema muito bem. Vantagens:

  • Reduza a redundância de código
  • Separação de negócios e implementação
  • Reduza os custos de manutenção

Então, qual é o modo Objeto de página? Como o nome sugere, é o objeto de página. Nos testes automatizados reais, os scripts geralmente são divididos em três camadas:

  • Camada de objeto: usada para armazenar o posicionamento dos elementos da página
  • Camada lógica: usada para armazenar alguns módulos de casos de uso funcionais encapsulados
  • Camada de negócios: usada para armazenar a parte operacional de nossos casos de teste reais

Além das três camadas acima, há também uma camada básica. A camada básica é principalmente para alguns métodos comuns de Selenium. Ela é reencapsulada de acordo com as necessidades reais do negócio, como clicar, inserir e outras operações, adicionando algumas espera, entrada de log, capturas de tela e outras operações por conveniência. Verifique o status de execução do script e solucione problemas posteriormente.

2. Camada básica

O nome da classe da camada base geralmente é denominado BasePage. As operações subsequentes da camada de objeto em elementos herdam essa classe base. O exemplo a seguir usa clique e entrada:

# basepage.py
import os
import time
import datetime
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from common.logging import log
from common.constant import IMG_DIR


class BasePage:

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

    def wait_ele_visible(self, loc, img_desc, timeout=20, frequency=0.5):
        """等待元素可见"""
        try:
            WebDriverWait(self.driver, timeout, frequency).until(EC.visibility_of_element_located(loc))
            log.info("等待:{} - 元素{}可见成功。".format(img_desc, loc))
        except:
            log.exception("等待:{} - 元素{}可见失败!".format(img_desc, loc))
            self.save_img(img_desc)
            raise

    def get_element(self, loc, img_desc):
        """查找元素"""
        try:
            ele = self.driver.find_element(*loc)
        except:
            log.exception("查找:{} - 元素{}失败!".format(img_desc, loc))
            self.save_img(img_desc)
            raise
        else:
            log.info("查找:{} - 元素{}成功".format(img_desc, loc))
            return ele

    def click_element(self, loc, img_desc, timeout=20, frequency=0.5):
        """点击元素"""
        self.wait_ele_visible(loc, img_desc, timeout, frequency)
        ele = self.get_element(loc, img_desc)
        try:
            ele.click()
            log.info("点击:{} - 元素{}成功".format(img_desc, loc))
        except:
            log.exception("点击:{} - 元素{}失败!".format(img_desc, loc))
            self.save_img(img_desc)
            raise

    def input_text(self, loc, value, img_desc, timeout=20, frequency=0.5):
        """在元素中输入文本"""
        self.wait_ele_visible(loc, img_desc, timeout, frequency)
        ele = self.get_element(loc, img_desc)
        try:
            ele.send_keys(value)
            log.info("输入:在{} - 元素{}输入文本值({})成功".format(img_desc, loc, value))
        except:
            log.exception("输入:在{} - 元素{}输入文本值({})失败!".format(img_desc, loc, value))
            self.save_img(img_desc)
            raise

    def save_img(self, img_description):
        """保存异常截图"""
        now = time.strftime("%Y-%m-%d %H-%M-%S ", time.localtime())
        img_path = os.path.join(IMG_DIR, now + img_description + '.png')
        try:
            self.driver.save_screenshot(img_path)
        except:
            log.exception("异常截图失败!")
        else:
            log.info("异常截图成功,截图存放在{}".format(img_path))
折叠

Tome click_element() como exemplo. A operação de espera, a entrada de log e as capturas de tela de exceção são adicionadas ao encapsulamento secundário aqui. Ao clicar no elemento posteriormente, você pode chamar diretamente click_element() para acertar em uma única etapa. Não há necessidade de considerar espera, registros e exceções. A situação foi tratada aqui. Embora escrever páginas básicas consuma mais tempo no estágio inicial, contanto que a base esteja lançada, o trabalho de manutenção subsequente será muito mais demorado. mais fácil. O texto acima é apenas um exemplo e pode ser otimizado de acordo com suas necessidades reais.

3. Camada de objeto e camada lógica

A camada de objeto armazena o posicionamento dos elementos da página e a camada lógica armazena os métodos de operação dos elementos (funções da página). O posicionamento dos elementos pode ser mantido em um módulo separado de acordo com as necessidades reais ou pode ser armazenado no Excel para gerenciamento centralizado; os elementos são demonstrados abaixo Os métodos de posicionamento e operação de elementos são armazenados em um módulo, um módulo por página. Se os elementos da página subsequentes mudarem, você só precisará modificar a expressão de posicionamento ou método de operação correspondente neste módulo.

​ A demonstração toma como exemplo a página inicial do Baidu:

# baidu_page.py

from selenium.webdriver.common.by import By
from common.basepage import BasePage


class LoginPage(BasePage):

    login_btn = (By.XPATH, '//div[@id="u1"]//a[@name="tj_login"]')  # 登录按钮
    username_login_btn = (By.ID, 'TANGRAM__PSP_11__footerULoginBtn')    # 用户名登录按钮
    user_input = (By.ID, 'TANGRAM__PSP_11__userName')  # 用户信息输入框
    pwd_input = (By.ID, 'TANGRAM__PSP_11__password')  # 密码输入框
    login_submit = (By.ID, 'TANGRAM__PSP_11__submit')   # 登录提交按钮

    def login(self, user, pwd):
        """
        百度用户名登录
        :param user: 手机/邮箱/用户名
        :param pwd: 密码
        :return:
        """
        self.click_element(self.login_btn, '百度-登录')
        self.click_element(self.username_login_btn, '百度登录-用户名登录')
        self.input_text(self.user_input, user, '用户名登录-手机/邮箱/用户名')
        self.input_text(self.pwd_input, pwd, '用户名登录-密码')
        self.click_element(self.login_submit, '用户名登录-登录')

4. Camada de negócios

Usado para armazenar operações reais de casos de teste. O posicionamento dos elementos e as funções da página não aparecerão aqui. Todas as operações são chamadas diretamente para a camada lógica.

Caso de teste = função do objeto de teste + dados de teste. A seguir, o login do Baidu é usado como exemplo (para demonstração, abreviado):

import unittest
import pytest
import ddt
from selenium import webdriver
from PageObjects.baidu_login_page import LoginPage
from testdatas import common_datas as com_d
from testdatas import login_data as lo_d
from common.logging import log


@ddt.ddt
class TestLogin(unittest.TestCase):

    def setUp(self):
        log.info("-------用例前置工作:打开浏览器--------")
        self.driver = webdriver.Chrome()
        self.driver.get(com_d.baidu_url)
        self.driver.maximize_window()

    def tearDown(self):
        self.driver.quit()
        log.info("-------用例后置工作:关闭浏览器--------")

    @pytest.mark.smoke
    def test_login_success(self):
        # 用例:登录页的登录功能
        # 步骤
        LoginPage(self.driver).login(lo_d.success_data['user'], lo_d.success_data['pwd'])
        # 断言.....

Resultados em execução:

Testing started at 11:50 ...
C:\software\python\python.exe "C:\Program Files\JetBrains\PyCharm Community Edition 2022.1.3\helpers\pycharm\_jb_unittest_runner.py" --path D:/learn/test/testcases/test_baidu_login.py
Launching unittests with arguments python -m unittest D:/learn/test/testcases/test_baidu_login.py in D:\learn\test\testcases

Process finished with exit code 0
2022-07-11 11:50:47,238-【test_baidu_login.py-->line:27】-INFO:-------用例前置工作:打开浏览器--------
2022-07-11 11:50:51,327-【basepage.py-->line:38】-INFO:等待:百度-登录 - 元素('xpath', '//div[@id="u1"]//a[@name="tj_login"]')可见成功,耗时0:00:00.056843秒
2022-07-11 11:50:51,339-【basepage.py-->line:77】-INFO:查找:百度-登录 - 元素('xpath', '//div[@id="u1"]//a[@name="tj_login"]')成功
2022-07-11 11:50:51,414-【basepage.py-->line:86】-INFO:点击:百度-登录 - 元素('xpath', '//div[@id="u1"]//a[@name="tj_login"]')成功
2022-07-11 11:50:53,463-【basepage.py-->line:38】-INFO:等待:百度登录-用户名登录 - 元素('id', 'TANGRAM__PSP_11__footerULoginBtn')可见成功,耗时0:00:02.048293秒
2022-07-11 11:50:53,474-【basepage.py-->line:77】-INFO:查找:百度登录-用户名登录 - 元素('id', 'TANGRAM__PSP_11__footerULoginBtn')成功
2022-07-11 11:50:53,535-【basepage.py-->line:86】-INFO:点击:百度登录-用户名登录 - 元素('id', 'TANGRAM__PSP_11__footerULoginBtn')成功
2022-07-11 11:50:53,576-【basepage.py-->line:38】-INFO:等待:用户名登录-手机/邮箱/用户名 - 元素('id', 'TANGRAM__PSP_11__userName')可见成功,耗时0:00:00.040890秒
2022-07-11 11:50:53,584-【basepage.py-->line:77】-INFO:查找:用户名登录-手机/邮箱/用户名 - 元素('id', 'TANGRAM__PSP_11__userName')成功
2022-07-11 11:50:53,714-【basepage.py-->line:98】-INFO:输入:在用户名登录-手机/邮箱/用户名 - 元素('id', 'TANGRAM__PSP_11__userName')输入文本值(15692004245)成功
2022-07-11 11:50:53,759-【basepage.py-->line:38】-INFO:等待:用户名登录-密码 - 元素('id', 'TANGRAM__PSP_11__password')可见成功,耗时0:00:00.043882秒
2022-07-11 11:50:53,771-【basepage.py-->line:77】-INFO:查找:用户名登录-密码 - 元素('id', 'TANGRAM__PSP_11__password')成功
2022-07-11 11:50:53,925-【basepage.py-->line:98】-INFO:输入:在用户名登录-密码 - 元素('id', 'TANGRAM__PSP_11__password')输入文本值(phang0209)成功
2022-07-11 11:50:53,958-【basepage.py-->line:38】-INFO:等待:用户名登录-登录 - 元素('id', 'TANGRAM__PSP_11__submit')可见成功,耗时0:00:00.031914秒
2022-07-11 11:50:53,969-【basepage.py-->line:77】-INFO:查找:用户名登录-登录 - 元素('id', 'TANGRAM__PSP_11__submit')成功
2022-07-11 11:50:54,051-【basepage.py-->line:86】-INFO:点击:用户名登录-登录 - 元素('id', 'TANGRAM__PSP_11__submit')成功
2022-07-11 11:50:56,426-【test_baidu_login.py-->line:35】-INFO:-------用例后置工作:关闭浏览器--------


Ran 1 test in 9.191s

OK

​ A julgar pelo registro de saída, cada etapa da operação é claramente visível e os problemas podem ser localizados rapidamente e otimizados de acordo com as necessidades reais.

  • Modo PO
  • camada base
  • Camada de objeto e camada lógica
  • Camada de Negócios

Por fim: A seguir estão os materiais de aprendizagem de apoio. Para quem está fazendo [teste de software], deve ser o armazém de preparação mais abrangente e completo. Este armazém também me acompanhou na jornada mais difícil. Espero que também possa ajudá-lo!

Applet de entrevista de teste de software

Um banco de perguntas de teste de software que tem sido usado por milhões de pessoas! ! ! Quem é quem sabe! ! ! O miniprograma de teste de entrevista mais completo da Internet, você pode usar seu celular para tirar dúvidas, pegar metrô, ônibus e enrolar!

Abrange as seguintes seções de perguntas da entrevista:

1. Teoria básica de teste de software, 2. web, aplicativo, teste de função de interface, 3. rede, 4. banco de dados, 5. linux

6. Web, aplicativo, automação de interface, 7. Teste de desempenho, 8. Noções básicas de programação, 9. Perguntas da entrevista de RH, 10. Perguntas de teste abertas, 11. Testes de segurança, 12. Noções básicas de informática

  Como obter o conjunto completo de informações: Clique no pequeno cartão abaixo para obtê-lo você mesmo

Acho que você gosta

Origin blog.csdn.net/weixin_57794111/article/details/132900677
Recomendado
Clasificación