Bagikan melalui


Menguji aplikasi MVC Core ASP.NET

Petunjuk / Saran

Konten ini adalah kutipan dari eBook, Architect Modern Web Applications dengan ASP.NET Core dan Azure, tersedia di .NET Docs atau sebagai PDF gratis yang dapat diunduh yang dapat dibaca secara offline.

Rancang Aplikasi Web Modern dengan ASP.NET Core dan Azure eBook gambar mini sampul.

"Jika Anda tidak suka pengujian unit untuk produk Anda, kemungkinan besar pelanggan Anda juga tidak ingin mengujinya." _-Anonim-

Perangkat lunak dari kompleksitas apa pun dapat gagal dengan cara yang tidak terduga sebagai respons terhadap perubahan. Dengan demikian, pengujian setelah membuat perubahan diperlukan untuk semua tetapi aplikasi yang paling sepele (atau paling tidak penting). Pengujian manual adalah cara paling lambat, paling tidak dapat diandalkan, paling mahal untuk menguji perangkat lunak. Sayangnya, jika aplikasi tidak dirancang untuk dapat diuji, itu bisa menjadi satu-satunya cara pengujian yang tersedia. Aplikasi yang ditulis untuk mengikuti prinsip arsitektur yang ditata dalam bab 4 sebagian besar harus dapat diuji secara unit. aplikasi ASP.NET Core mendukung integrasi otomatis dan pengujian fungsional.

Jenis pengujian otomatis

Ada banyak jenis pengujian otomatis untuk aplikasi perangkat lunak. Pengujian tingkat paling sederhana dan terendah adalah pengujian unit. Pada tingkat yang sedikit lebih tinggi, ada pengujian integrasi dan pengujian fungsi. Jenis pengujian lain, seperti pengujian UI, uji beban, tes stres, dan uji asap, berada di luar cakupan dokumen ini.

Pengujian unit

Uji komponen menguji satu bagian dari logika aplikasi Anda. Seseorang dapat menjelaskannya lebih lanjut dengan mencantumkan beberapa hal yang tidak ada. Pengujian unit tidak menguji cara kerja kode Anda dengan dependensi atau infrastruktur – itulah tujuan pengujian integrasi. Pengujian unit tidak menguji kerangka kerja yang ditulis kode Anda - Anda harus menganggapnya berfungsi atau, jika Anda menemukannya tidak, ajukan bug dan kode solusi. Pengujian unit berjalan sepenuhnya dalam memori dan dalam proses. Ini tidak berkomunikasi dengan sistem file, jaringan, atau database. Pengujian unit hanya boleh menguji kode Anda.

Pengujian unit, berdasarkan fakta bahwa mereka hanya menguji satu unit kode Anda, tanpa dependensi eksternal, harus dijalankan dengan sangat cepat. Dengan demikian, Anda harus dapat menjalankan rangkaian pengujian ratusan pengujian unit dalam beberapa detik. Jalankan secara sering, idealnya sebelum setiap dorongan ke repositori kontrol sumber bersama, dan tentu saja dengan setiap build otomatis di server build Anda.

Uji Integrasi

Meskipun ada baiknya untuk merangkum kode Anda yang berinteraksi dengan infrastruktur seperti database dan sistem file, Anda masih akan memiliki beberapa kode itu, dan Anda mungkin ingin mengujinya. Selain itu, Anda harus memverifikasi bahwa lapisan kode Anda berinteraksi seperti yang Anda harapkan ketika dependensi aplikasi Anda diselesaikan sepenuhnya. Fungsionalitas ini adalah tanggung jawab pengujian integrasi. Pengujian integrasi cenderung lebih lambat dan lebih sulit disiapkan daripada pengujian unit, karena sering bergantung pada dependensi dan infrastruktur eksternal. Dengan demikian, Anda harus menghindari pengujian hal-hal yang dapat diuji dengan pengujian unit dalam pengujian integrasi. Jika Anda dapat menguji skenario tertentu dengan pengujian unit, Anda harus mengujinya dengan pengujian unit. Jika tidak dapat, maka pertimbangkan untuk menggunakan pengujian integrasi.

Pengujian integrasi akan sering memiliki prosedur penyiapan dan teardown yang lebih kompleks daripada pengujian unit. Misalnya, pengujian integrasi yang bertentangan dengan database aktual akan memerlukan cara untuk mengembalikan database ke status yang diketahui sebelum setiap pengujian dijalankan. Saat pengujian baru ditambahkan dan skema database produksi berkembang, skrip pengujian ini akan cenderung tumbuh dalam ukuran dan kompleksitas. Dalam banyak sistem besar, tidak praktis untuk menjalankan rangkaian lengkap pengujian integrasi pada stasiun kerja pengembang sebelum memeriksa perubahan pada kontrol sumber bersama. Dalam kasus ini, pengujian integrasi dapat dijalankan pada server build.

Tes fungsi

Pengujian integrasi ditulis dari perspektif pengembang, untuk memverifikasi bahwa beberapa komponen sistem bekerja dengan benar bersama-sama. Tes fungsional ditulis dari perspektif pengguna, dan memverifikasi kebenaran sistem berdasarkan persyaratannya. Kutipan berikut menawarkan analogi yang berguna tentang cara memikirkan tes fungsi, dibandingkan dengan pengujian unit:

"Sering kali pengembangan sistem diibaratkan dengan bangunan rumah. Meskipun analogi ini tidak cukup benar, kita dapat memperluasnya untuk tujuan memahami perbedaan antara unit dan tes fungsi. Pengujian unit dianalogikan dengan inspektur bangunan yang mengunjungi lokasi konstruksi rumah. Ia berfokus pada berbagai sistem internal rumah, fondasi, pembingkaian, listrik, pipa, dan sebagainya. Dia memastikan (tes) bahwa bagian-bagian rumah akan bekerja dengan benar dan aman, yaitu memenuhi kode bangunan. Pengujian fungsional dalam skenario ini dianalogikan dengan pemilik rumah yang mengunjungi lokasi konstruksi yang sama ini. Dia berasumsi bahwa sistem internal akan bersifat tepat, bahwa inspektur bangunan menjalankan tugasnya. Pemilik rumah berfokus pada bagaimana rasanya tinggal di rumah ini. Dia memperhatikan bagaimana rumah terlihat, apakah ukuran berbagai kamar nyaman, apakah rumah tersebut memenuhi kebutuhan keluarga, apakah jendelanya berada di tempat yang tepat untuk menangkap matahari pagi. Pemilik rumah melakukan tes fungsional pada rumah. Dia memiliki perspektif pengguna. Inspektur bangunan sedang melakukan pengujian unit pada rumah. Dia memiliki perspektif pembangun."

Sumber: Pengujian Unit versus Uji Fungsi

Saya suka mengatakan "Sebagai pengembang, kami gagal dengan dua cara: kami membangun hal yang salah, atau kami membangun hal yang salah." Pengujian unit memastikan Anda membangun hal yang benar; tes fungsian memastikan Anda membangun hal yang benar.

Karena pengujian fungsional beroperasi pada tingkat sistem, pengujian mungkin memerlukan beberapa tingkat otomatisasi UI. Seperti pengujian integrasi, mereka biasanya bekerja dengan beberapa jenis infrastruktur pengujian juga. Aktivitas ini membuatnya lebih lambat dan lebih rapuh daripada pengujian unit dan integrasi. Anda harus memiliki tes fungsi sebanyak yang Anda butuhkan untuk yakin sistem berperilaku seperti yang diharapkan pengguna.

Menguji Piramida

Martin Fowler menulis tentang piramida pengujian, contohnya ditunjukkan pada Gambar 9-1.

Menguji Piramida

Gambar 9-1. Menguji Piramida

Berbagai lapisan piramida, dan ukuran relatifnya, mewakili berbagai jenis tes dan berapa banyak Anda harus menulis untuk aplikasi Anda. Seperti yang Anda lihat, rekomendasinya adalah memiliki basis besar pengujian unit, yang didukung oleh lapisan pengujian integrasi yang lebih kecil, dengan lapisan pengujian fungsional yang lebih kecil. Setiap lapisan idealnya hanya memiliki tes di dalamnya yang tidak dapat dilakukan secara memadai pada lapisan yang lebih rendah. Ingatlah piramida pengujian ketika Anda mencoba memutuskan jenis pengujian mana yang Anda butuhkan untuk skenario tertentu.

Apa yang harus diuji

Masalah umum bagi pengembang yang belum berpengalaman menulis pengujian otomatis adalah menentukan apa yang harus diuji. Titik awal yang baik adalah menguji logika bersyarat. Kapan pun Anda memiliki metode dengan perilaku yang berubah berdasarkan pernyataan kondisional (if-else, switch, dan sebagainya), Anda harus dapat membuat setidaknya beberapa pengujian yang mengonfirmasi perilaku yang benar untuk kondisi tertentu. Jika kode Anda memiliki kondisi kesalahan, ada baiknya untuk menulis setidaknya satu pengujian untuk "jalur bahagia" yang melalui kode tanpa kesalahan, dan setidaknya satu pengujian untuk "jalur sedih" dengan kesalahan atau hasil atipikal, untuk mengonfirmasi aplikasi Anda berperilaku seperti yang diharapkan dalam kondisi kesalahan. Terakhir, cobalah untuk fokus pada pengujian hal-hal yang dapat gagal, daripada berfokus pada metrik seperti cakupan kode. Cakupan kode yang lebih banyak lebih baik daripada yang lebih sedikit, umumnya. Namun, menulis beberapa pengujian lagi dari metode yang kompleks dan penting bagi bisnis biasanya merupakan penggunaan waktu yang lebih baik daripada menulis pengujian untuk properti otomatis hanya untuk meningkatkan metrik cakupan kode pengujian.

Mengatur proyek pengujian

Proyek pengujian dapat diatur sesuai yang paling cocok untuk Anda. Ada baiknya untuk memisahkan pengujian berdasarkan jenis (pengujian unit, pengujian integrasi) dan dengan apa yang mereka uji (berdasarkan proyek, berdasarkan namespace). Apakah pemisahan ini terdiri dari folder dalam satu proyek pengujian, atau beberapa proyek pengujian, adalah keputusan desain. Satu proyek paling sederhana, tetapi untuk proyek besar dengan banyak pengujian, atau untuk lebih mudah menjalankan serangkaian pengujian yang berbeda, Anda mungkin ingin memiliki beberapa proyek pengujian yang berbeda. Banyak tim mengatur proyek pengujian berdasarkan proyek yang mereka uji, yang untuk aplikasi dengan lebih dari beberapa proyek dapat menghasilkan sejumlah besar proyek pengujian, terutama jika Anda masih memecahnya sesuai dengan jenis pengujian apa yang ada di setiap proyek. Pendekatan kompromi adalah memiliki satu proyek per jenis pengujian, per aplikasi, dengan folder di dalam proyek pengujian untuk menunjukkan proyek (dan kelas) yang sedang diuji.

Pendekatan umum adalah mengatur proyek aplikasi di bawah folder 'src', dan proyek pengujian aplikasi di bawah folder 'pengujian' paralel. Anda dapat membuat folder solusi yang cocok di Visual Studio, jika organisasi ini berguna.

Menguji organisasi dalam solusi Anda

Gambar 9-2. Menguji organisasi dalam solusi Anda

Anda dapat menggunakan kerangka kerja pengujian apa pun yang Anda sukai. Kerangka kerja xUnit berfungsi dengan baik dan merupakan kerangka kerja yang digunakan dalam semua pengujian ASP.NET Core dan EF Core. Anda dapat menambahkan proyek pengujian xUnit di Visual Studio menggunakan templat yang ditampilkan di Gambar 9-3, atau dari CLI menggunakan dotnet new xunit.

Menambahkan Proyek Pengujian xUnit di Visual Studio

Gambar 9-3. Menambahkan Proyek Pengujian xUnit di Visual Studio

Penamaan pengujian

Beri nama pengujian Anda dengan cara yang konsisten, dengan nama yang menunjukkan apa yang dilakukan setiap pengujian. Salah satu pendekatan yang sangat berhasil bagi saya adalah memberi nama kelas pengujian sesuai dengan kelas dan metode yang mereka uji. Pendekatan ini menghasilkan banyak kelas pengujian kecil, tetapi membuatnya sangat jelas apa yang menjadi tanggung jawab setiap pengujian. Dengan menyiapkan nama kelas pengujian, untuk mengidentifikasi kelas dan metode yang akan diuji, nama metode pengujian dapat digunakan untuk menentukan perilaku yang sedang diuji. Nama ini harus mencakup perilaku yang diharapkan dan input atau asumsi apa pun yang harus menghasilkan perilaku ini. Beberapa contoh nama pengujian:

  • CatalogControllerGetImage.CallsImageServiceWithId

  • CatalogControllerGetImage.LogsWarningGivenImageMissingException

  • CatalogControllerGetImage.ReturnsFileResultWithBytesGivenSuccess

  • CatalogControllerGetImage.ReturnsNotFoundResultGivenImageMissingException

Variasi pendekatan ini mengakhiri setiap nama kelas pengujian dengan "Harus" dan sedikit memodifikasi tense-nya.

  • CatalogControllerGetImage Sebaiknya.PanggilImageServiceWithId

  • CatalogControllerGetImage Sebaiknya.BatangWarningGivenImageMissingException

Beberapa tim menemukan pendekatan penamaan kedua lebih jelas, meskipun sedikit lebih verbose. Bagaimanapun, cobalah untuk menggunakan konvensi penamaan yang memberikan wawasan tentang perilaku pengujian, sehingga ketika satu atau beberapa pengujian gagal, jelas dari nama mereka kasus apa yang gagal. Hindari penamaan pengujian Anda samar-samar, seperti ControllerTests.Test1, karena nama-nama ini tidak menawarkan nilai saat Anda melihatnya dalam hasil pengujian.

Jika Anda mengikuti konvensi penamaan seperti yang di atas yang menghasilkan banyak kelas pengujian kecil, ada baiknya mengatur pengujian Anda lebih lanjut menggunakan folder dan namespace. Gambar 9-4 menunjukkan satu pendekatan untuk mengatur pengujian menurut folder dalam beberapa proyek pengujian.

Mengatur kelas pengujian menurut folder berdasarkan kelas yang sedang diuji

Gambar 9-4. Mengatur kelas pengujian dalam folder sesuai dengan kelas yang diuji.

Jika kelas aplikasi tertentu memiliki banyak metode yang sedang diuji (dan dengan demikian banyak kelas pengujian), mungkin masuk akal untuk menempatkan kelas-kelas ini dalam folder yang sesuai dengan kelas aplikasi. Organisasi ini tidak berbeda dari bagaimana Anda dapat mengatur file ke dalam folder di tempat lain. Jika Anda memiliki lebih dari tiga atau empat file terkait dalam folder yang berisi banyak file lain, seringkali berguna untuk memindahkannya ke subfolder mereka sendiri.

Pengujian unit aplikasi ASP.NET Core

Dalam aplikasi ASP.NET Core yang dirancang dengan baik, sebagian besar kompleksitas dan logika bisnis akan dienkapsulasi dalam entitas bisnis dan berbagai layanan. Aplikasi ASP.NET Core MVC itu sendiri, dengan pengontrol, filter, viewmodel, dan tampilannya, harus memerlukan beberapa pengujian unit. Sebagian besar fungsionalitas tindakan tertentu terletak di luar metode tindakan itu sendiri. Menguji apakah perutean atau penanganan kesalahan global berfungsi dengan benar tidak dapat dilakukan secara efektif dengan uji unit. Demikian juga, filter apa pun, termasuk validasi model dan filter autentikasi dan otorisasi, tidak dapat diuji unit dengan pengujian yang menargetkan metode tindakan pengontrol. Tanpa sumber perilaku ini, sebagian besar metode tindakan harus sangat sederhana, mendelegasikan sebagian besar pekerjaan mereka ke layanan yang dapat diuji secara independen dari pengontrol yang menggunakannya.

Terkadang Anda harus merefaktor kode Anda agar dapat melakukan pengujian unit padanya. Sering kali aktivitas ini melibatkan identifikasi abstraksi dan menggunakan injeksi dependensi untuk mengakses abstraksi dalam kode yang ingin Anda uji, daripada pengkodean langsung terhadap infrastruktur. Misalnya, pertimbangkan metode tindakan mudah ini untuk menampilkan gambar:

[HttpGet("[controller]/pic/{id}")]
public IActionResult GetImage(int id)
{
  var contentRoot = _env.ContentRootPath + "//Pics";
  var path = Path.Combine(contentRoot, id + ".png");
  Byte[] b = System.IO.File.ReadAllBytes(path);
  return File(b, "image/png");
}

Pengujian unit pada metode ini menjadi sulit karena ketergantungan langsungnya pada System.IO.File, yang digunakan untuk membaca dari sistem file. Anda dapat menguji perilaku ini untuk memastikannya berfungsi seperti yang diharapkan, tetapi melakukannya dengan file nyata adalah pengujian integrasi. Perlu dicatat bahwa Anda tidak dapat menguji rute metode ini secara unit—Anda akan segera melihat cara melakukan pengujian ini dengan pengujian fungsi.

Jika Anda tidak dapat menguji perilaku sistem file secara langsung, dan Anda tidak dapat menguji rute, apa yang harus diuji? Nah, setelah pengubahan kode untuk memungkinkan pengujian unit, Anda mungkin menemukan beberapa skenario uji dan perilaku yang hilang, seperti penanganan kesalahan. Apa yang dilakukan metode ketika file tidak ditemukan? Apa yang harus dilakukannya? Dalam contoh ini, metode yang direfaktor terlihat seperti ini:

[HttpGet("[controller]/pic/{id}")]
public IActionResult GetImage(int id)
{
  byte[] imageBytes;
  try
  {
    imageBytes = _imageService.GetImageBytesById(id);
  }
  catch (CatalogImageMissingException ex)
  {
    _logger.LogWarning($"No image found for id: {id}");
    return NotFound();
  }
  return File(imageBytes, "image/png");
}

_logger dan _imageService keduanya disuntikkan sebagai ketergantungan. Sekarang Anda dapat menguji bahwa ID yang sama yang diteruskan ke metode tindakan diteruskan ke _imageService, dan bahwa byte yang dihasilkan dikembalikan sebagai bagian dari FileResult. Anda juga dapat menguji bahwa pengelogan kesalahan terjadi seperti yang diharapkan, dan bahwa NotFound hasilnya dikembalikan jika gambar hilang, dengan asumsi perilaku ini adalah perilaku aplikasi penting (yaitu, bukan hanya kode sementara yang ditambahkan pengembang untuk mendiagnosis masalah). Logika berkas aktual telah dipindahkan ke layanan implementasi yang terpisah, dan telah ditingkatkan untuk mengembalikan pengecualian yang spesifik untuk aplikasi dalam kasus berkas yang hilang. Anda dapat menguji implementasi ini secara independen, menggunakan pengujian integrasi.

Dalam kebanyakan kasus, Anda harus menggunakan penangan pengecualian global di pengontrol Anda, sehingga jumlah logika di dalamnya harus minimal dan mungkin tidak layak untuk pengujian unit. Lakukan sebagian besar pengujian tindakan pengontrol menggunakan pengujian fungsional dan TestServer kelas yang dijelaskan di bawah ini.

Pengujian integrasi aplikasi ASP.NET Core

Sebagian besar pengujian integrasi di aplikasi ASP.NET Core Anda harus menguji layanan dan jenis implementasi lain yang ditentukan dalam proyek Infrastruktur Anda. Misalnya, Anda dapat menguji bahwa EF Core berhasil memperbarui dan mengambil data yang Anda harapkan dari kelas akses data Anda yang berada di proyek Infrastruktur. Cara terbaik untuk menguji bahwa proyek MVC Core ASP.NET Anda berperilaku dengan benar adalah dengan pengujian fungsional yang berjalan terhadap aplikasi Anda yang berjalan di host pengujian.

Pengujian fungsional aplikasi ASP.NET Core

Untuk aplikasi ASP.NET Core, TestServer kelas membuat pengujian fungsional cukup mudah ditulis. Anda mengonfigurasi TestServer menggunakan WebHostBuilder (atau HostBuilder) secara langsung (seperti yang biasa Anda lakukan untuk aplikasi Anda), atau dengan tipe WebApplicationFactory (tersedia sejak versi 2.1). Cobalah untuk mencocokkan host pengujian Anda dengan host produksi Anda sedekat mungkin, sehingga pengujian Anda menjalankan perilaku yang mirip dengan apa yang akan dilakukan aplikasi dalam produksi. Kelas WebApplicationFactory ini berguna untuk mengonfigurasi ContentRoot dari TestServer, yang digunakan oleh ASP.NET Core untuk menemukan sumber daya statis seperti Views.

Anda dapat membuat pengujian fungsional sederhana dengan membuat kelas pengujian yang mengimplementasikan IClassFixture<WebApplicationFactory<TEntryPoint>>, di mana TEntryPoint adalah kelas aplikasi Startup web Anda. Dengan antarmuka ini di tempat, perlengkapan pengujian Anda dapat membuat klien menggunakan metode pabrik CreateClient :

public class BasicWebTests : IClassFixture<WebApplicationFactory<Program>>
{
  protected readonly HttpClient _client;

  public BasicWebTests(WebApplicationFactory<Program> factory)
  {
    _client = factory.CreateClient();
  }

  // write tests that use _client
}

Petunjuk / Saran

Jika Anda menggunakan konfigurasi API minimal dalam file Program.cs Anda, secara default kelas akan dinyatakan internal dan tidak akan dapat diakses dari proyek pengujian. Anda dapat memilih kelas instans lain di proyek web Anda, atau menambahkannya ke file Program.cs Anda:

// Make the implicit Program class public so test projects can access it
public partial class Program { }

Sering kali, Anda akan ingin melakukan beberapa konfigurasi tambahan situs Anda sebelum setiap pengujian berjalan, seperti mengonfigurasi aplikasi untuk menggunakan penyimpanan data dalam memori dan kemudian menyemai aplikasi dengan data pengujian. Untuk mencapai fungsionalitas ini, buat subkelas WebApplicationFactory<TEntryPoint> Anda sendiri dan timpa metode ConfigureWebHost. Contoh di bawah ini berasal dari proyek eShopOnWeb FunctionalTests dan digunakan sebagai bagian dari pengujian pada aplikasi web utama.

using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.EntityFrameworkCore;
using Microsoft.eShopWeb.Infrastructure.Data;
using Microsoft.eShopWeb.Infrastructure.Identity;
using Microsoft.eShopWeb.Web;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;

namespace Microsoft.eShopWeb.FunctionalTests.Web;
public class WebTestFixture : WebApplicationFactory<Startup>
{
  protected override void ConfigureWebHost(IWebHostBuilder builder)
  {
    builder.UseEnvironment("Testing");

    builder.ConfigureServices(services =>
    {
      services.AddEntityFrameworkInMemoryDatabase();

      // Create a new service provider.
      var provider = services
            .AddEntityFrameworkInMemoryDatabase()
            .BuildServiceProvider();

      // Add a database context (ApplicationDbContext) using an in-memory
      // database for testing.
      services.AddDbContext<CatalogContext>(options =>
      {
        options.UseInMemoryDatabase("InMemoryDbForTesting");
        options.UseInternalServiceProvider(provider);
      });

      services.AddDbContext<AppIdentityDbContext>(options =>
      {
        options.UseInMemoryDatabase("Identity");
        options.UseInternalServiceProvider(provider);
      });

      // Build the service provider.
      var sp = services.BuildServiceProvider();

      // Create a scope to obtain a reference to the database
      // context (ApplicationDbContext).
      using (var scope = sp.CreateScope())
      {
        var scopedServices = scope.ServiceProvider;
        var db = scopedServices.GetRequiredService<CatalogContext>();
        var loggerFactory = scopedServices.GetRequiredService<ILoggerFactory>();

        var logger = scopedServices
            .GetRequiredService<ILogger<WebTestFixture>>();

        // Ensure the database is created.
        db.Database.EnsureCreated();

        try
        {
          // Seed the database with test data.
          CatalogContextSeed.SeedAsync(db, loggerFactory).Wait();

          // seed sample user data
          var userManager = scopedServices.GetRequiredService<UserManager<ApplicationUser>>();
          var roleManager = scopedServices.GetRequiredService<RoleManager<IdentityRole>>();
          AppIdentityDbContextSeed.SeedAsync(userManager, roleManager).Wait();
        }
        catch (Exception ex)
        {
          logger.LogError(ex, $"An error occurred seeding the " +
                    "database with test messages. Error: {ex.Message}");
        }
      }
    });
  }
}

Pengujian dapat menggunakan WebApplicationFactory kustom ini dengan menggunakannya untuk membuat klien lalu membuat permintaan ke aplikasi menggunakan instans klien ini. Aplikasi akan memiliki benih data yang dapat digunakan sebagai bagian dari pernyataan pengujian. Pengujian berikut memverifikasi bahwa halaman beranda aplikasi eShopOnWeb dimuat dengan benar dan menyertakan daftar produk yang ditambahkan ke aplikasi sebagai bagian dari data benih.

using Microsoft.eShopWeb.FunctionalTests.Web;
using System.Net.Http;
using System.Threading.Tasks;
using Xunit;

namespace Microsoft.eShopWeb.FunctionalTests.WebRazorPages;
[Collection("Sequential")]
public class HomePageOnGet : IClassFixture<WebTestFixture>
{
  public HomePageOnGet(WebTestFixture factory)
  {
    Client = factory.CreateClient();
  }

  public HttpClient Client { get; }

  [Fact]
  public async Task ReturnsHomePageWithProductListing()
  {
    // Arrange & Act
    var response = await Client.GetAsync("/");
    response.EnsureSuccessStatusCode();
    var stringResponse = await response.Content.ReadAsStringAsync();

    // Assert
    Assert.Contains(".NET Bot Black Sweatshirt", stringResponse);
  }
}

Pengujian fungsional ini menjalankan tumpukan aplikasi ASP.NET Core MVC / Razor Pages lengkap, termasuk semua middleware, filter, dan pengikat yang mungkin digunakan. Ini memverifikasi bahwa rute tertentu ("/") mengembalikan kode status keberhasilan dan output HTML yang diharapkan. Ini melakukannya tanpa menyiapkan server web nyata, dan menghindari banyak kekakuan yang dapat dialami saat menggunakan server web nyata untuk pengujian (misalnya, masalah dengan pengaturan firewall). Pengujian fungsional yang berjalan terhadap TestServer biasanya lebih lambat daripada integrasi dan pengujian unit, tetapi jauh lebih cepat daripada pengujian yang akan berjalan melalui jaringan ke server web pengujian. Gunakan pengujian fungsi untuk memastikan tumpukan front-end aplikasi Anda berfungsi seperti yang diharapkan. Pengujian ini sangat berguna ketika Anda menemukan duplikasi di pengontrol atau halaman Anda dan Anda mengatasi duplikasi dengan menambahkan filter. Idealnya, pemfaktoran ulang ini tidak akan mengubah perilaku aplikasi, dan serangkaian pengujian fungsi akan memverifikasi hal ini terjadi.

Referensi – Menguji aplikasi MVC Inti ASP.NET