דף קיצורים ל Python ו Selenium

15/01/2019

פוסט זה כולל טיפ קצר לעבודה יעילה עם Python. אם אתם רוצים ללמוד פייתון יותר לעומק אני ממליץ על קורס Python כאן באתר.
הקורס כולל עשרות שיעורי וידאו והמון תרגול מעשי וילמד אתכם Python בצורה מקצועית מההתחלה ועד הנושאים המתקדמים.

לקראת הוובינר של יום חמישי ולטובת כותבי הבדיקות האוטומטיות שבקהל הקוראים אני מדביק כאן את הקיצורים והרעיונות המרכזיים שאנחנו משתמשים בהם בעת פיתוח בדיקות אוטומטיות ב Python ו Selenium ליישום Web. אם אתם באזור בסוף הפוסט יש לינק לפרטים על הוובינר - מוזמנים בחום להצטרף ולראות את כל הרעיונות האלה בשימוש בכתיבת בדיקות לאתר אמיתי.

1. סטארטר לקובץ בדיקות

אני אוהב לחלק את הבדיקות לקבצים לפי נושאים, ואחרי הרבה סיכסוכים עם סלניום הגעתי למבנה הבא שעובד לי די טוב:

import unittest
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support.ui import Select

import pdb
import time


class TestAccount(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.driver = webdriver.Firefox()
        cls.driver.implicitly_wait(5)

    @classmethod
    def tearDownClass(cls):
        cls.driver.close()

    def setUp(self):
        self.driver.delete_all_cookies()

    def test_something(self):
        pass

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

יש פה את כל ה import-ים שאתם יכולים לרצות, בחירת זמן המתנה דיפולטי של 5 שניות כך שסלניום יחכה קצת כשהוא מחפש אלמנטים ונוכל לעבוד גם עם אתרי JavaScript. הבחירה בפיירפוקס אינה מקרית - הרבה בדיקות שכתבתי וניסיתי להריץ בכרום נפלו רק בגלל בעיות בדרייבר. לא יודע אם זו בעיה רק על המחשב שלי או משהו יותר גלובאלי, אבל פיירפוקס באופן עקבי נותן תוצאות טובות יותר.

החלק הכי מעניין בסטארטר הזה הוא שלושת הפונקציות לאיתחול וסיום בדיקות: בתחילת הרצת הקובץ אנחנו מפעילים את הדפדפן ומתחברים אליו באמצעות יצירת הדרייבר, בסיום הרצת הקובץ סוגרים את הדפדפן ובין כל בדיקה לזאת שאחריה מנקים את כל העוגיות. בצורה כזאת אנחנו יכולים לרוץ מהר על כל הבדיקות בקובץ ועדיין יחסית לא ליצור השפעה או חשיבות לסדר הבדיקות.

2. פקודות סלניום ופייתון

בתחילת בדיקה בדרך כלל נרצה להיכנס לדף מסוים באתר עם:

self.driver.get('https://www.tocode.co.il')

לאחר מכן נרצה למצוא אלמנט בעמוד כדי לתקשר איתו, והכי קל לעשות את זה דרך CSS Selector:

el = self.driver.find_element_by_css_selector('#forgot')

מרגע שיש לנו אלמנט נוכל ללחוץ עליו, להעביר לו קלט או לנקות את הקלט שבו (אם זה תיבת טקסט):

el.click()
el.send_keys('hello')
el.clear()

בנוסף נוכל לשלוף מידע מהאלמנט. כך נקבל את הטקסט שכתוב באלמנט span או p:

el.text

ואם מדובר בתיבת טקסט נשתמש ב:

el.get_attribute('value')

אם האלמנט שלכם הוא במקרה תיבת Select תוכלו להשתמש בקוד הבא כדי להשפיע על הערך שבה:

select = Select(driver.find_element_by_name('name'))
select.select_by_index(index)
select.select_by_visible_text("text")
select.select_by_value(value)

ואם האלמנט נמצא בתוך טופס תוכלו להגיש את הטופס עם:

el.submit()

בחזרה לדרייבר, תוכלו לקבל את ה url הנוכחי עם:

self.driver.current_url

ואת כותרת העמוד הנוכחי עם:

self.driver.title

וגם לנווט קדימה ואחורה עם:

driver.forward()
driver.back()

3. שרשראות פעולות

יש מצבים שהאתר שאתם עובדים עליו רוצה שתיקחו את העכבר למקום מסוים ואז תלחצו או שתגררו אלמנט ממקום למקום או שתעשו סלטה הפוכה או כל מחווה מוזרה אחרת. בשביל זה המציאו בסלניום את ה Action Chains שמאפשרות לכם להזיז את העכבר בין אלמנטים וללחוץ או לעזוב את הכפתור, ממש כאילו היתה יד אנושית שמפעילה אותו.

הנה דוגמא לשרשרת פעולות שמוצאת אלמנט בתפריט שמופיע רק ב Hover:

ActionChains(self.driver).move_to_element(menu).click(item).perform()

יש גם תמיכה בגרירה ושיחרור עם:

ActionChains(driver).drag_and_drop(source_element, target_element).perform()

4. המתנה לאירועים

האוביקט expected_conditions של סלניום יאפשר לכם לחכות עד שתנאי מסוים יתקיים. במקרה הפשוט זו תהיה המתנה לאלמנט שיופיע או יעלם מהמסך, אבל יש עוד הרבה אפשרויות.

הדוגמא הבאה מהתיעוד יוצרת המתנה של עשר שניות או עד שאלמנט מסוים יהפוך ל"לחיץ":

wait = WebDriverWait(self.driver, 10)
element = wait.until(EC.element_to_be_clickable((By.ID, 'someid')))

הקטע הבא ימתין עשר שניות או עד שתופיע alert על המסך:

wait = WebDriverWait(self.driver, 10)
alert = wait.until(EC.alert_is_present())
alert.accept()

הסיבה המרכזית להעדיף את ExpectedCondition על פני time.sleep היא שבדרך כלל אנחנו לא יודעים כמה זמן אירוע מסוים ייקח - כמה זמן ייקח עד שחלון ה alert יופיע, עד שאלמנט מסוים יגיע למסך או עד שמעבר דף יסתיים. עם ExpectedCondition אנחנו יכולים לתת זמן המתנה פוטנציאלי ארוך ולדעת שאם דברים יעבדו יותר מהר לא נחכה סתם.

5. קישורים שימושיים לסיום

ביום חמישי אני אשתמש בכל הקיצורים האלה ועוד כדי לכתוב בדיקות לאתר אמיתי ברשת, ואתם יכולים להצטרף, לעזור לי למצוא באגים ולהציע רעיונות לאיזה בדיקות לכתוב. זה יקרה לייב באפליקציית Zoom וזה הקישור כדי להצטרף למפגש:

https://www.tocode.co.il/workshops/62

רוב מה שתרצו לדעת על Python ו Selenium כבר כתוב בתיעוד המצוין שלהם בקישור כאן:

https://selenium-python.readthedocs.io/index.html

ותמיד עוזר להכיר את הפונקציות מ unittest כמו assertEqual ו assert, על כולן אפשר לקרוא בדף התיעוד של המודול כאן:

https://docs.python.org/3/library/unittest.html