בפוסט זה אסביר כיצד כותבים Framework של Selenium , זהו פוסט טכני יותר מהאחרים ומיועד לכאלו שכבר מכירים Frameworks של תוכנה וכאלו שעובדים עם Selenium WebDriver ומכירים את ה-API שלו לעומק.

ישנם לא מעט Frameworks אשר רוכבים מעל הספריות של Selenium ומקלים עלינו את החיים בבואנו לכתוב תשתיות אוטומציה. רובם ככולם פשוט מממשים שכבות נוספות שעוטפות את הפונקציות של Selenium ומרחיבות את היכולות שלהן.

בואו ניקח את היישות הבסיסית ביותר ב-Selenium הלא היא ה-Interface של WebElement. ממנו אנחנו מייצרים או מגדירים כל אלמנט של האפליקציה אותה אנו בודקים.

דוגמא למעטפת כזאת אשר משתמשת ב-WebElement וכבר ממומשת בספריות של Selenium היא ה-Select לבחירת שדה מסויים מתוך ComboBox , דוגמא לעבודה עם Select:

Select country = new Select(driver.findElement(By.id("countries")));
country.selectByVisibleText("Israel");

כאמור ה- driver.findElement(By.id("countries")) מחזיר לנו אובייקט מסוג WebElement , במקרה שלנו זהו האלמנט של ה-ComboBox , אותו עטפנו בפונקציונליות של מחלקת ה-Select ע"י יצירת אובייקט (Country) וכך יכולנו להפעיל עליו מתודות , כמו ה- selectByVisibleText
iconpuzzle
ספריות Selenium – בשביל לשמור על הקוד הגנרי שלהן – אינן מרבות במעטפות כאלו , כך שאם נרצה לעטוף אלמנטים נוספים , נצטרך לממש אותם בעצמנו וליצור למעשה API שלנו שמשתמש ב-API של סלניום , או במילים אחרות – לממש Framework משל עצמנו.

 

אז איך עושים זאת ?

תחילה עלינו לכתוב כמה Interfaces משל עצמנו , למשל ה-Interface ל-WebElement עימו אנחנו נרצה לעבוד:

public interface Element extends WebElement, WrapsElement, Locatable
{
    boolean elem();
}

 

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

public class ElementImpl implements Element
{
    private final WebElement element;

    public ElementImpl(final WebElement element)
    {
        this.element = element;
    }

    @Override
    public void click()
    {
        element.click();
    }

    @Override
    public void sendKeys(CharSequence... keysToSend)
    {
        element.sendKeys(keysToSend);
    }

    // Continue to implement basic functionality
}

 

אנו משתמשים כאן ב-Delegation Pattern בכדיי לאפשר ל-WebElement לממש את הפונקציונליות , אנו יכולים להגדיר בדיוק איך אנחנו רוצים לממש.

כעת, אנחנו יכולים להגיע לאלמנט ספציפי בכדיי לכתוב לו מעטפת , ניקח לדוגמא את האלמנט CheckBox , אני למשל רוצה לכתוב לו מימוש של: אם השדה לא מסומן – סמן (בחר) אותו. הכל בצורה נקייה ואינטואטיבית ע"י פונקציה מובנית.

אז לשם כך ניצור Interface חדש של CheckBox שכמובן יורש מה-Interface של ה-Element שלנו:

public interface CheckBox extends Element
{
    void toggle();
    void check();
    void uncheck();
    boolean isChecked();
}

 

והמימוש של המתודות יהיה כך:

public class CheckBoxImpl extends ElementImpl implements CheckBox
{
    public CheckBoxImpl(WebElement element)
    {
        super(element);
    }

    public void toggle()
    {
        getWrappedElement().click();
    }

    public void check()
    {
        if (!isChecked())
        {
            toggle();
        }
    }

    public void uncheck()
    {
        if (isChecked())
        {
            toggle();
        }
    }

    public boolean isChecked()
    {
        return getWrappedElement().isSelected();
    }
}

 

המימוש הוא קצר והוא קשור במקרה הזה אך ורק לפונקציונליות של ה-CheckBox , כעת בתוכנית הראשית שלנו, כשנרצה להשתמש בפונקציה החדשה check (שבפנים משתמשת בפונקציה toggle) , נעשה זאת כך:

public class TestForm
{
    @FindBy(id = "checkbox")
    WebElement checkBox;

    @Test
    public void simple()
    {
        WebDriver driver = new FirefoxDriver();
        PageFactory.initElements(driver, this);
        driver.get("http://example_with_checkbox.com");
        CheckBox wrappedCheckBox = new CheckBoxImpl(checkBox);

        Assert.assertFalse(wrappedCheckBox.isChecked());
        wrappedCheckBox.check();
        Assert.assertTrue(wrappedCheckBox.isChecked());

        driver.quit();
    }
}

 

אז מה ראינו פה ?

הרחבנו את הספריות של Selenium WebDriver והוספנו עוד יכולות על ידי יצירת מעטפות מעל האובייקט הבסיסי – WebElement , כך שבדוגמא שלנו השתמשנו בפונקציית check אשר לא באה כחלק מהספריות הגנריות אלא נכתבה על ידינו – כאמור הפונקציה בודקת האם ה-CheckBox מסומן ובמידה ולא – היא מסמנת (בוחרת) אותו.

במילים אחרות, כתבנו API שמשתמש ב-API של Selenium , או במילים אחרות אחרות – כתבנו Framework מעל Selenium.

השאר הערה\הודעה