Webautomatisierung mit Python+Selenium – PageObject-Musteranalyse und Fälle

1. PO-Modus

Das Seitenobjektmuster (kurz PO) ist in der Selenium-Praxis am beliebtesten und das bekannteste und angesehenste Entwurfsmuster im automatisierten Testen. Abstrahieren Sie beim Entwerfen automatisierter Tests die Seitenelemente und ihre Betriebsmethoden entsprechend der Seite, teilen Sie sie in bestimmte Objekte auf und organisieren Sie sie dann.

​ Eines der problematischsten Probleme bei der Webautomatisierung besteht darin, dass sich die Seite ändert. Wenn das PO-Entwurfsmuster nicht verwendet wird, bedeutet eine Änderung der Seite, dass die vorherige Elementpositionierung und sogar die Elementoperationsmethode nicht verwendet werden können und überarbeitet werden müssen . Sie müssen die Elementpositionierungsmethoden und Elementoperationsmethoden, die einzeln geändert werden müssen, aus dem Testskript ermitteln und sie dann einzeln ändern. Solche automatisierten Skripte sind nicht nur umständlich, sondern auch äußerst kostspielig in der Wartung.

Der Seitenobjektmodus kann dieses Problem sehr gut lösen. Vorteile:

  • Reduzieren Sie die Code-Redundanz
  • Trennung von Geschäft und Umsetzung
  • Reduzieren Sie die Wartungskosten

Was ist also der Seitenobjektmodus? Wie der Name schon sagt, handelt es sich um das Seitenobjekt. Bei tatsächlichen automatisierten Tests werden Skripte im Allgemeinen in drei Ebenen unterteilt:

  • Objektebene: Wird zum Speichern der Positionierung von Seitenelementen verwendet
  • Logikschicht: Wird zum Speichern einiger gekapselter funktionaler Anwendungsfallmodule verwendet
  • Geschäftsschicht: Wird zum Speichern des operativen Teils unserer realen Testfälle verwendet

​ Zusätzlich zu den oben genannten drei Schichten gibt es auch eine Basisschicht. Die Basisschicht dient hauptsächlich einigen gängigen Methoden von Selenium und wird entsprechend den tatsächlichen Geschäftsanforderungen wie Klicken, Eingaben und anderen Vorgängen neu gekapselt und einige hinzugefügt Warten Sie, protokollieren Sie Eingaben, erstellen Sie Screenshots und andere Vorgänge zur Vereinfachung. Überprüfen Sie den Ausführungsstatus des Skripts und beheben Sie Probleme später.

2. Grundschicht

Der Name der Basisschichtklasse heißt im Allgemeinen BasePage. Nachfolgende Objektschichtoperationen für Elemente erben diese Basisklasse. Im Folgenden werden Klick und Eingabe als Beispiel verwendet:

# 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))
折叠

​ Nehmen Sie als Beispiel click_element(). Der Wartevorgang, die Protokolleingabe und Ausnahme-Screenshots werden hier zur sekundären Kapselung hinzugefügt. Wenn Sie später auf das Element klicken, können Sie click_element() direkt aufrufen, um es in einem Schritt richtig zu machen. Warten, Protokolle und Ausnahmen müssen nicht berücksichtigt werden. Die Situation wurde hier behandelt. Obwohl das Schreiben grundlegender Seiten in der Anfangsphase zeitaufwändiger sein wird, werden die nachfolgenden Wartungsarbeiten viel kosten, solange der Grundstein gelegt ist Einfacher. Das Obige ist nur ein Beispiel und kann entsprechend Ihren tatsächlichen Anforderungen optimiert werden.

3. Objektschicht und Logikschicht

​ Die Objektebene speichert die Positionierung von Seitenelementen und die logische Ebene speichert Elementbetriebsmethoden (Seitenfunktionen). Die Elementpositionierung kann entsprechend den tatsächlichen Anforderungen in einem separaten Modul verwaltet oder zur zentralen Verwaltung in Excel gespeichert werden. Die Elemente werden demonstriert Unten. Positionierungs- und Elementoperationsmethoden werden in einem Modul gespeichert, ein Modul pro Seite. Wenn sich nachfolgende Seitenelemente ändern, müssen Sie nur den entsprechenden Positionierungsausdruck oder die entsprechende Operationsmethode in diesem Modul ändern.

​ Die Demonstration nimmt die Baidu-Homepage als Beispiel:

# 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. Geschäftsschicht

Wird zum Speichern realer Testfalloperationen verwendet. Elementpositionierung und Seitenfunktionen werden hier nicht angezeigt. Alle Operationen werden direkt an die Logikebene aufgerufen.

Testfall = Funktion des Testobjekts + Testdaten. Im Folgenden wird die Baidu-Anmeldung als Beispiel verwendet (zur Demonstration, abgekürzt):

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'])
        # 断言.....

​ Laufergebnisse:

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

​ Aus dem Ausgabeprotokoll geht hervor, dass jeder Schritt des Vorgangs klar sichtbar ist und Probleme schnell lokalisiert und entsprechend den tatsächlichen Anforderungen optimiert werden können.

  • PO-Modus
  • Grundschicht
  • Objektschicht und Logikschicht
  • Geschäftsschicht

Abschließend: Im Folgenden finden Sie die unterstützenden Lernmaterialien. Für diejenigen, die [Softwaretests] durchführen, sollte es das umfassendste und vollständigste Vorbereitungslager sein. Dieses Lager hat mich auch auf der schwierigsten Reise begleitet. Ich hoffe, es kann Ihnen auch helfen !

Interview-Applet für Softwaretests

Eine Fragenbank für Softwaretests, die von Millionen von Menschen genutzt wird! ! ! Wer weiß es! ! ! Mit dem umfassendsten Interviewtest-Miniprogramm im Internet können Sie mit Ihrem Mobiltelefon Fragen beantworten, mit der U-Bahn oder dem Bus fahren und losfahren!

Deckt die folgenden Abschnitte mit Interviewfragen ab:

1. Grundlegende Theorie des Softwaretests, 2. Web-, App-, Schnittstellenfunktionstests, 3. Netzwerk, 4. Datenbank, 5. Linux

6. Web, App, Schnittstellenautomatisierung, 7. Leistungstests, 8. Programmiergrundlagen, 9. HR-Interviewfragen, 10. Offene Testfragen, 11. Sicherheitstests, 12. Computergrundlagen

  So erhalten Sie die vollständigen Informationen: Klicken Sie auf die kleine Karte unten, um sie selbst abzurufen

おすすめ

転載: blog.csdn.net/weixin_57794111/article/details/132900677