Bagikan melalui


Gunakan stub untuk mengisolasi bagian aplikasi Anda satu sama lain untuk pengujian unit

Jenis stub adalah teknologi penting yang disediakan oleh kerangka kerja Microsoft Fakes, memungkinkan isolasi komponen yang mudah Anda uji dari komponen lain yang diandalkannya. Stub bertindak sebagai bagian kecil kode yang menggantikan komponen lain selama pengujian. Manfaat utama menggunakan stub adalah kemampuan untuk mendapatkan hasil yang konsisten untuk mempermudah penulisan pengujian. Bahkan jika komponen lain belum berfungsi penuh, Anda masih dapat menjalankan pengujian dengan menggunakan stub.

Untuk menerapkan stub secara efektif, disarankan untuk merancang komponen Anda dengan cara yang terutama bergantung pada antarmuka daripada kelas konkret dari bagian lain aplikasi. Pendekatan desain ini mempromosikan pemisahan dan mengurangi kemungkinan perubahan dalam satu bagian yang membutuhkan modifikasi di bagian lain. Dalam hal pengujian, pola desain ini memungkinkan penggantian implementasi stub untuk komponen nyata, memfasilitasi isolasi yang efektif dan pengujian komponen target yang akurat.

Misalnya, mari kita pertimbangkan diagram yang mengilustrasikan komponen yang terlibat:

Diagram of Real and Stub classes of StockAnalyzer.

Dalam diagram ini, komponen yang sedang diuji adalah StockAnalyzer, yang biasanya bergantung pada komponen lain yang disebut RealStockFeed. Namun, RealStockFeed menimbulkan tantangan untuk pengujian karena mengembalikan hasil yang berbeda setiap kali metodenya dipanggil. Varianbilitas ini menyulitkan untuk memastikan pengujian yang konsisten dan andal dari StockAnalyzer.

Untuk mengatasi hambatan ini selama pengujian, kita dapat mengadopsi praktik injeksi dependensi. Pendekatan ini melibatkan penulisan kode Anda sedaya sehingga tidak secara eksplisit menyebutkan kelas di komponen lain dari aplikasi Anda. Sebagai gantinya, Anda menentukan antarmuka yang dapat diterapkan komponen lain dan stub untuk tujuan pengujian.

Berikut adalah contoh bagaimana Anda dapat menggunakan injeksi dependensi dalam kode Anda:

public int GetContosoPrice(IStockFeed feed) => feed.GetSharePrice("COOO");

Batasan stub

Tinjau batasan berikut untuk stub.

Membuat Stub: Panduan Langkah demi Langkah

Mari kita mulai latihan ini dengan contoh yang memotivasi: yang ditunjukkan dalam diagram sebelumnya.

Membuat Pustaka Kelas

Ikuti langkah-langkah ini untuk membuat pustaka kelas.

  1. Buka Visual Studio dan buat proyek Pustaka Kelas.

    Screenshot of Class Library project in Visual Studio.

  2. Konfigurasikan atribut proyek:

    • Atur Nama proyek ke StockAnalysis.
    • Atur Nama solusi ke StubsTutorial.
    • Atur kerangka kerja Target proyek ke .NET 8.0.
  3. Hapus file default Class1.cs.

  4. Tambahkan file baru bernama IStockFeed.cs dan salin dalam definisi antarmuka berikut:

    // IStockFeed.cs
    public interface IStockFeed
    {
        int GetSharePrice(string company);
    }
    
  5. Tambahkan file baru lain bernama StockAnalyzer.cs dan salin dalam definisi kelas berikut:

    // StockAnalyzer.cs
    public class StockAnalyzer
    {
        private IStockFeed stockFeed;
        public StockAnalyzer(IStockFeed feed)
        {
            stockFeed = feed;
        }
        public int GetContosoPrice()
        {
            return stockFeed.GetSharePrice("COOO");
        }
    }
    

Membuat Proyek Pengujian

Buat proyek pengujian untuk latihan.

  1. Klik kanan pada solusi dan tambahkan proyek baru bernama MSTest Test Project.

  2. Atur nama proyek ke TestProject.

  3. Atur kerangka kerja target proyek ke .NET 8.0.

    Screenshot of Test project in Visual Studio.

Menambahkan rakitan Palsu

Tambahkan rakitan Palsu untuk proyek.

  1. Tambahkan referensi proyek ke StockAnalyzer.

    Screenshot of the command Add Project Reference.

  2. Tambahkan Rakitan Palsu.

    1. Di Penjelajah Solusi, temukan referensi perakitan:

      • Untuk Proyek .NET Framework yang lebih lama (gaya non-SDK), perluas node Referensi proyek pengujian unit Anda.

      • Untuk proyek gaya SDK yang menargetkan .NET Framework, .NET Core, atau .NET 5.0 atau yang lebih baru, perluas node Dependensi untuk menemukan rakitan yang ingin Anda palsukan di bawah Rakitan, Proyek, atau Paket.

      • Jika Anda bekerja di Visual Basic, pilih Perlihatkan Semua File di toolbar Penjelajah Solusi untuk melihat node Referensi.

    2. Pilih rakitan yang berisi definisi kelas yang ingin Anda buat bongkahannya.

    3. Pada menu pintasan, pilih Tambahkan Rakitan Fake.

      Screenshot of the command Add Fakes Assembly.

Membuat proyek pengujian unit

Sekarang buat pengujian unit.

  1. Ubah file default UnitTest1.cs untuk menambahkan definisi berikut Test Method .

    [TestClass]
    class UnitTest1
    {
        [TestMethod]
        public void TestContosoPrice()
        {
            // Arrange:
            int priceToReturn = 345;
            string companyCodeUsed = "";
            var componentUnderTest = new StockAnalyzer(new StockAnalysis.Fakes.StubIStockFeed()
            {
                GetSharePriceString = (company) =>
                {
                    // Store the parameter value:
                    companyCodeUsed = company;
                    // Return the value prescribed by this test:
                    return priceToReturn;
                }
            });
    
            // Act:
            int actualResult = componentUnderTest.GetContosoPrice();
    
            // Assert:
            // Verify the correct result in the usual way:
            Assert.AreEqual(priceToReturn, actualResult);
    
            // Verify that the component made the correct call:
            Assert.AreEqual("COOO", companyCodeUsed);
        }
    }
    

    Bagian khusus sihir di sini adalah StubIStockFeed kelas. Untuk setiap antarmuka dalam rakitan yang dirujuk, mekanisme Microsoft Fakes menghasilkan kelas stub. Nama kelas stub berasal dari nama antarmuka, dengan "Fakes.Stub" sebagai prefiks, dan nama jenis parameter ditambahkan.

    Stub juga dihasilkan untuk getter dan setter properti, untuk peristiwa, dan untuk metode generik. Untuk informasi selengkapnya, lihat Menggunakan stub untuk mengisolasi bagian aplikasi Anda satu sama lain untuk pengujian unit.

    Screenshot of Solution Explorer showing all files.

  2. Buka Test Explorer dan jalankan pengujian.

    Screenshot of Test Explorer.

Stub untuk berbagai jenis anggota jenis

Ada stub untuk berbagai jenis anggota jenis.

Metode

Dalam contoh yang disediakan, metode dapat di-stubbing dengan melampirkan delegasi ke instans kelas stub. Nama jenis stub berasal dari nama metode dan parameter. Misalnya, pertimbangkan antarmuka berikut IStockFeed dan metodenya GetSharePrice:

// IStockFeed.cs
interface IStockFeed
{
    int GetSharePrice(string company);
}

Kami melampirkan stub ke GetSharePrice dengan menggunakan GetSharePriceString:

// unit test code
var componentUnderTest = new StockAnalyzer(new StockAnalysis.Fakes.StubIStockFeed()
        {
            GetSharePriceString = (company) =>
            {
                // Store the parameter value:
                companyCodeUsed = company;
                // Return the value prescribed by this test:
                return priceToReturn;
            }
        });

Jika Anda tidak menyediakan stub untuk metode , Fakes menghasilkan fungsi yang mengembalikan default value jenis pengembalian. Untuk angka, nilai defaultnya adalah 0. Untuk jenis kelas, defaultnya ada null di C# atau Nothing di Visual Basic.

Properti

Pencari properti dan setter diekspos sebagai delegasi terpisah dan dapat disandingkan satu per satu. Misalnya, pertimbangkan Value properti dari IStockFeedWithProperty:

interface IStockFeedWithProperty
{
    int Value { get; set; }
}

Untuk membuat stub getter dan setter dan Value mensimulasikan properti otomatis, Anda dapat menggunakan kode berikut:

// unit test code
int i = 5;
var stub = new StubIStockFeedWithProperty();
stub.ValueGet = () => i;
stub.ValueSet = (value) => i = value;

Jika Anda tidak menyediakan metode stub untuk setter atau getter properti, Fakes menghasilkan stub yang menyimpan nilai, membuat properti stub berperilaku seperti variabel sederhana.

Aktivitas

Peristiwa diekspos sebagai bidang delegasi, memungkinkan peristiwa yang tersandung dinaikkan hanya dengan memanggil bidang dukungan peristiwa. Mari kita pertimbangkan antarmuka berikut untuk stub:

interface IStockFeedWithEvents
{
    event EventHandler Changed;
}

Untuk menaikkan Changed acara, Anda memanggil delegasi backing:

// unit test code
var withEvents = new StubIStockFeedWithEvents();
// raising Changed
withEvents.ChangedEvent(withEvents, EventArgs.Empty);

Metode generik

Anda dapat membagi metode generik dengan menyediakan delegasi untuk setiap instansiasi metode yang diinginkan. Misalnya, mengingat antarmuka berikut dengan metode generik:

interface IGenericMethod
{
    T GetValue<T>();
}

Anda dapat membasahi GetValue<int> instansiasi sebagai berikut:

[TestMethod]
public void TestGetValue()
{
    var stub = new StubIGenericMethod();
    stub.GetValueOf1<int>(() => 5);

    IGenericMethod target = stub;
    Assert.AreEqual(5, target.GetValue<int>());
}

Jika kode memanggil dengan instansiasi GetValue<T> lain, stub menjalankan perilaku.

Stub kelas virtual

Dalam contoh sebelumnya, stub telah dihasilkan dari antarmuka. Namun, Anda juga dapat menghasilkan stub dari kelas yang memiliki anggota virtual atau abstrak. Misalnya:

// Base class in application under test
public abstract class MyClass
{
    public abstract void DoAbstract(string x);
    public virtual int DoVirtual(int n)
    {
        return n + 42;
    }

    public int DoConcrete()
    {
        return 1;
    }
}

Dalam stub yang dihasilkan dari kelas ini, Anda dapat mengatur metode delegasi untuk DoAbstract() dan DoVirtual(), tetapi tidak DoConcrete().

// unit test
var stub = new Fakes.MyClass();
stub.DoAbstractString = (x) => { Assert.IsTrue(x>0); };
stub.DoVirtualInt32 = (n) => 10 ;

Jika Anda tidak memberikan delegasi untuk metode virtual, Fakes dapat memberikan perilaku default atau memanggil metode di kelas dasar. Agar metode dasar dipanggil, atur CallBase properti :

// unit test code
var stub = new Fakes.MyClass();
stub.CallBase = false;
// No delegate set - default delegate:
Assert.AreEqual(0, stub.DoVirtual(1));

stub.CallBase = true;
// No delegate set - calls the base:
Assert.AreEqual(43,stub.DoVirtual(1));

Mengubah perilaku default

Setiap jenis stub yang dihasilkan menyimpan instans IStubBehavior antarmuka melalui IStub.InstanceBehavior properti . Perilaku ini dipanggil setiap kali klien memanggil anggota tanpa delegasi kustom yang terlampir. Jika perilaku tidak diatur, ia menggunakan instans yang dikembalikan oleh StubsBehaviors.Current properti . Secara default, properti ini mengembalikan perilaku yang melemparkan pengecualian NotImplementedException.

Anda dapat mengubah perilaku kapan saja dengan mengatur InstanceBehavior properti pada instans stub apa pun. Misalnya, cuplikan berikut mengubah perilaku sehingga stub tidak melakukan apa pun atau mengembalikan nilai default dari jenis default(T)pengembalian :

// unit test code
var stub = new StockAnalysis.Fakes.StubIStockFeed();
// return default(T) or do nothing
stub.InstanceBehavior = StubsBehaviors.DefaultValue;

Perilaku juga dapat diubah secara global untuk semua objek stub di mana perilaku tidak diatur dengan StubsBehaviors.Current properti :

// Change default behavior for all stub instances where the behavior has not been set.
StubBehaviors.Current = BehavedBehaviors.DefaultValue;