الأتمتة في السيلينيوم: نموذج كائن الصفحة ومصنع الصفحة
نشرت: 2022-03-11تعد كتابة الاختبارات الآلية أكثر من مجرد رفاهية لأي فريق تطوير برمجيات رشيق. إنها حاجة وأداة أساسية للعثور على الأخطاء بسرعة خلال المراحل الأولى من دورات تطوير البرامج. عندما تكون هناك ميزة جديدة لا تزال في مرحلة التطوير ، يمكن للمطورين إجراء اختبارات آلية ومعرفة كيفية تأثر الأجزاء الأخرى من النظام بهذه التغييرات. تشرح هذه المقالة كيف يمكنك تسريع الاختبار الآلي باستخدام نموذج كائن الصفحة في السيلينيوم.
من خلال أتمتة الاختبار ، من الممكن خفض تكلفة إصلاح الأخطاء وإدخال تحسينات شاملة على عملية ضمان جودة البرامج (QA). من خلال الاختبارات المناسبة ، يحصل المطورون على فرصة لإيجاد الأخطاء وحلها حتى قبل أن تصل إلى ضمان الجودة. تساعدنا أتمتة الاختبار أيضًا على أتمتة حالات الاختبار والميزات التي تتراجع باستمرار. بهذه الطريقة يكون لدى ضمان الجودة مزيد من الوقت في اختبار أجزاء أخرى من التطبيق. علاوة على ذلك ، يساعد ذلك في ضمان جودة المنتج في إصدارات الإنتاج. نتيجة لذلك ، نحصل على منتجات أكثر استقرارًا بشكل فعال ، وعملية ضمان جودة أكثر كفاءة.
على الرغم من أن كتابة الاختبارات الآلية قد تبدو مهمة سهلة للمطورين والمهندسين ، إلا أنه لا يزال هناك احتمال أن ينتهي الأمر باختبارات سيئة التنفيذ ، والتكلفة العالية لصيانة الكود في أي عملية رشيقة. يمكن أن تكون محاولة تقديم التغييرات أو الميزات باستمرار في أي مشروع تطوير رشيق مكلفًا عند إجراء الاختبارات. سيتطلب تغيير عنصر واحد على صفحة ويب يعتمد عليها 20 اختبارًا أن يمر أحدهم عبر إجراءات الاختبار العشرين هذه وتحديث كل عنصر للتكيف مع هذا التغيير الذي تم إدخاله حديثًا. لا يمكن أن يكون هذا مضيعة للوقت حقًا فحسب ، بل يمكن أن يكون أيضًا عاملاً محفزًا خطيرًا عندما يتعلق الأمر بتنفيذ الاختبارات الآلية في وقت مبكر.
ولكن ، ماذا لو تمكنا من إجراء التغيير في مكان واحد فقط ، واستخدمنا كل اختبار روتيني ذي صلة؟ في هذه المقالة ، سوف نلقي نظرة على الاختبارات الآلية في السيلينيوم ، وكيف يمكننا استخدام نماذج كائن الصفحة لكتابة إجراءات اختبار قابلة للصيانة وإعادة الاستخدام.
نموذج كائن الصفحة في السيلينيوم
نموذج كائن الصفحة هو نمط تصميم كائن في السيلينيوم ، حيث يتم تمثيل صفحات الويب في شكل فئات ، ويتم تعريف العناصر المختلفة على الصفحة كمتغيرات في الفصل. يمكن بعد ذلك تنفيذ جميع تفاعلات المستخدم الممكنة كطرق على الفصل:
clickLoginButton(); setCredentials(user_name,user_password);
نظرًا لأنه من السهل قراءة الطرق ذات الأسماء الجيدة في الفصول الدراسية ، فإن هذا يعمل كطريقة أنيقة لتنفيذ إجراءات الاختبار التي يمكن قراءتها وأسهل صيانتها أو تحديثها في المستقبل. علي سبيل المثال:
من أجل دعم نموذج كائن الصفحة ، نستخدم Page Factory. يعد Page Factory في السيلينيوم امتدادًا لـ Page Object ويمكن استخدامه بطرق مختلفة. في هذه الحالة ، سنستخدم Page Factory لتهيئة عناصر الويب المحددة في فئات صفحات الويب أو كائنات الصفحة.
تحتاج فئات صفحات الويب أو كائنات الصفحة التي تحتوي على عناصر ويب إلى التهيئة باستخدام Page Factory قبل استخدام متغيرات عنصر الويب. يمكن القيام بذلك ببساطة من خلال استخدام وظيفة التهيئة في PageFactory :
LoginPage page = new LoginPage(driver); PageFactory.initElements(driver, page);
أو حتى أبسط:
LoginPage page = PageFactory.intElements(driver,LoginPage.class)
أو ، داخل مُنشئ فئة صفحة الويب:
public LoginPage(WebDriver driver) { this.driver = driver; PageFactory.initElements(driver, this); }
سيقوم Page Factory بتهيئة كل متغير WebElement بمرجع إلى عنصر مطابق في صفحة الويب الفعلية بناءً على "محددات المواقع" التي تم تكوينها. يتم ذلك من خلال استخدام التعليقات التوضيحية FindBy . باستخدام هذا التعليق التوضيحي ، يمكننا تحديد استراتيجية للبحث عن العنصر ، جنبًا إلى جنب مع المعلومات الضرورية لتحديده:
@FindBy(how=How.NAME, using="username") private WebElement user_name;
في كل مرة يتم استدعاء طريقة في متغير WebElement ، سيجدها السائق أولاً في الصفحة الحالية ثم يحاكي التفاعل. في حال كنا نعمل بصفحة بسيطة ، نعلم أننا سنجد العنصر في الصفحة في كل مرة نبحث عنها ، ونعلم أيضًا أننا سننتقل في النهاية بعيدًا عن هذه الصفحة ولن نعود إليها ، يمكننا تخزينها مؤقتًا الحقل الذي تم البحث عنه باستخدام تعليق توضيحي بسيط آخر:
@FindBy(how=How.NAME, using="username") @CacheLookup private WebElement user_name;
يمكن استبدال هذا التعريف الكامل لمتغير WebElement بشكله الأكثر إيجازًا:
@FindBy(name="username") private WebElement user_name;
يدعم التعليق التوضيحي FindBy عددًا قليلاً من الاستراتيجيات الأخرى التي تجعل الأمور أسهل قليلاً:
id, name, className, css, tagName, linkText, partialLinkText, xpath
@FindBy() private WebElement user_name; @FindBy(name="passsword") private WebElement user_password; @FindBy(className="h3") private WebElement label; @FindBy(css=”#content”) private WebElement text;
بمجرد التهيئة ، يمكن بعد ذلك استخدام متغيرات WebElement للتفاعل مع العناصر المقابلة في الصفحة. سوف الكود التالي ، على سبيل المثال:
user_password.sendKeys(password);
... أرسل التسلسل المحدد لضغطات المفاتيح إلى حقل كلمة المرور على الصفحة ، وهو يعادل:
driver.findElement(By.name(“user_password”)).sendKeys(password);
عند الانتقال ، غالبًا ما تواجه مواقف تحتاج فيها إلى العثور على قائمة بالعناصر على الصفحة ، وذلك عندما يكون FindBys مفيدًا:
@FindBys(@FindBy(css=”div[class='yt-lockup-tile yt-lockup-video']”))) private List<WebElement> videoElements;
سيجد الكود أعلاه جميع عناصر div التي تحتوي على اسمين للفئتين "yt-lockup-tile" و "yt-lockup-video". يمكننا تبسيط هذا أكثر من خلال استبداله بما يلي:
@FindBy(how=How.CSS,using="div[class='yt-lockup-tile yt-lockup-video']") private List<WebElement> videoElements;
بالإضافة إلى ذلك ، يمكنك استخدام FindAll مع العديد من التعليقات التوضيحية FindBy للبحث عن العناصر التي تطابق أيًا من محددات المواقع المحددة:
@FindAll({@FindBy(how=How.ID, using=”username”), @FindBy(className=”username-field”)}) private WebElement user_name;
الآن بعد أن أصبح بإمكاننا تمثيل صفحات الويب على أنها فئات Java واستخدام Page Factory لتهيئة متغيرات WebElement بسهولة ، فقد حان الوقت لنرى كيف يمكننا كتابة اختبارات سيلينيوم بسيطة باستخدام نمط Page Object و Page Factory.
مشروع أتمتة اختبار السيلينيوم البسيط في جافا
بالنسبة إلى البرنامج التعليمي الخاص بنموذج كائن الصفحة ، فلنقم بالتسجيل التلقائي للمطور في Toptal. للقيام بذلك ، نحتاج إلى أتمتة الخطوات التالية:
قم بزيارة www.toptal.com
انقر فوق الزر "تطبيق كمطور"
في صفحة البوابة أولاً ، تحقق مما إذا كان مفتوحًا
انقر على زر "الانضمام إلى Toptal"
املأ الاستمارة
أرسل النموذج من خلال النقر على زر "Join Toptal"
انشاء مشروع
قم بتنزيل وتثبيت Java JDK
قم بتنزيل وتثبيت InteliJ Idea
إنشاء مشروع Maven جديد
اربط "Project SDK" بـ JDK ، على سبيل المثال: في Windows “C: \ Program Files \ Java \ jdkxxx”
إعداد groupId و artifactId:
<groupId>SeleniumTEST</groupId> <artifactId>Test</artifactId>
- أضف التبعيات Selenium و JUnit Maven في ملف POM لمشروعك
<dependencies> <!-- JUnit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <!-- Selenium --> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-firefox-driver</artifactId> <version>${selenium.version}</version> </dependency> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-support</artifactId> <version>${selenium.version}</version> </dependency> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>${selenium.version}</version> </dependency> </dependencies>
استبدل إصدار Selenium وإصدار JUnit بأحدث أرقام الإصدارات التي يمكن العثور عليها من خلال البحث عن JUnit Maven على Google وعلى موقع Selenium.
في هذه المرحلة ، إذا تم تمكين الإنشاء التلقائي ، فيجب أن يبدأ تنزيل التبعيات تلقائيًا. إذا لم يكن الأمر كذلك ، فقم فقط بتنشيط الإضافات> تثبيت> تثبيت: قم بالتثبيت ضمن لوحة Maven Projects على الجانب الأيمن من IntelliJ Idea IDE.

بمجرد بدء تشغيل المشروع ، يمكننا البدء في إنشاء حزمة الاختبار الخاصة بنا ضمن "src / test / java". قم بتسمية الحزمة "com.toptal" ، وأنشئ حزمتين إضافيتين تحتها: "com.toptal.webpages" و "com.toptal.tests".
سنحتفظ بفصول صفحة Object / Page Factory الخاصة بنا ضمن "com.toptal.webpages" وإجراءات الاختبار ضمن "com.toptal.tests".
الآن ، يمكننا البدء في إنشاء فئات كائن الصفحة الخاصة بنا.
كائن صفحة الصفحة الرئيسية
أول ما نحتاج إلى تنفيذه هو الصفحة الرئيسية لموقع Toptal (www.toptal.com). قم بإنشاء فصل دراسي ضمن "com.toptal.webpages" وقم بتسميته "الصفحة الرئيسية".
package com.toptal.webpages; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.How; import org.openqa.selenium.support.PageFactory; public class HomePage { private WebDriver driver; //Page URL private static String PAGE_URL="https://www.toptal.com"; //Locators //Apply as Developer Button @FindBy(how = How.LINK_TEXT, using = "APPLY AS A DEVELOPER") private WebElement developerApplyButton; //Constructor public HomePage(WebDriver driver){ this.driver=driver; driver.get(PAGE_URL); //Initialise Elements PageFactory.initElements(driver, this); } public void clickOnDeveloperApplyButton(){ developerApplyButton.click(); } }
تحديد محددات العناصر
في الصفحة الرئيسية لموقع Toptal ، نحن مهتمون بعنصر واحد على وجه الخصوص ، وهو زر "التقدم بطلب كمطور". يمكننا إيجاد هذا العنصر عن طريق مطابقة النص ، وهو ما سنفعله أعلاه. أثناء تصميم صفحات الويب على هيئة فئات كائن الصفحة ، غالبًا ما يصبح العثور على العناصر وتعريفها عملاً روتينيًا. باستخدام Google Chrome أو أدوات تصحيح الأخطاء في Firefox ، يمكن تسهيل ذلك. بالنقر بزر الماوس الأيمن على أي عنصر في الصفحة ، يمكنك تنشيط خيار "فحص العنصر" من قائمة السياق لمعرفة معلومات مفصلة حول العنصر.
تتمثل إحدى الطرق الشائعة (والمفضلة لدي) في العثور على عناصر باستخدام امتداد FireBug من Firefox ، جنبًا إلى جنب مع برنامج تشغيل الويب Firefox في السيلينيوم. بعد تثبيت وتمكين امتداد FireBug ، يمكنك النقر بزر الماوس الأيمن على الصفحة وتحديد "فحص العنصر باستخدام FireBug" لفتح FireBug. من علامة التبويب HTML الخاصة بـ FireBug ، يمكنك نسخ XPath أو مسار CSS أو اسم العلامة أو "المعرف" (إذا كان متاحًا) لأي عنصر في الصفحة.
من خلال نسخ XPath للعنصر في لقطة الشاشة أعلاه ، يمكننا إنشاء حقل WebElement له في كائن الصفحة على النحو التالي:
@FindBy(xpath = "/html/body/div[1]/div/div/header/div/h1") WebElement heading;
أو لتبسيط الأمور ، يمكننا استخدام اسم العلامة "h1" هنا ، طالما أنه يحدد العنصر الذي نهتم به بشكل فريد:
@FindBy(tagName = "h1") WebElement heading;
كائن صفحة DeveloperPortalPage
بعد ذلك ، نحتاج إلى كائن صفحة يمثل صفحة بوابة المطور ، والتي يمكننا الوصول إليها بالنقر فوق الزر "تطبيق كمطور".
في هذه الصفحة ، لدينا عنصران مهمان. لتحديد ما إذا تم تحميل الصفحة ، نريد التحقق من وجود العنوان. ونريد أيضًا حقل WebElement للزر "Join Toptal".
package com.toptal.webpages; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.PageFactory; public class DeveloperPortalPage { private WebDriver driver; @FindBy(xpath = "/html/body/div[1]/div/div/header/div/h1") private WebElement heading; @FindBy(linkText = "JOIN TOPTAL") private WebElement joinToptalButton; //Constructor public DeveloperPortalPage (WebDriver driver){ this.driver=driver; //Initialise Elements PageFactory.initElements(driver, this); } //We will use this boolean for assertion. To check if page is opened public boolean isPageOpened(){ return heading.getText().toString().contains("Developer portal"); } public void clikOnJoin(){ joinToptalButton.click(); } }
DeveloperApplyPage Page Object
وأخيرًا ، بالنسبة إلى كائن الصفحة الثالثة والأخيرة لهذا المشروع ، نحدد عنصرًا يمثل الصفحة التي تحتوي على نموذج طلب المطور. نظرًا لأنه يتعين علينا التعامل مع عدد من حقول النموذج هنا ، فإننا نحدد متغير WebElement واحدًا لكل حقل نموذج. نجد كل حقل من خلال "المعرف" الخاص بهم ونقوم بتعريف طرق تعيين خاصة لكل حقل تحاكي ضغطات المفاتيح للحقول المقابلة.
package com.toptal.webpages; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.PageFactory; public class DeveloperApplyPage { private WebDriver driver; @FindBy(tagName = "h1") WebElement heading; @FindBy() WebElement developer_email; @FindBy() WebElement developer_password; @FindBy() WebElement developer_password_confirmation; @FindBy() WebElement developer_full_name; @FindBy() WebElement developer_skype; @FindBy() WebElement join_toptal_button; //Constructor public DeveloperApplyPage(WebDriver driver){ this.driver=driver; //Initialise Elements PageFactory.initElements(driver, this); } public void setDeveloper_email(String email){ developer_email.clear(); developer_email.sendKeys(email); } public void setDeveloper_password(String password){ developer_password.clear(); developer_password.sendKeys(password); } public void setDeveloper_password_confirmation(String password_confirmation){ developer_password_confirmation.clear(); developer_password_confirmation.sendKeys(password_confirmation); } public void setDeveloper_full_name (String fullname){ developer_full_name.clear(); developer_full_name.sendKeys(fullname); } public void setDeveloper_skype (String skype){ developer_skype.clear(); developer_skype.sendKeys(skype); } public void clickOnJoin(){ join_toptal_button.click(); } public boolean isPageOpened(){ //Assertion return heading.getText().toString().contains("Apply to join our network as a developer"); } }
كتابة اختبار السيلينيوم البسيط
من خلال فئات كائن الصفحة التي تمثل صفحاتنا وتفاعلات المستخدم كطرق لها ، يمكننا الآن كتابة روتين الاختبار البسيط الخاص بنا كسلسلة من استدعاءات وتأكيدات الطريقة البسيطة.
package com.toptal.tests; import com.toptal.webpages.DeveloperApplyPage; import com.toptal.webpages.DeveloperPortalPage; import com.toptal.webpages.HomePage; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.openqa.selenium.WebDriver; import org.openqa.selenium.firefox.FirefoxDriver; import java.net.URL; import java.util.concurrent.TimeUnit; public class ApplyAsDeveloperTest { WebDriver driver; @Before public void setup(){ //use FF Driver driver = new FirefoxDriver(); driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); } @Test public void applyAsDeveloper() { //Create object of HomePage Class HomePage home = new HomePage(driver); home.clickOnDeveloperApplyButton(); //Create object of DeveloperPortalPage DeveloperPortalPage devportal= new DeveloperPortalPage(driver); //Check if page is opened Assert.assertTrue(devportal.isPageOpened()); //Click on Join Toptal devportal.clikOnJoin(); //Create object of DeveloperApplyPage DeveloperApplyPage applyPage =new DeveloperApplyPage(driver); //Check if page is opened Assert.assertTrue(applyPage.isPageOpened()); //Fill up data applyPage.setDeveloper_email("[email protected]"); applyPage.setDeveloper_full_name("Dejan Zivanovic Automated Test"); applyPage.setDeveloper_password("password123"); applyPage.setDeveloper_password_confirmation("password123"); applyPage.setDeveloper_skype("automated_test_skype"); //Click on join //applyPage.clickOnJoin(); } @After public void close(){ driver.close(); } }
إجراء الاختبار
في هذه المرحلة ، يجب أن يبدو هيكل مشروعك كما يلي:
إذا كنت ترغب في إجراء الاختبار ، فحدد "ApplyAsDeveloperTest" من الشجرة ، وانقر بزر الماوس الأيمن فوقه ثم حدد Run "ApplyAsDeveloperTest" .
بمجرد تشغيل الاختبار ، يمكنك رؤية النتائج في الزاوية اليسرى السفلية من IDE الخاص بك:
خاتمة
يسهّل كائن الصفحة ومصنع الصفحة تصميم صفحات الويب في السيلينيوم واختبارها تلقائيًا وتجعل حياة كل من المطورين و QAs أكثر بساطة. عند القيام بذلك بشكل صحيح ، يمكن إعادة استخدام فئات كائن الصفحة هذه عبر مجموعة الاختبار بالكامل ولإعطاء نفسك الفرصة لتنفيذ اختبارات السيلينيوم الآلية لمشاريعك في وقت مبكر ، دون المساومة على التطوير السريع. من خلال استخلاص تفاعلات المستخدم في نماذج كائنات صفحتك والحفاظ على روتين الاختبار الخاص بك خفيفًا وبسيطًا ، يمكنك تكييف مجموعة الاختبار الخاصة بك مع المتطلبات المتغيرة بجهد ضئيل.
آمل أن أكون قد تمكنت من أن أوضح لك كيفية كتابة رمز اختبار لطيف ونظيف يسهل الحفاظ عليه. سأنهي المقال باقتباس QA المفضل لدي:
فكر مرتين ، كود مرة واحدة!