python + selenium 自動化測試框架


分享一個網站自動化測試框架

結構如下:

test_project
|--logs
|---pages

  |---register_page.py
|      |---base_page.py
|---test_case
       |---web_test_case
                   |---test_register.py
|      |---base.py
|---utilities
  |---conn_db.py
  |---conn_redis.py
  |---operation.py
|---settings.py
|---settings_local.py
|---requirements.txt

 

一、requirements.txt

這個文件里面是需要安裝的包,包名+版本號

1 nose==1.3.7
2 redis==2.10.5 3 selenium==3.4.3 4 PyMySQL==0.7.11 5 requests==2.18.1

在cmd 中直接運行 pip install -r requirements.txt ,自動安裝所有需要的包

 

二、settings.py

項目配置文件,用於記錄測試項目域名、全局等待時間、數據庫地址、redis地址、log的存放目錄等

# env config
ENV = 'test'

# test url test config
WEB_TEST_BASE_URL = "http://www.abc.com"

# global waiting time config
WAIT_TIME = 10

# redis config
REDIS_HOST = ''
REDIS_PORT = ''

# drive config
GECKODRIVER_PATH = 'geckodriver'

# mysql config
DB_HOST = ''
DB_PORT = ''
DB_USER = ''
DB_PASSWORD = ''

# local debugging config
import os

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
SNAPSHOT_DIRECTORY = os.path.join(BASE_DIR, 'logs')

SETTING_LOCAL_DIR = os.path.join(BASE_DIR, "settings_local.py")
if os.path.exists(SETTING_LOCAL_DIR):
    execfile(SETTING_LOCAL_DIR)

 

三、base,py

test_case目錄下所有的case需要繼承BaseSeleniumTestCase()這個類,此處需要說明一下,通過設置settings中ENV的值修改啟動的瀏覽器,當ENV='dev'的時候,啟動的是Firefox,否則啟動PhantomJS。

 import logging
from unittest import TestCase
from selenium import webdriver
import settings

logger = logging.getLogger(__name__)


class BaseSeleniumTestCase(TestCase):
    def get_web_driver(self):
        driver = webdriver.Firefox(executable_path=settings.GECKODRIVER_PATH) if settings.ENV == "dev" else webdriver.PhantomJS()
        driver.maximize_window()
        return driver

    def setUp(self):
        self.selenium = self.get_web_driver()

    def tearDown(self):
        self.selenium.quit()

四、base_page.py

頁面基類,主要是定位、判斷元素等,所有pages目錄下的各個頁面的page文件需要繼承BasePage()類。

fail_on_screenshot() 修飾器,當定位元素或者判斷元素的方法報出 TimeoutException、NoSuchElementException、InvalidElementStateException 錯誤時,對當時的頁面進行截圖,並且保存在項目logs目錄中,名稱為當前時間。

 # coding=UTF-8
import logging,os,settings
from datetime import datetime
from selenium.common.exceptions import NoSuchElementException, TimeoutException, InvalidElementStateException
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as expected
from selenium.webdriver.support.wait import WebDriverWait
from settings import WAIT_TIME

logger = logging.getLogger(__name__)


def fail_on_screenshot(function):
    def get_snapshot_directory():
        if not os.path.exists(settings.SNAPSHOT_DIRECTORY):
            os.mkdir(settings.SNAPSHOT_DIRECTORY)
        return settings.SNAPSHOT_DIRECTORY

    def get_current_time_str():
        return datetime.strftime(datetime.now(), "%Y%m%d%H%M%S%f")

    def wrapper(*args, **kwargs):
        instance, selector = args[0], args[1]
        try:
            return function(*args, **kwargs)
        except (TimeoutException, NoSuchElementException, InvalidElementStateException) as ex:
            logger.error("Could not find the selector: [{}].".format(selector))
            filename = "{}.png".format(get_current_time_str())
            screenshot_path = os.path.join(get_snapshot_directory(), filename)
            logger.debug(instance.selenium.page_source)
            instance.selenium.save_screenshot(screenshot_path)
            raise ex
    return wrapper


class BasePage(object):
    url = ""
    base_url = settings.WEB_TEST_BASE_URL

    def __init__(self, selenium, url_params=None):
        if not url_params:
            url_params = []
        self.selenium = selenium
        self.url_params = url_params
        self.go_to()

    def go_to(self):
        logger.debug("Goto page: [{}]".format(self.get_page_url()))
        return self._selenium_get_url(self.get_page_url())

    def refresh(self):
        self.selenium.refresh()

    def navigate_back(self):
        self.selenium.back()

    def _selenium_get_url(self, url):
        try:
            self.selenium.get('about:blank')
            self.selenium.get(str(url))
        except Exception as ex:
            logger.error("Can not open the url:[{}]".format(url))
            raise ex
        return self

    def get_page_url(self):
        if not self.url:
            raise RuntimeError("no url been set")
        return self._get_url(self.url)

    def _get_url(self, url):
        format_url = url.format(*self.url_params)
        return "{0}{1}".format(self.base_url, format_url)

    def get_current_page_url(self):
        return self.selenium.current_url

    def get_page_title(self):
        return self.selenium.title

    def get_cookie_value(self):
        return self.selenium.get_cookie('client_identity')['value']

    # ---------------------------------------------------------------------------------------------------------------
    '''判斷某個元素是否被添加到了dom里並且可見,可見代表元素可顯示且寬和高都大於0'''

    @fail_on_screenshot
    def find_element_by_css(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.visibility_of_element_located((By.CSS_SELECTOR, selector)))

    @fail_on_screenshot
    def find_element_by_link_text(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.visibility_of_element_located((By.LINK_TEXT, selector)))

    @fail_on_screenshot
    def find_element_by_partial_link_text(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.visibility_of_element_located((By.PARTIAL_LINK_TEXT, selector)))

    @fail_on_screenshot
    def find_element_by_id(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.visibility_of_element_located((By.ID, selector)))

    @fail_on_screenshot
    def find_element_by_xpath(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.visibility_of_element_located((By.XPATH, selector)))

    @fail_on_screenshot
    def find_element_by_name(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.visibility_of_element_located((By.NAME, selector)))

    @fail_on_screenshot
    def find_element_by_class_name(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.visibility_of_element_located((By.CLASS_NAME, selector)))

    @fail_on_screenshot
    def find_element_by_tag_name(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.visibility_of_element_located((By.TAG_NAME, selector)))

    # ----------------------------------------------------------------------------------------------------------------
    '''判斷是否至少有1個元素存在於dom樹中,如果定位到就返回列表'''

    @fail_on_screenshot
    def find_elements_by_css(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.presence_of_all_elements_located((By.CSS_SELECTOR, selector)))

    @fail_on_screenshot
    def find_elements_by_class_name(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.presence_of_all_elements_located((By.CLASS_NAME, selector)))

    @fail_on_screenshot
    def find_elements_by_link_text(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.presence_of_all_elements_located((By.LINK_TEXT, selector)))

    @fail_on_screenshot
    def find_elements_by_xpath(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.presence_of_all_elements_located((By.XPATH, selector)))

    # -------------------------------------------------------------------------------------------------------------
    '''判斷某個元素在是否存在於dom或不可見,如果可見返回False,不可見返回這個元素'''

    @fail_on_screenshot
    def invisible_element_by_id(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.invisibility_of_element_located((By.ID, selector)))

    @fail_on_screenshot
    def invisible_element_by_xpath(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.invisibility_of_element_located((By.XPATH, selector)))

    @fail_on_screenshot
    def invisible_element_by_css(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.invisibility_of_element_located((By.CSS_SELECTOR, selector)))

    @fail_on_screenshot
    def invisible_element_by_link_text(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.invisibility_of_element_located((By.LINK_TEXT, selector)))

    @fail_on_screenshot
    def invisible_element_by_name(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.invisibility_of_element_located((By.NAME, selector)))

    @fail_on_screenshot
    def invisible_element_by_class_name(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.invisibility_of_element_located((By.CLASS_NAME, selector)))

    @fail_on_screenshot
    def invisible_element_by_tag_name(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.invisibility_of_element_located((By.TAG_NAME, selector)))

    @fail_on_screenshot
    def invisible_element_by_partial_link_text(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.invisibility_of_element_located((By.PARTIAL_LINK_TEXT, selector)))

    # -----------------------------------------------------------------------------------------------------------------

    '''判斷指定的元素中是否包含了預期的字符串,返回布爾值'''

    @fail_on_screenshot
    def text_to_be_present_in_element_by_id(self, selector, wait_time=WAIT_TIME,text=None):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.text_to_be_present_in_element((By.ID, selector),text))

    @fail_on_screenshot
    def text_to_be_present_in_element_by_name(self, selector, wait_time=WAIT_TIME,text=None):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.text_to_be_present_in_element((By.NAME, selector),text))

    @fail_on_screenshot
    def text_to_be_present_in_element_by_class_name(self, selector, wait_time=WAIT_TIME,text=None):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.text_to_be_present_in_element((By.CLASS_NAME, selector),text))

    @fail_on_screenshot
    def text_to_be_present_in_element_by_xpath(self, selector, wait_time=WAIT_TIME,text=None):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.text_to_be_present_in_element((By.XPATH, selector),text))

    @fail_on_screenshot
    def text_to_be_present_in_element_by_tag_name(self, selector, wait_time=WAIT_TIME,text=None):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.text_to_be_present_in_element((By.TAG_NAME, selector),text))

    @fail_on_screenshot
    def text_to_be_present_in_element_by_css(self, selector, wait_time=WAIT_TIME,text=None):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.text_to_be_present_in_element((By.CSS_SELECTOR, selector),text))

    # -----------------------------------------------------------------------------------------------------------------

    '''判斷指定元素的屬性值中是否包含了預期的字符串,返回布爾值'''

    @fail_on_screenshot
    def text_to_be_present_in_element_value_by_css(self, selector, wait_time=WAIT_TIME,text=None):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.text_to_be_present_in_element_value((By.CSS_SELECTOR, selector),text))

    @fail_on_screenshot
    def text_to_be_present_in_element_value_by_id(self, selector, wait_time=WAIT_TIME,text=None):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.text_to_be_present_in_element_value((By.ID, selector),text))

    @fail_on_screenshot
    def text_to_be_present_in_element_value_by_name(self, selector, wait_time=WAIT_TIME,text=None):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.text_to_be_present_in_element_value((By.NAME, selector),text))

    @fail_on_screenshot
    def text_to_be_present_in_element_value_by_css_name(self, selector, wait_time=WAIT_TIME,text=None):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.text_to_be_present_in_element_value((By.CLASS_NAME, selector),text))

    @fail_on_screenshot
    def text_to_be_present_in_element_value_by_xpath(self, selector, wait_time=WAIT_TIME,text=None):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.text_to_be_present_in_element_value((By.XPATH, selector),text))

    @fail_on_screenshot
    def text_to_be_present_in_element_value_by_tag_name(self, selector, wait_time=WAIT_TIME,text=None):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.text_to_be_present_in_element_value((By.TAG_NAME, selector),text))


    # -----------------------------------------------------------------------------------------------------------------
    '''判斷title,返回布爾值'''

    @fail_on_screenshot
    def page_title_is(self, title, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(expected.title_is(title))

    @fail_on_screenshot
    def page_title_contains(self, title, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(expected.title_contains(title))

    # -----------------------------------------------------------------------------------------------------------------

    '''判斷某個元素中是否可見並且是enable的,代表可點擊'''

    @fail_on_screenshot
    def element_to_be_click_able_by_id(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.element_to_be_clickable((By.ID, selector)))

    @fail_on_screenshot
    def element_to_be_click_able_by_name(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.element_to_be_clickable((By.NAME, selector)))

    @fail_on_screenshot
    def element_to_be_click_able_by_class_name(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.element_to_be_clickable((By.CLASS_NAME, selector)))

    @fail_on_screenshot
    def element_to_be_click_able_by_css(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.element_to_be_clickable((By.CSS_SELECTOR, selector)))

    @fail_on_screenshot
    def element_to_be_click_able_by_tag_name(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.element_to_be_clickable((By.TAG_NAME, selector)))

    @fail_on_screenshot
    def element_to_be_click_able_by_xpath(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.element_to_be_clickable((By.XPATH, selector)))

    @fail_on_screenshot
    def element_to_be_click_able_by_link_text(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.element_to_be_clickable((By.LINK_TEXT, selector)))

    # -----------------------------------------------------------------------------------------------------------------

    '''判斷元素是否可見,如果可見就返回這個元素,不可見返回False'''

    @fail_on_screenshot
    def visibility_of_element_by_id(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.visibility_of_element_located((By.ID, selector)))

    @fail_on_screenshot
    def visibility_of_element_by_name(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.visibility_of_element_located((By.NAME, selector)))

    @fail_on_screenshot
    def visibility_of_element_by_class_name(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.visibility_of_element_located((By.CLASS_NAME, selector)))

    @fail_on_screenshot
    def visibility_of_element_by_css(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.visibility_of_element_located((By.CSS_SELECTOR, selector)))

    @fail_on_screenshot
    def visibility_of_element_by_xpath(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.visibility_of_element_located((By.XPATH, selector)))

    @fail_on_screenshot
    def visibility_of_element_by_tag_name(self, selector, wait_time=WAIT_TIME):
        return WebDriverWait(self.selenium, wait_time).until(
            expected.visibility_of_element_located((By.TAG_NAME, selector)))

    def get_cookie_by_name(self, name):
        cookie = self.selenium.get_cookie(name)
        return cookie['value']

    def get_session_id(self):
        return self.get_cookie_by_name("TSID")

五、utilities目錄下主要存放數據庫、redis等其他相關的操作

conn_db.py 

連接數據庫

import pymysql.cursors,settings


def execute(sql, params=None, db='', is_fetchone=True):
    # Connect to the database
    connection = pymysql.connect(host=settings.DB_HOST,
                                 port=settings.DB_PORT,
                                 user=settings.DB_USER,
                                 password=settings.DB_PASSWORD,
                                 db=db,
                                 autocommit=True,
                                 charset='utf8mb4',
                                 cursorclass=pymysql.cursors.DictCursor)
    try:
        with connection.cursor() as cursor:
            cursor.execute(sql, params)
            if is_fetchone:
                return cursor.fetchone()
            else:
                return cursor.fetchall()
    finally:
        connection.close()

 

conn_redis.py

連接redis(在redis中通過session獲取圖形驗證碼、清除緩存等)

import redis, settings


def redis_connect(host=settings.CACHED_REDIS_HOST, port=settings.CACHED_REDIS_PORT):
    # Connect to the redis
    redis_client = redis.StrictRedis(host=host, port=port)
    return redis_client

 

 

下面是對注冊功能的自動化,供參考:

在pages下創建register_page.py,封裝注冊頁面中所需要的元素,內容如下:

# coding=UTF-8
from pages.base_page import BasePage
from utilities import operation


class RegisterPage(BasePage):
    url = '/register'


    def input_new_mobile(self,mobile):
        # 輸入新注冊手機號
        element = self.find_element_by_id('phonenumber')
        element.clear()
        element.send_keys(mobile)
        return self

    def click_send_sms_captcha_bt(self):
        # 點擊獲取短信驗證碼
        if self.element_to_be_click_able_by_id('get_code_btn'):
            self.find_element_by_id('get_code_btn').click()
            return self

    def judgement_sms_captcha_frame(self):
        # 校驗發送驗證碼成功后彈框
        self.visibility_of_element_by_css('.except-live-pop')
        return self

    def click_send_sms_captcha_affirm(self):
        # 點擊發送短信驗證碼彈框上的確定按鈕
        self.find_element_by_css('.except-live-pop-btn').click()
        return self

    def input_sms_captcha(self,mobile):
        # 輸入短信驗證碼
        sms_captcha = operation.get_sms_captcha(mobile)
        element = self.find_element_by_id('r_valiedatecode')
        element.clear()
        element.send_keys(sms_captcha)
        return self

    def input_new_password(self,password):
        # 輸入注冊時密碼
        element = self.find_element_by_id('r_pwd')
        element.clear()
        element.send_keys(password)
        return self

    def click_submit_register(self):
        # 點擊注冊按鈕
        if self.element_to_be_click_able_by_id('btn_reg'):
            self.find_element_by_id('btn_reg').click()
            return self

    def judgement_input_nickname_frame(self):
        # 校驗彈出輸入用戶昵稱框
        self.visibility_of_element_by_css('.c-name')
        return self

    def input_nickname(self,nickname):
        # 輸入用戶昵稱
        element = self.find_element_by_id('c_name_ipt')
        element.clear()
        element.send_keys(nickname)
        return self

    def click_nickname_bt(self):
        # 點擊輸入昵稱框確定按鈕
        if self.element_to_be_click_able_by_css('.c-n-btn'):
            self.find_element_by_css('.c-n-btn').click()
            return self

    def register(self,mobile,password,nickname):
        # 注冊流程
        self.input_new_mobile(mobile).click_send_sms_captcha_bt()
        if self.judgement_sms_captcha_frame():
            self.click_send_sms_captcha_affirm()
            self.input_sms_captcha(mobile)
            self.input_new_password(password).click_submit_register()
            if self.judgement_input_nickname_frame():
                self.input_nickname(nickname).click_nickname_bt()
        return self

index_page.py

封裝首頁所需要的元素,主要是進行注冊成功后用戶昵稱的校驗
# -*- coding:utf-8 -*-
from page.base_page import BasePage


class IndexPage(BasePage):
    url = '/index'

        def get_user_name(self):
        # 獲取用戶昵稱
        name = self.find_element_by_css('.yk-name').text
        return name

 

operation.py文件內容:

在數據庫中獲取短信驗證碼和刪除新注冊用戶的sql

# -*- coding:utf-8 -*-
import db

def get_sms_captcha(mobile):
    # 獲取短信驗證碼
    sms_captcha = db.execute('select code from send_sms_code where mobile=%s order by id desc',params=(mobile))
    return sms_captcha['code']

def delete_user(mobile):
    # 刪除用戶
    db.execute('delete from user where mobile=%s',params=(mobile))

 

在test_case下新建test_register.py

下面是一個簡單的測試注冊成功的測試用例

# -*- coding:utf-8 -*-
from pages.register_page import RegisterPage
from pages.index_page import IndexPage
from test_case.base import BaseSeleniumTestCase
from utilities import operation
import settings,time



class TestRegister(BaseSeleniumTestCase):
    mobile = '13100000001'
    password = '123abc'
    nickname = 'autotester'


    def test_register_success(self):
        # 校驗注冊流程及注冊成功后自動跳轉到首頁
        after_register_url = RegisterPage(self.selenium).register(self.mobile, self.password,self.nickname).get_current_page_url()
        time.sleep(1.5)
        self.assertEqual(after_register_url, settings.WEB_TEST_BASE_URL + '/index')

        # 校驗注冊成功后頁面title
        after_register_title = RegisterPage(self.selenium).get_page_title()
        self.assertEqual(after_register_title,u'Test-Title')

        # 校驗注冊成功后首頁用戶昵稱是否與填寫的一致
        nickname = IndexPage(self.selenium).get_user_name()
        self.assertEqual(nickname,u'autotest...')

    def tearDown(self):
        super(TestRegister,self).tearDown()
        operation.delete_user(self.mobile)

 

 

用例執行結束后,通過teardown()方法將該用戶在數據庫中刪除,下次執行的時候避免提示該手機號已注冊。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM