Menulis pengujian antarmuka pengguna

Selesai

Di bagian ini, Anda membantu Andy dan Amita menulis tes Selenium yang memverifikasi perilaku antarmuka pengguna yang dijelaskan Amita.

Amita biasanya menjalankan pengujian di Chrome, Firefox, dan Microsoft Edge. Di sini, Anda melakukan hal yang sama. Agen yang dihosting Microsoft yang akan Anda gunakan telah dikonfigurasi sebelumnya untuk bekerja dengan masing-masing browser ini.

Ambil cabang dari GitHub

Di bagian ini, Anda mengambil cabang selenium dari GitHub. Anda kemudian memeriksa, atau beralih ke, cabang itu. Isi cabang akan membantu Anda mengikuti tes yang ditulis Andy dan Amita.

Cabang ini berisi proyek Space Game yang anda kerjakan di modul sebelumnya. Ini juga berisi konfigurasi Azure Pipelines untuk memulai.

  1. Di Visual Studio Code, buka terminal terintegrasi.

  2. Untuk mengunduh cabang bernama selenium dari repositori Microsoft, beralihlah ke cabang tersebut, dan jalankan perintah git fetch dan git checkout berikut:

    git fetch upstream selenium
    git checkout -B selenium upstream/selenium
    

    Tip

    Jika Anda mengikuti tes manual Amita di unit sebelumnya, Anda mungkin sudah menjalankan perintah ini. Jika Anda sudah menjalankannya di unit sebelumnya, Anda mungkin masih menjalankannya lagi sekarang.

    Ingat bahwa upstram mengacu pada repositori Microsoft GitHub. Konfigurasi Git proyek Anda memahami jarak jauh upstram karena Anda menyiapkan hubungan tersebut. Anda menyiapkannya saat Anda membuat fork proyek dari repositori Microsoft dan mengkloningnya secara lokal.

    Setelahnya, Anda akan mendorong cabang ini ke repositori GitHub Anda, yang dikenal sebagai origin.

  3. Secara opsional, di Visual Studio Code, buka file azure-pipelines.yml. Biasakan diri Anda dengan konfigurasi awal.

    Konfigurasi menyerupai dengan yang Anda buat di modul sebelumnya di jalur pembelajaran ini. Ini hanya membangun konfigurasi Rilis aplikasi. Singkatnya, ini juga menghilangkan pemicu, persetujuan manual, dan pengujian yang Anda siapkan di modul sebelumnya.

    Catatan

    Konfigurasi yang lebih kuat mungkin menentukan cabang yang berpartisipasi dalam proses build. Misalnya, untuk membantu memverifikasi kualitas kode, Anda dapat menjalankan pengujian unit setiap kali Anda mendorong perubahan pada cabang mana pun. Anda mungkin juga menyebarkan aplikasi ke lingkungan yang melakukan pengujian yang lebih lengkap. Namun, Anda melakukan penyebaran ini hanya ketika Anda memiliki permintaan pull, ketika Anda memiliki kandidat rilis, atau ketika Anda menggabungkan kode ke utama.

    Untuk informasi selengkapnya, lihat Menerapkan alur kerja kode di alur build Anda dengan menggunakan Git dan GitHub dan pemicu alur build.

Menulis kode pengujian unit

Amita sangat senang belajar menulis kode yang mengontrol browser web.

Dia dan Andy akan bekerja sama untuk menulis tes Selenium. Andy telah menyiapkan proyek NUnit kosong. Sepanjang proses, mereka merujuk ke dokumentasi Selenium, beberapa tutorial online, dan catatan yang mereka ambil ketika Amita melakukan tes secara manual. Di akhir modul ini, Anda akan menemukan banyak sumber daya untuk membantu Anda melewati proses.

Mari kita tinjau proses yang digunakan Andy dan Amita untuk menulis tes mereka. Anda dapat mengikuti dengan membuka HomePageTest.cs di direktori Tailspin.SpaceGame.Web.UITests di Visual Studio Code.

Tentukan kelas HomePageTest

Andy: Hal pertama yang perlu kita lakukan adalah mendefinisikan kelas pengujian kita. Kita dapat memilih untuk mengikuti salah satu dari beberapa konvensi penamaan. Mari kita panggil kelas HomePageTest kita. Di kelas ini, kita akan menempatkan semua tes yang berhubungan dengan halaman beranda.

Andy menambahkan kode ini ke HomePageTest.cs:

public class HomePageTest
{
}

Andy: Kita perlu menandai kelas public ini agar tersedia untuk kerangka kerja NUnit.

Menambahkan variabel anggota IWebDriver

Andy: Selanjutnya, kita memerlukan IWebDriver variabel anggota. IWebDriver adalah antarmuka pemrograman yang Anda gunakan untuk meluncurkan browser web dan berinteraksi dengan konten halaman web.

Amita: Saya pernah mendengar antarmuka dalam pemrograman. Bisa kau ceritakan lebih banyak?

Andy: Anggap antarmuka sebagai spesifikasi atau cetak biru tentang bagaimana komponen harus ber perilaku. Antarmuka menyediakan metode, atau perilaku, dari komponen tersebut. Tetapi antarmuka tidak memberikan detail yang mendasar. Anda atau orang lain akan membuat satu atau beberapa kelas konkret yang mengimplementasikan antarmuka tersebut. Selenium menyediakan kelas konkret yang kita butuhkan.

Diagram IWebDriver ini menunjukkan antarmuka dan beberapa kelas yang mengimplementasikan antarmuka ini:

Diagram of the IWebDriver interface, its methods, and concrete classes.

Diagram menunjukkan tiga metode yang IWebDriver menyediakan: Navigate, FindElement dan Close.

Tiga kelas yang ditampilkan di sini, ChromeDriver, FirefoxDriver, dan EdgeDriver, masing-masing mengimplementasikan IWebDriver dan metodenya. Ada kelas lain, seperti SafariDriver, yang juga mengimplementasikan IWebDriver. Setiap kelas driver dapat mengontrol browser web yang diwakilinya.

Andy menambahkan variabel anggota bernama driver ke HomePageTest kelas , seperti kode ini:

public class HomePageTest
{
    private IWebDriver driver;
}

Tentukan perlengkapan pengujian

Andy: Kami ingin menjalankan seluruh rangkaian pengujian di Chrome, Firefox, dan Edge. Di NUnit, kita dapat menggunakan perlengkapan pengujian untuk menjalankan seluruh rangkaian pengujian beberapa kali, satu kali untuk setiap browser yang ingin kita uji.

Di NUnit, Anda menggunakan atribut TestFixture untuk menentukan perlengkapan pengujian Anda. Andy menambahkan ketiga perlengkapan uji ini ke kelas HomePageTest:

[TestFixture("Chrome")]
[TestFixture("Firefox")]
[TestFixture("Edge")]
public class HomePageTest
{
    private IWebDriver driver;
}

Andy: Selanjutnya, kita perlu menentukan konstruktor untuk kelas pengujian kita. Konstruktor dipanggil ketika NUnit membuat instans kelas ini. Sebagai argumennya, konstruktor mengambil string yang kami lampirkan ke perlengkapan pengujian kami. Berikut tampilan kodenya:

[TestFixture("Chrome")]
[TestFixture("Firefox")]
[TestFixture("Edge")]
public class HomePageTest
{
    private string browser;
    private IWebDriver driver;

    public HomePageTest(string browser)
    {
        this.browser = browser;
    }
}

Andy: Kami menambahkan browser variabel anggota sehingga kami dapat menggunakan nama browser saat ini dalam kode penyiapan kami. Mari kita tulis kode penyiapan berikutnya.

Tentukan metode Penyiapan

Andy: Selanjutnya, kita perlu menetapkan variabel anggota kita IWebDriver ke instans kelas yang mengimplementasikan antarmuka ini untuk browser yang sedang kita uji. Kelas ChromeDriver, FirefoxDriver, dan EdgeDriver mengimplementasikan antarmuka ini untuk Chrome, Firefox, dan Edge, masing-masing.

Mari kita buat metode bernama Setup yang mengatur driver variabel. Kami menggunakan atribut OneTimeSetUp untuk memberi tahu NUnit untuk menjalankan metode ini satu kali per perlengkapan pengujian.

[OneTimeSetUp]
public void Setup()
{
}

Dalam metode ini Setup , kita dapat menggunakan switch pernyataan untuk menetapkan driver variabel anggota ke implementasi konkret yang sesuai berdasarkan nama browser. Mari kita tambahkan kode itu sekarang.

// 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");
}

Konstruktor untuk setiap kelas driver mengambil jalur opsional ke perangkat lunak driver yang diperlukan Selenium untuk mengontrol browser web. Nantinya, kita akan membahas peran variabel lingkungan yang ditampilkan di sini.

Dalam contoh ini, konstruktor EdgeDriver juga memerlukan opsi tambahan untuk menentukan bahwa kita ingin menggunakan versi Chromium Edge.

Menentukan metode pembantu

Andy: Aku tahu kita harus mengulangi dua tindakan selama tes:

  • Menemukan elemen di halaman, seperti tautan yang kami klik dan jendela modal yang kami harapkan muncul
  • Mengklik elemen pada halaman, seperti tautan yang mengungkapkan jendela modal dan tombol yang menutup setiap modal

Mari kita tulis dua metode pembantu, satu untuk setiap tindakan. Kita akan mulai dengan metode yang menemukan elemen di halaman.

Tulis metode pembantu FindElement

Saat Anda menemukan elemen di halaman, elemen biasanya menanggapi beberapa peristiwa lain, seperti pemuatan halaman atau pengguna yang memasukkan informasi. Selenium menyediakan WebDriverWait kelas , yang memungkinkan Anda untuk menunggu kondisi menjadi benar. Jika kondisi tidak benar dalam periode waktu tertentu, WebDriverWait melemparkan pengecualian atau kesalahan. Kita dapat menggunakan kelas WebDriverWait untuk menunggu elemen tertentu ditampilkan dan siap menerima input pengguna.

Untuk menemukan elemen di halaman, gunakan By kelas . Kelas ini By menyediakan metode yang memungkinkan Anda menemukan elemen berdasarkan namanya, dengan nama kelas CSS-nya, dengan tag HTML-nya, atau dalam kasus kami, dengan atributnya id .

Andy dan Amita membuat kode metode pembantu FindElement. Sepertinya kode ini:

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;
        });
}

Menulis metode pembantu ClickElement

Andy: Selanjutnya, mari kita tulis metode pembantu yang mengklik tautan. Selenium menyediakan beberapa cara untuk menulis metode itu. Salah satunya adalah antarmuka IJavaScriptExecutor. Dengan itu, kita dapat mengklik tautan secara terprogram dengan menggunakan JavaScript. Pendekatan ini berfungsi dengan baik karena dapat mengklik tautan tanpa terlebih dahulu menggulirnya ke tampilan.

ChromeDriver, FirefoxDriver, dan EdgeDriver masing-masing mengimplementasikan IJavaScriptExecutor. Kita perlu melemparkan driver ke antarmuka ini dan kemudian memanggil ExecuteScript untuk menjalankan metode click() JavaScript pada objek HTML yang mendasarinya.

Andy dan Amita membuat kode metode pembantu ClickElement. Sepertinya kode ini:

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);
}

Amita: Saya suka ide menambahkan metode pembantu ini. Mereka tampaknya cukup umum untuk digunakan dalam hampir semua tes. Kita dapat menambahkan lebih banyak metode pembantu nanti karena kita membutuhkannya.

Tentukan metode pengujian

Andy: Sekarang, kami siap untuk menentukan metode pengujian. Berdasarkan tes manual yang kita jalankan sebelumnya, mari kita sebut metode ClickLinkById_ShouldDisplayModalById ini. Ini adalah praktik yang baik untuk memberikan metode pengujian nama deskriptif yang menentukan dengan tepat apa yang dicapai pengujian. Di sini, kita ingin mengklik tautan yang ditentukan oleh atributnya id . Kemudian kita ingin memverifikasi bahwa jendela modal yang tepat muncul, juga dengan menggunakan atributnya id .

Andy menambahkan kode pemula untuk metode pengujian:

public void ClickLinkById_ShouldDisplayModalById(string linkId, string modalId)
{
}

Andy: Sebelum kita menambahkan lebih banyak kode, mari kita tentukan apa yang harus dilakukan pengujian ini.

Amita: Aku bisa menangani bagian ini. Kami ingin:

  1. Temukan tautan berdasarkan atribut id nya lalu klik tautan.
  2. Temukan modal yang dihasilkan.
  3. Tutup modal.
  4. Verifikasi bahwa modal berhasil ditampilkan.

Andy: Hebat. Kita juga perlu menangani beberapa hal lainnya. Misalnya, kita perlu mengabaikan tes jika driver tidak dapat dimuat, dan kita perlu menutup modal hanya jika modal berhasil ditampilkan.

Setelah mengisi ulang cangkir kopi mereka, Andy dan Amita menambahkan kode ke metode pengujian mereka. Mereka menggunakan metode pembantu yang mereka tulis untuk menemukan elemen halaman dan mengklik tautan dan tombol. Berikut hasilnya:

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);
}

Amita: Pengodeannya terlihat bagus sejauh ini. Tetapi bagaimana cara menghubungkan pengujian ini ke atribut id yang kami kumpulkan sebelumnya?

Andy: Pertanyaan bagus. Kami akan menghandel selanjutnya.

Menentukan data kasus pengujian

Andy: Di NUnit, Anda dapat memberikan data ke pengujian Anda dalam beberapa cara. Di sini, kita menggunakan TestCase atribut . Atribut ini mengambil argumen yang kemudian diteruskan kembali ke metode pengujian saat dijalankan. Kita dapat memiliki beberapa atribut TestCase yang masing-masing menguji fitur yang berbeda dari aplikasi kita. Setiap atribut TestCase menghasilkan kasus uji yang disertakan dalam laporan yang muncul di akhir proses pipeline.

Andy menambahkan atribut TestCase ini ke metode pengujian. Atribut ini menggambarkan tombol Unduh game, salah satu layar game, dan pemain teratas di papan peringkat. Setiap atribut menentukan dua atribut id: satu untuk tautan yang akan diklik dan satu untuk jendela modal yang sesuai.

// 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: Untuk setiap atribut TestCase, parameter pertama adalah atribut id untuk tautan yang akan diklik. Parameter kedua adalah atribut id untuk jendela modal yang kami harapkan muncul. Anda dapat melihat bagaimana parameter ini sesuai dengan argumen dua string dalam metode pengujian kami.

Amita: Saya melihatnya. Dengan beberapa latihan, saya pikir saya bisa menambahkan tes saya sendiri. Kapan kita dapat melihat pengujian ini berjalan di alur kita?

Andy: Sebelum kita mendorong perubahan melalui alur, mari kita verifikasi terlebih dahulu bahwa kode mengompilasi dan berjalan secara lokal. Kami akan menerapkan dan mendorong perubahan ke GitHub dan melihatnya bergerak melalui alur hanya setelah kami memverifikasi bahwa semuanya berfungsi. Mari kita jalankan tes secara lokal sekarang.