Birim testi için uygulamanızın parçalarını birbirinden yalıtmak üzere saplamalar kullanma

Saplama türleri , Microsoft Fakes çerçevesi tarafından sağlanan ve test ettiğiniz bileşenin bağlı olduğu diğer bileşenlerden kolayca yalıtılmasını sağlayan önemli bir teknolojidir. Saplama, test sırasında başka bir bileşenin yerini alacak küçük bir kod parçası işlevi görür. Saptamaları kullanmanın temel avantajlarından biri, test yazmayı kolaylaştırmak için tutarlı sonuçlar elde etmektir. Diğer bileşenler henüz tam olarak işlevsel olmasa bile saptamaları kullanarak testleri yürütebilirsiniz.

Saplamaları etkili bir şekilde uygulamak için, bileşeninizi uygulamanın diğer bölümlerindeki somut sınıflar yerine birincil olarak arabirimlere bağlı olacak şekilde tasarlamanız önerilir. Bu tasarım yaklaşımı, ayrıştırma işlemini teşvik eder ve bir bölümde değişiklik yapılması için başka bir bölümde değişiklik yapılması olasılığını azaltır. Test söz konusu olduğunda, bu tasarım deseni gerçek bir bileşen için saplama uygulamasının değiştirilip etkin yalıtımın ve hedef bileşenin doğru test edilmesine olanak tanır.

Örneğin, ilgili bileşenleri gösteren diyagramı ele alalım:

Diagram of Real and Stub classes of StockAnalyzer.

Bu diyagramda, test altındaki bileşen genellikle StockAnalyzeradlı RealStockFeedbaşka bir bileşene dayanır. Ancak, RealStockFeed yöntemleri her çağrıldığında farklı sonuçlar döndürdüğünden test için bir zorluk oluşturur. Bu değişkenlik tutarlı ve güvenilir bir şekilde test StockAnalyzeredilmesini zorlaştırıyor.

Test sırasında bu engeli aşmak için bağımlılık ekleme uygulamasını benimseyebiliriz. Bu yaklaşım, kodunuzu uygulamanızın başka bir bileşenindeki sınıflardan açıkça bahsetmeyen bir şekilde yazmayı içerir. Bunun yerine, diğer bileşenin ve saplamanın test amacıyla uygulayabileceği bir arabirim tanımlarsınız.

Kodunuzda bağımlılık ekleme özelliğini nasıl kullanabileceğinize yönelik bir örnek aşağıda verilmişti:

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

Saptama sınırlamaları

Saptamalar için aşağıdaki sınırlamaları gözden geçirin.

  • İşaretçileri olan yöntem imzaları desteklenmez.

  • Saplama türleri sanal yöntem gönderimi kullandığından, korumalı sınıflar veya statik yöntemler saplama türleri kullanılarak saplanamaz. Bu gibi durumlarda, birim testi için uygulamanızı diğer derlemelerden yalıtmak için dolguları kullanma başlığında açıklandığı gibi dolgu türlerini kullanın

Saplama Oluşturma: Adım Adım Kılavuz

Bu alıştırmaya motive edici bir örnekle başlayalım: önceki diyagramda gösterilen alıştırma.

Sınıf Kitaplığı Oluşturma

Sınıf kitaplığı oluşturmak için bu adımları izleyin.

  1. Visual Studio'yu açın ve bir Sınıf Kitaplığı projesi oluşturun.

    Screenshot of Class Library project in Visual Studio.

  2. Proje özniteliklerini yapılandırın:

    • Proje adını StockAnalysis olarak ayarlayın.
    • Çözüm adını StubsTutorial olarak ayarlayın.
    • Proje Hedef çerçevesini .NET 8.0 olarak ayarlayın.
  3. Varsayılan Class1.cs dosyasını silin.

  4. IStockFeed.cs adlı yeni bir dosya ekleyin ve aşağıdaki arabirim tanımına kopyalayın:

    // IStockFeed.cs
    public interface IStockFeed
    {
        int GetSharePrice(string company);
    }
    
  5. StockAnalyzer.cs adlı başka bir yeni dosya ekleyin ve aşağıdaki sınıf tanımına kopyalayın:

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

Test Projesi Oluşturma

Alıştırma için test projesini oluşturun.

  1. Çözüme sağ tıklayın ve MSTest Test Projesi adlı yeni bir proje ekleyin.

  2. Proje adını TestProjesi olarak ayarlayın.

  3. Projenin hedef çerçevesini .NET 8.0 olarak ayarlayın.

    Screenshot of Test project in Visual Studio.

Fakes derlemesi ekleme

Proje için Fakes derlemesini ekleyin.

  1. öğesine StockAnalyzerbir proje başvurusu ekleyin.

    Screenshot of the command Add Project Reference.

  2. Fakes Derlemesini ekleyin.

    1. Çözüm Gezgini'da derleme başvuruyu bulun:

      • Eski bir .NET Framework Projesi (SDK olmayan stil) için birim testi projenizin Başvurular düğümünü genişletin.

      • .NET Framework, .NET Core veya .NET 5.0 veya üzerini hedefleyen SDK stilinde bir proje için, Derlemeler, Projeler veya Paketler altında sahtesini yapmak istediğiniz derlemeyi bulmak için Bağımlılıklar düğümünü genişletin.

      • Visual Basic'te çalışıyorsanız Başvurular düğümünü görmek için Çözüm Gezgini araç çubuğunda Tüm Dosyaları Göster'i seçin.

    2. Saplama oluşturmak istediğiniz sınıf tanımlarını içeren derlemeyi seçin.

    3. Kısayol menüsünde Sahte Derleme Ekle'yi seçin.

      Screenshot of the command Add Fakes Assembly.

Birim testi oluşturma

Şimdi birim testini oluşturun.

  1. Aşağıdaki Test Method tanımı eklemek için varsayılan UnitTest1.cs dosyasını değiştirin.

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

    Buradaki özel sihir parçası sınıfımız StubIStockFeed . Başvurulan derlemedeki her arabirim için saptama sınıfı Microsoft Fakes mekanizması oluşturur. Saplama sınıfının adı arabirimin adından türetilir ve ön ek olarak "Fakes.Stub" ve parametre türü adları eklenir.

    Saptamalar ayrıca olaylar ve genel yöntemlerle ilgili olarak özellik okuyucu ve ayarlayıcılar için oluşturulur. Daha fazla bilgi için bkz . Birim testi için uygulamanızın parçalarını birbirinden yalıtmak için saplamaları kullanma.

    Screenshot of Solution Explorer showing all files.

  2. Test Gezgini'ni açın ve testi çalıştırın.

    Screenshot of Test Explorer.

Tür üyelerinin farklı türleri için saptamalar

Farklı tür üyeleri için saplamalar vardır.

Yöntemler

Sağlanan örnekte, saplama sınıfının bir örneğine temsilci eklenerek yöntemler saplanabilir. Saptama türünün adı yöntemi ve parametreleri adlarından türetilir. Örneğin, aşağıdaki IStockFeed arabirimi ve yöntemini GetSharePricegöz önünde bulundurun:

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

kullanarak GetSharePriceStringbir GetSharePrice saplama ekleriz:

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

Bir yöntem için saplama sağlamazsanız Fakes, dönüş türünün sonucunu döndüren default value bir işlev oluşturur. Sayılar için varsayılan değer 0'dır. Sınıf türleri için varsayılan değer C# veya Nothing Visual Basic'tirnull.

Özellikler

Özellik alıcıları ve ayarlayıcıları ayrı temsilciler olarak sunulur ve ayrı ayrı saplanabilir. Örneğin, özelliğini IStockFeedWithPropertygöz önünde bulundurunValue:

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

Bir otomatik özelliğin alıcısını ve ayarlayıcısını Value saplayıp benzetimini yapmak için aşağıdaki kodu kullanabilirsiniz:

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

Bir özelliğin ayarlayıcısı veya alıcısı için saptama yöntemleri sağlamazsanız Fakes değerleri depolayan bir saptama oluşturur ve saplama özelliğinin basit bir değişken gibi davranmasını sağlar.

Olaylar

Olaylar temsilci alanları olarak sunulur ve saplanan olayların yalnızca olay yedekleme alanı çağrılarak tetiklenmesine olanak sağlar. Saptamak için aşağıdaki arabirimi ele alalım:

interface IStockFeedWithEvents
{
    event EventHandler Changed;
}

Olayı başlatmak Changed için, yedekleme temsilcisini çağırırsınız:

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

Genel yöntemler

Yöntemin istenen her örneği için bir temsilci sağlayarak genel yöntemleri saplayabilirsiniz. Örneğin, genel bir yöntemle aşağıdaki arabirim göz önünde bulundurulduğunda:

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

Örneklemeyi GetValue<int> aşağıdaki gibi saplayabilirsiniz:

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

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

Kod başka bir örneklemeyle çağırırsa GetValue<T> , saplama davranışı yürütür.

Sanal sınıf saptamaları

Önceki örneklerde saptamalar arabirimlerden üretilmedi. Ancak, sanal veya soyut üyeleri olan bir sınıftan saplamalar da oluşturabilirsiniz. Örneğin:

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

Bu sınıftan oluşturulan saplamada ve DoVirtual()için DoAbstract() temsilci yöntemleri ayarlayabilirsiniz, ancak ayarlayamayabilirsinizDoConcrete().

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

Sanal yöntem için temsilci sağlamazsanız Fakes varsayılan davranışı sağlayabilir veya temel sınıfta yöntemini çağırabilir. Base yönteminin çağrılmış olması için özelliğini ayarlayın CallBase :

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

Saptamaların varsayılan davranışını değiştirme

Oluşturulan her saplama türü, özelliği aracılığıyla arabirimin IStubBehavior bir örneğini IStub.InstanceBehavior tutar. Bu davranış, bir istemci ekli özel temsilcisi olmayan bir üyeyi her çağırışında çağrılır. Davranış ayarlı değilse, özelliği tarafından StubsBehaviors.Current döndürülen örneği kullanır. Varsayılan olarak, bu özellik özel durum oluşturan bir NotImplementedException davranış döndürür.

Herhangi bir saplama örneğinde özelliğini ayarlayarak InstanceBehavior istediğiniz zaman davranışı değiştirebilirsiniz. Örneğin, aşağıdaki kod parçacığı davranışı değiştirerek saplama hiçbir şey yapmaz veya dönüş türünün default(T)varsayılan değerini döndürür:

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

Davranış, davranışın özelliğiyle StubsBehaviors.Current ayarlandığı tüm saptama nesneleri için de genel olarak değiştirilebilir:

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