Sabit kodlu nesne ile yöntem nasıl alay edilir?


11

Birden çok katmanı olan bir uygulama üzerinde çalışıyorum. Veri kaynağından veri almak ve kaydetmek için veri erişim katmanı, verileri değiştirmek için iş mantığı, verileri ekranda göstermek için kullanıcı arayüzü.

Ayrıca iş mantığı katmanı üzerinde birim testi yapıyorum. Tek gereklilik, iş katmanı mantığının akışını test etmektir. Bu yüzden veri erişim katmanı ve birim mantık katmanı MS Unit ile test etmek için Moq framework kullanıyorum.

Birim testinin yapılabilmesi için tasarım ayrıştırmasını olabildiğince yapmak için arayüz programlaması kullanıyorum. İş katmanı arayüzü üzerinden veri erişim katmanı çağrısı.

İş mantığı yöntemlerinden birini test etmeye çalışırken bir sorunla karşılaşıyorum. Bu yöntem bazı işleri yapar ve bir nesne oluşturur ve bunu veri erişim katmanına iletir. Ben o veri erişim katmanı yöntemi alay etmeye çalıştığımda o zaman başarılı alay olamaz.

Burada sorunumu göstermek için bir demo kodu oluşturmaya çalışıyorum.

Model:

public class Employee
{
    public string Name { get; set; }
}

Veri erişim katmanı:

public interface IDal
{
    string GetMessage(Employee emp);
}

public class Dal : IDal
{
    public string GetMessage(Employee emp)
    {
        // Doing some data source access work...

        return string.Format("Hello {0}", emp.Name);
    }
}

İş mantığı katmanı:

public interface IBll
{
    string GetMessage();
}

public class Bll : IBll
{
    private readonly IDal _dal;

    public Bll(IDal dal)
    {
        _dal = dal;
    }

    public string GetMessage()
    {
        // Object creating inside business logic method.
        Employee emp = new Employee(); 

        string msg = _dal.GetMessage(emp);
        return msg;
    }
}

Ünite testi:

[TestMethod]
    public void Is_GetMessage_Return_Proper_Result()
    {
        // Arrange.
        Employee emp = new Employee; // New object.

        Mock<IDal> mockDal = new Mock<IDal>();
        mockDal.Setup(d => d.GetMessage(emp)).Returns("Hello " + emp.Name);

        IBll bll = new Bll(mockDal.Object);

        // Act.

        // This will create another employee object inside the 
        // business logic method, which is different from the 
        // object which I have sent at the time of mocking.
        string msg = bll.GetMessage(); 

        // Assert.
        Assert.AreEqual("Hello arnab", msg);
    }

Alay sırasındaki birim test durumunda bir Employee nesnesi gönderiyorum ancak iş mantığı yöntemini çağırırken, yöntemin içinde farklı Employee nesnesi oluşturuyor. Bu yüzden nesneyi alay edemiyorum.

Bu durumda, sorunu çözebilmem için nasıl tasarım yapılır?


Genellikle hile nesneyi bir arabirime sarmak ve tüm tüketicilerin bu arabirimi kullanmasını sağlamaktır, o zaman sadece arabirimi alay edersiniz, alternatif olarak yöntemi sanal hale getirebilir ve daha sonra moq yöntemi arabirim olmadan alay edebilir. Ancak bu durumda rhinomocks veya diğerleri hakkında emin değilim.
Jimmy Hoffa

Yanıtlar:


12

EmployeeDoğrudan kullanarak bir nesne oluşturmak yerine, newsınıfınız Bllbunun için bir EmployeeFactorysınıf kullanarak createInstanceyapıcıya enjekte edilen bir yöntem kullanabilir :

 class EmployeeFactory : IEmployeeFactory
 {
       public Employee createInstance(){return new Employee();}
 }

Yapıcı fabrika nesnesini bir arabirim aracılığıyla almalıdır IEmployeeFactory, böylece "gerçek" fabrikayı bir sahte fabrika ile kolayca değiştirebilirsiniz.

public class Bll : IBll
{
    private readonly IDal _dal;
    private readonly IEmployeeFactory _employeeFactory;

    public Bll(IDal dal, IEmployeeFactory employeeFactory)
    {
        _dal = dal;
        _employeeFactory=employeeFactory;
    }

    public string GetMessage()
    {
        // Object creating inside business logic method
        // *** using a factory ***
        Employee emp = _employeeFactory.createObject(); 
        // ...
    }
    //...
}

Sahte fabrika, test Employeeiçin testiniz için ihtiyacınız olan her türlü nesneyi sağlayabilir (örneğin, createInstanceher zaman aynı nesneyi döndürebilir):

 class MockEmployeeFactory : IEmployeeFactory
 {
       private Employee _emp;

       public MockEmployeeFactory()
       {
          _emp = new Employee();
          // add any kind of special initializing here for testing purposes
       }

       public Employee createInstance()
       {
          // just for testing, return always the same object
          return _emp;
       }
 }

Şimdi bu sahte testinizde hile yapmak gerekir.


Teorinizi görselleştirebilmem için bana bir kod örneği verebilir misiniz?
DeveloperArnab

@DeveloperArnab: benim düzenlememe bakın.
Doc Brown

Very helpful ...
DeveloperArnab

4

Bunu test etmek için tek bir birim olarak ele alırdım.

EmployeeNesnenin oluşturulduğu tüm girdileri kontrol ettiğiniz sürece, test edilen nesnede yaratıldığı gerçeği önemli olmamalıdır. Bağımsız değişkenin içeriği beklenti ile eşleşiyorsa beklenen sonucu döndürmek için sadece bir sahte yöntem gerekir.

Açıkçası, sahte yöntem için özel mantık sağlamanız gerektiği anlamına gelir. Gelişmiş mantık genellikle sadece "x dönüş y" tipi alaylarla test edilemez.

Aslında, testlerde üretimde olduğundan farklı bir nesne döndürmesini sağlamamalısınız , çünkü eğer yaparsanız, onu oluşturması gereken kodu test etmeyeceksiniz. Ancak bu kod, üretim kodunun ayrılmaz bir parçasıdır ve bu nedenle de test durumu tarafından kapsanmalıdır.


Evet, veri erişim katmanının girişleri hakkında endişelenmiyorum, sadece bu nesneyi alay etmek ve iş mantığını test edebilmek için sabit kodlanmış bir veri döndürmek istiyorum. Ancak sorun, iki farklı Çalışan nesnesi nedeniyle, veri erişim katmanı yöntemini alay edemiyorum.
DeveloperArnab

@DeveloperArnab: Nesneler farklı olacak, ancak içeriği biliniyor olacak. Yani yapmanız gereken tek şey sahte nesne kimliği yerine özel karşılaştırma yapmak.
Jan Hudec

@DeveloperArnab: Testlere farklı bir Employeenesne enjekte ederseniz , normalde onu oluşturan kodu test etmezsiniz . Yani değiştirmemelisin.
Jan Hudec

0

Bazı test araçlarının başarısız olması, her zaman arayüzleri kullanmanız ve her şeyin arayüz tabanlı nesneyi başka biri için değiştirmenize izin verecek şekilde yaratılması gerekir.

Bununla birlikte, daha iyi araçlar var - herhangi bir nesneyi, statik ve küresel olanları bile değiştirmenize izin veren Microsoft Fakes'i (Moles olarak adlandırıldı) alın. Nesneleri değiştirmek için daha düşük seviyeli bir yaklaşım gerekir, böylece alıştığınız testleri yazma yolunu korurken, her yerde arayüz kullanmak zorunda kalmazsınız.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.