كتابة اختبارات واجهة المستخدم
في هذا القسم، يمكنك مساعدة أندي وأميتا في كتابة اختبارات Selenium التي تتحقق من سلوكيات واجهة المستخدم التي وصفتها أميتا.
تقوم أميتا عادة بإجراء الاختبارات على Chrome وFirefox وMicrosoft Edge. هنا، أنت تفعل الشيء نفسه. تم تكوين العامل المستضاف من Microsoft الذي ستستخدمه مسبقا للعمل مع كل من هذه المستعرضات.
إحضار الفرع من GitHub
في هذا القسم، يمكنك إحضار selenium
الفرع من GitHub. ثم يمكنك سحب هذا الفرع أو التبديل إليه. ستساعدك محتويات الفرع على المتابعة مع الاختبارات التي يكتبها أندي وأميتا.
يحتوي هذا الفرع على مشروع Space Game الذي عملت معه في الوحدات النمطية السابقة. كما يحتوي على تكوين Azure Pipelines للبدء به.
في Visual Studio Code، افتح المحطة الطرفية المتكاملة.
لتنزيل فرع يسمى
selenium
من مستودع Microsoft، قم بالتبديل إلى هذا الفرع، ثم قم بتشغيلgit fetch
الأوامر التالية:git checkout
git fetch upstream selenium git checkout -B selenium upstream/selenium
تلميح
إذا تابعت مع اختبار أميتا اليدوي في الوحدة السابقة، فربما قمت بتشغيل هذه الأوامر بالفعل. إذا قمت بتشغيلها بالفعل في الوحدة السابقة، فلا يزال بإمكانك تشغيلها مرة أخرى الآن.
تذكر أن المصدر يشير إلى مستودع Microsoft GitHub. يفهم تكوين Git الخاص بمشروعك جهاز التحكم عن بعد المصدر لأنك قمت بإعداد هذه العلاقة. يمكنك إعداده عند نسخ المشروع من مستودع Microsoft واستنساخه محليا.
قريبا، ستدفع هذا الفرع إلى مستودع GitHub الخاص بك، والمعروف باسم
origin
.اختياريا، في Visual Studio Code، افتح ملف azure-pipelines.yml . تعرف على التكوين الأولي.
يشبه التكوين تلك التي قمت بإنشائها في الوحدات النمطية السابقة في مسار التعلم هذا. يقوم بإنشاء تكوين إصدار التطبيق فقط. للإيجاز، فإنه يحذف أيضا المشغلات والموافقات اليدوية والاختبارات التي قمت بإعدادها في الوحدات النمطية السابقة.
إشعار
قد يحدد التكوين الأكثر قوة الفروع التي تشارك في عملية الإنشاء. على سبيل المثال، للمساعدة في التحقق من جودة التعليمات البرمجية، يمكنك تشغيل اختبارات الوحدة في كل مرة تقوم فيها بدفع تغيير على أي فرع. يمكنك أيضا نشر التطبيق في بيئة تجري اختبارا أكثر شمولا. ولكن يمكنك تنفيذ هذا التوزيع فقط، عندما يكون لديك طلب سحب، أو عندما يكون لديك إصدار المرشح، أو عندما تدمج التعليمة البرمجية في أخرى رئيسية.
لمزيد من المعلومات، راجع تنفيذ سير عمل التعليمات البرمجية في البنية الأساسية لبرنامج ربط العمليات التجارية للبناء باستخدام مشغلات Git وGitHub و Build pipeline.
كتابة التعليمات البرمجية لاختبار الوحدة
أميتا متحمسة لتعلم كتابة التعليمات البرمجية التي تتحكم في مستعرض الويب.
هي و(أندي) سيعملان معا لكتابة اختبارات (سيلينيوم). قام أندي بالفعل بإعداد مشروع NUnit فارغ. خلال العملية، يشيرون إلى وثائق Selenium، وبعض البرامج التعليمية عبر الإنترنت، والملاحظات التي أخذوها عندما أجرت أميتا الاختبارات يدويا. في نهاية هذه الوحدة النمطية، ستجد المزيد من الموارد لمساعدتك في إنجاز العملية.
دعونا نراجع العملية التي يستخدمها أندي وأميتا لكتابة اختباراتهما. يمكنك المتابعة عن طريق فتح HomePageTest.cs في دليل Tailspin.SpaceGame.Web.UITests في Visual Studio Code.
تعريف فئة HomePageTest
أندي: أول شيء نحتاج إلى القيام به هو تحديد فئة الاختبار لدينا. يمكننا اختيار اتباع أحد اصطلاحات التسمية المتعددة. دعونا نسمي صفنا HomePageTest
. في هذه الفئة، سنضع جميع اختباراتنا التي تتعلق بالصفحة الرئيسية.
يضيف أندي هذه التعليمة البرمجية إلى HomePageTest.cs:
public class HomePageTest
{
}
Andy: نحتاج إلى تحديد هذه الفئة بحيث تكون public
متاحة لإطار عمل NUnit.
إضافة متغير عضو IWebDriver
أندي: بعد ذلك، نحتاج إلى IWebDriver
متغير عضو. IWebDriver
هي واجهة البرمجة التي تستخدمها لتشغيل مستعرض ويب والتفاعل مع محتوى صفحة الويب.
أميتا: لقد سمعت عن واجهات في البرمجة. هل يمكنك إخباري بالمزيد؟
أندي: فكر في الواجهة كمواصفات أو مخطط لكيفية تصرف المكون. توفر الواجهة أساليب أو سلوكيات هذا المكون. ولكن الواجهة لا توفر أيا من التفاصيل الأساسية. ستقوم أنت أو شخص آخر بإنشاء فئة واحدة أو أكثر من الفئات الملموسة التي تنفذ هذه الواجهة. يوفر السيلينيوم الفئات الملموسة التي نحتاجها.
يوضح هذا الرسم التخطيطي الواجهة IWebDriver
وبعض الفئات التي تنفذ هذه الواجهة:
يوضح الرسم التخطيطي ثلاثة من الطرق التي IWebDriver
توفر: Navigate
و FindElement
و Close
.
الفئات الثلاث الموضحة هنا، ChromeDriver
و FirefoxDriver
، و، و EdgeDriver
، كل تنفيذ IWebDriver
وأساليبه. هناك فئات أخرى، مثل SafariDriver
، التي تنفذ IWebDriver
أيضا . يمكن لكل فئة برنامج تشغيل التحكم في مستعرض الويب الذي تمثله.
يضيف أندي متغير عضو يسمى driver
إلى الفئة، مثل هذه التعليمة البرمجية HomePageTest
:
public class HomePageTest
{
private IWebDriver driver;
}
تحديد تركيبات الاختبار
أندي: نريد إجراء مجموعة كاملة من الاختبارات على Chrome وFirefox وEdge. في NUnit، يمكننا استخدام تركيبات الاختبار لتشغيل مجموعة كاملة من الاختبارات عدة مرات، مرة واحدة لكل متصفح نريد اختباره.
في NUnit، يمكنك استخدام السمة TestFixture
لتحديد تركيبات الاختبار الخاصة بك. يضيف أندي هذه التركيبات الاختبارية الثلاثة إلى HomePageTest
الفئة:
[TestFixture("Chrome")]
[TestFixture("Firefox")]
[TestFixture("Edge")]
public class HomePageTest
{
private IWebDriver driver;
}
أندي: بعد ذلك، نحتاج إلى تحديد منشئ لفئة الاختبار الخاصة بنا. يتم استدعاء الدالة الإنشائية عندما يقوم NUnit بإنشاء مثيل لهذه الفئة. كوسيطة لها، يأخذ الدالة الإنشائية السلسلة التي أرفقناها بمثبتات الاختبار الخاصة بنا. إليك الشكل الذي تبدو عليه التعليمات البرمجية:
[TestFixture("Chrome")]
[TestFixture("Firefox")]
[TestFixture("Edge")]
public class HomePageTest
{
private string browser;
private IWebDriver driver;
public HomePageTest(string browser)
{
this.browser = browser;
}
}
أندي: أضفنا متغير العضو حتى نتمكن من استخدام اسم المستعرض الحالي في التعليمة البرمجية browser
للإعداد. لنكتب التعليمة البرمجية للإعداد بعد ذلك.
تعريف أسلوب الإعداد
أندي: بعد ذلك، نحتاج إلى تعيين متغير العضو الخاص بنا IWebDriver
إلى مثيل فئة ينفذ هذه الواجهة للمتصفح الذي نختبر عليه. ChromeDriver
FirefoxDriver
تنفذ الفئات و و EdgeDriver
هذه الواجهة ل Chrome وFirefox وEdge على التوالي.
دعونا ننشئ أسلوبا يسمى Setup
الذي يعين driver
المتغير. نستخدم السمة OneTimeSetUp
لإخبار NUnit بتشغيل هذه الطريقة مرة واحدة لكل مثبت اختبار.
[OneTimeSetUp]
public void Setup()
{
}
في Setup
الأسلوب ، يمكننا استخدام عبارة switch
لتعيين driver
متغير العضو إلى التنفيذ الملموس المناسب بناء على اسم المتصفح. دعونا نضيف هذه التعليمة البرمجية الآن.
// Create the driver for the current browser.
switch(browser)
{
case "Chrome":
driver = new ChromeDriver(
Environment.GetEnvironmentVariable("ChromeWebDriver")
);
break;
case "Firefox":
driver = new FirefoxDriver(
Environment.GetEnvironmentVariable("GeckoWebDriver")
);
break;
case "Edge":
driver = new EdgeDriver(
Environment.GetEnvironmentVariable("EdgeWebDriver"),
new EdgeOptions
{
UseChromium = true
}
);
break;
default:
throw new ArgumentException($"'{browser}': Unknown browser");
}
تأخذ الدالة الإنشائية لكل فئة برنامج تشغيل مسارا اختياريا إلى برنامج التشغيل الذي يحتاجه Selenium للتحكم في مستعرض الويب. لاحقا، سنناقش دور متغيرات البيئة الموضحة هنا.
في هذا المثال، يتطلب المنشئ EdgeDriver
أيضا خيارات إضافية لتحديد أننا نريد استخدام إصدار Chromium من Edge.
تعريف أساليب المساعد
أندي: أعلم أننا سنحتاج إلى تكرار إجراءين خلال الاختبارات:
- البحث عن عناصر على الصفحة، مثل الارتباطات التي نضغط عليها والنوافذ المشروطة التي نتوقع ظهورها
- النقر فوق عناصر على الصفحة، مثل الارتباطات التي تكشف عن النوافذ المشروطة والزر الذي يغلق كل نموذج
دعونا نكتب طريقتين مساعدتين، واحدة لكل إجراء. سنبدأ بالأسلوب الذي يعثر على عنصر على الصفحة.
كتابة أسلوب مساعد FindElement
عند تحديد موقع عنصر على الصفحة، عادة ما يكون استجابة لحدث آخر، مثل تحميل الصفحة أو إدخال المستخدم للمعلومات. يوفر WebDriverWait
Selenium الفئة ، والتي تسمح لك بالانتظار حتى يكون الشرط صحيحا. إذا لم يكن الشرط صحيحا خلال الفترة الزمنية المحددة، WebDriverWait
يطرح استثناء أو خطأ. يمكننا استخدام WebDriverWait
الفئة لانتظار عرض عنصر معين وأن نكون مستعدين لتلقي إدخال المستخدم.
لتحديد موقع عنصر على الصفحة، استخدم By
الفئة . By
توفر الفئة أساليب تتيح لك العثور على عنصر باسمه، أو باسم فئة CSS الخاصة به، أو بواسطة علامة HTML الخاصة به، أو في حالتنا، بواسطة سمتهid
.
يقوم أندي وأميتا بالتعليمة البرمجية FindElement
لأسلوب المساعد. يبدو مثل هذه التعليمة البرمجية:
private IWebElement FindElement(By locator, IWebElement parent = null, int timeoutSeconds = 10)
{
// WebDriverWait enables us to wait for the specified condition to be true
// within a given time period.
return new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutSeconds))
.Until(c => {
IWebElement element = null;
// If a parent was provided, find its child element.
if (parent != null)
{
element = parent.FindElement(locator);
}
// Otherwise, locate the element from the root of the DOM.
else
{
element = driver.FindElement(locator);
}
// Return true after the element is displayed and is able to receive user input.
return (element != null && element.Displayed && element.Enabled) ? element : null;
});
}
كتابة أسلوب مساعد ClickElement
أندي: بعد ذلك، دعنا نكتب أسلوب مساعد ينقر فوق الارتباطات. يوفر Selenium بعض الطرق لكتابة هذا الأسلوب. واحدة منها هي الواجهة IJavaScriptExecutor
. باستخدامه، يمكننا النقر فوق الارتباطات برمجيا باستخدام JavaScript. يعمل هذا الأسلوب بشكل جيد لأنه يمكنه النقر فوق الارتباطات دون تمريرها أولا إلى طريقة العرض.
ChromeDriver
، FirefoxDriver
، وكل EdgeDriver
منها ينفذ IJavaScriptExecutor
. نحتاج إلى تحويل برنامج التشغيل إلى هذه الواجهة ثم استدعاء ExecuteScript
لتشغيل أسلوب JavaScript click()
على كائن HTML الأساسي.
يقوم أندي وأميتا بالتعليمة البرمجية ClickElement
لأسلوب المساعد. يبدو مثل هذه التعليمة البرمجية:
private void ClickElement(IWebElement element)
{
// We expect the driver to implement IJavaScriptExecutor.
// IJavaScriptExecutor enables us to execute JavaScript code during the tests.
IJavaScriptExecutor js = driver as IJavaScriptExecutor;
// Through JavaScript, run the click() method on the underlying HTML object.
js.ExecuteScript("arguments[0].click();", element);
}
أميتا: أحب فكرة إضافة هذه الأساليب المساعدة. تبدو عامة بما يكفي لاستخدامها في أي اختبار تقريبا. يمكننا إضافة المزيد من أساليب المساعد لاحقا كما نحتاج إليها.
تعريف أسلوب الاختبار
أندي: الآن، نحن مستعدون لتحديد أسلوب الاختبار. بناء على الاختبارات اليدوية التي أجريناها سابقا، دعنا نسمي هذا الأسلوب ClickLinkById_ShouldDisplayModalById
. من الممارسات الجيدة إعطاء أساليب الاختبار أسماء وصفية تحدد بدقة ما يحققه الاختبار. هنا، نريد النقر فوق ارتباط محدد بواسطة السمة الخاصة به id
. ثم نريد التحقق من ظهور النافذة المشروطة المناسبة، أيضا باستخدام سمتها id
.
يضيف أندي رمز البداية لأسلوب الاختبار:
public void ClickLinkById_ShouldDisplayModalById(string linkId, string modalId)
{
}
أندي: قبل أن نضيف المزيد من التعليمات البرمجية، دعنا نحدد ما يجب أن يفعله هذا الاختبار.
أميتا: يمكنني التعامل مع هذا الجزء. نريد:
- حدد موقع الارتباط حسب السمة الخاصة به
id
ثم انقر فوق الارتباط. - حدد موقع المشروط الناتج.
- أغلق المشروط.
- تحقق من عرض المشروط بنجاح.
أندي: عظيم. سنحتاج أيضا إلى التعامل مع بعض الأشياء الأخرى. على سبيل المثال، نحتاج إلى تجاهل الاختبار إذا تعذر تحميل برنامج التشغيل، ونحتاج إلى إغلاق المشروط فقط إذا تم عرض المشروط بنجاح.
بعد إعادة تعبئة أكواب القهوة الخاصة بهم، يضيف أندي وأميتا تعليمة برمجية إلى أسلوب الاختبار الخاص بهم. يستخدمون أساليب المساعد التي كتبوها لتحديد موقع عناصر الصفحة والنقر فوق الارتباطات والأزرار. إليك النتيجة:
public void ClickLinkById_ShouldDisplayModalById(string linkId, string modalId)
{
// Skip the test if the driver could not be loaded.
// This happens when the underlying browser is not installed.
if (driver == null)
{
Assert.Ignore();
return;
}
// Locate the link by its ID and then click the link.
ClickElement(FindElement(By.Id(linkId)));
// Locate the resulting modal.
IWebElement modal = FindElement(By.Id(modalId));
// Record whether the modal was successfully displayed.
bool modalWasDisplayed = (modal != null && modal.Displayed);
// Close the modal if it was displayed.
if (modalWasDisplayed)
{
// Click the close button that's part of the modal.
ClickElement(FindElement(By.ClassName("close"), modal));
// Wait for the modal to close and for the main page to again be clickable.
FindElement(By.TagName("body"));
}
// Assert that the modal was displayed successfully.
// If it wasn't, this test will be recorded as failed.
Assert.That(modalWasDisplayed, Is.True);
}
أميتا: يبدو الترميز رائعا حتى الآن. ولكن كيف يمكننا توصيل هذا الاختبار بالسمات id
التي جمعناها سابقا؟
أندي: سؤال رائع. سنتعامل مع ذلك بعد ذلك.
تعريف بيانات حالة الاختبار
أندي: في NUnit، يمكنك توفير البيانات لاختباراتك بعدة طرق. هنا، نستخدم السمة TestCase
. تأخذ هذه السمة الوسيطات التي تمررها لاحقا إلى أسلوب الاختبار عند تشغيلها. يمكن أن يكون لدينا سمات متعددة TestCase
يختبر كل منها ميزة مختلفة لتطبيقنا. تنتج كل TestCase
سمة حالة اختبار مضمنة في التقرير الذي يظهر في نهاية تشغيل البنية الأساسية لبرنامج ربط العمليات التجارية.
يضيف أندي هذه TestCase
السمات إلى أسلوب الاختبار. تصف هذه السمات زر تنزيل اللعبة ، وأحد شاشات اللعبة، وأعلى لاعب على لوحة المتصدرين. تحدد كل سمة سمتين id
: واحدة للارتباط للنقر والأخرى للنافذة المشروطة المقابلة.
// Download game
[TestCase("download-btn", "pretend-modal")]
// Screen image
[TestCase("screen-01", "screen-modal")]
// // Top player on the leaderboard
[TestCase("profile-1", "profile-modal-1")]
public void ClickLinkById_ShouldDisplayModalById(string linkId, string modalId)
{
...
Andy: لكل سمات TestCase
، تكون المعلمة الأولى هي سمة id
للارتباط التي يجب النقر فوقها. المعلمة الثانية هي السمة id
للنافذة المشروطة التي نتوقع ظهورها. يمكنك أن ترى كيف تتوافق هذه المعلمات مع الوسيطات المكونة من سلسلتين في أسلوب الاختبار الخاص بنا.
أميتا: أرى ذلك. مع بعض التدريب، أعتقد أنه يمكنني إضافة اختباراتي الخاصة. متى يمكننا رؤية هذه الاختبارات قيد التشغيل في البنية الأساسية لبرنامج ربط العمليات التجارية لدينا؟
أندي: قبل أن ندفع التغييرات عبر البنية الأساسية لبرنامج ربط العمليات التجارية، دعنا أولا نتحقق من أن التعليمات البرمجية تقوم بالتحويل البرمجي وتشغيلها محليا. سنلتزم بالتغييرات وندفعها إلى GitHub ونراها تتحرك عبر البنية الأساسية لبرنامج ربط العمليات التجارية فقط بعد التحقق من أن كل شيء يعمل. دعونا نجري الاختبارات محليا الآن.