SORU
27 Mart 2014, PERŞEMBE


Nasıl insanlar birim Varlık Çerçevesi ile test etsin 6,?

Sadece Birim testleri ve genel olarak TDD ile başlayan duyuyorum. Amatörce önce aldım ama benim iş akışı eklemek ve daha iyi bir yazılım yazmaya kararlıyım artık.

Bu dahil dün bir soru sormuştum, ama kendi başına bir soru gibi görünüyor. Uzak Denetleyicilerinden iş mantığı Özet için kullanacağım bu Hizmet sınıfı uygulamaya oturdu ve belirli modeller ve veri etkileşimleri EF6 kullanarak göster.

Sorun var roadblock özellikli kendimi zaten çünkü ben istemedim soyut EF uzak bir depo (bu yine de kullanılabilir dışındaki hizmetleri için belirli sorguları, vs.) ve test hizmetleri (EF İçerik olarak kullanılacaktır).

Burada sanırım asıl soru, bunu yapmanın bir amacı var mı? Eğer öyleyse, nasıl insanlar işin içinde vahşi ışık sızdıran soyutlamalar nedeniyle IQueryable ve çok büyük mesaj Ladislav Mrnka konu test ünitesi olmadığı anlaşılır, çünkü farklı Seri sağlayıcıları ile çalışırken bir bellek uygulama gibi olmalısın için belirli bir veritabanı.

Test etmek istediğim kod oldukça basit görünüyor. (bu sadece deneyin ve yapıyorum, yaratılış TDD kullanarak sürmek istiyorum ne olduğunu anlamak için) örnek bir kod

Bağlam

public interface IContext
{
    IDbSet<Product> Products { get; set; }
    IDbSet<Category> Categories { get; set; }
    int SaveChanges();
}

public class DataContext : DbContext, IContext
{
    public IDbSet<Product> Products { get; set; }
    public IDbSet<Category> Categories { get; set; }

    public DataContext(string connectionString)
                : base(connectionString)
    {

    }
}

Hizmet

public class ProductService : IProductService
{
    private IContext _context;

    public ProductService(IContext dbContext)
    {
        _context = dbContext;
    }

    public IEnumerable<Product> GetAll()
    {
        var query = from p in _context.Products
                    select p;

        return query;
    }
}

Şu anda birkaç şey yapmaya zihniyet duyuyorum:

  1. Alay EF İçeriği ile bir şey gibi, bu yaklaşım- Mocking EF When Unit Testing ya da doğrudan kullanarak bir alay ortamı arayüzü gibi Adedi alma ağrı ünite testleri geçmesi olabilir ama mutlaka işe uçtan uca ve onları geri ile Entegrasyon testleri?
  2. Eğer başkasının vahşi kullanıyorsa, belki alay EF Effort gibi bir şey - hiç kullanmadım kullanan ve emin değil misiniz?
  3. Sadece EF - yani aslında doğrudan EF çağrı servis yöntemleri (getAll vb), birim test değil arar o test rahatsız değil ama sadece entegrasyon test?

Aslında bu bir Repo yapmayan ve başarılı olan biri?

CEVAP
27 Mart 2014, PERŞEMBE


Bu benim çok ilgimi çeken bir konu. EF ve Arabiriminin gibi teknolojiler test yapmamalısın bunu söyleyen çok fazla titiz vardır. Haklılar, zaten çok sıkı test ediyorlar ve bir önceki cevap genellikle anlamsız zaman büyük miktarda sahip değilsin ne test etmek için bir anlam ifade ediyor.

Ancak, veritabanı altında kendi yapmak!Bu EF/YU düzgün bir şekilde işlerini yapıyorlar ki bence bu yaklaşım bozuluyor, test etmeye gerek yok. Eşleştirmeleri/uygulamaları veritabanı ile çalıştığını test etmek gerekir. Bence bu test bir sistemin en önemli parçalarından biridir.

Entegrasyon test içine birim test alanı dışında ve gidiyoruz ancak açık konuşmak gerekirse ama ilkeleri aynı kalır.

Yapmanız gereken ilk şey, kan kurşun EF ve SQL bağımsız olarak test edilebilir, bu yüzden DAL alay edebilmek için.Bu birim testleri.Bir sonraki tasarım gerekirEntegrasyon Testlerisenin DAL kanıtlamak için, benim görüşüme göre, bu önemli olarak her bit.

Dikkate birkaç şey vardır:

  1. Veritabanı her test ile bilinen bir devlet olması gerekir. Sistemlerin çoğu için de böyle bir yedek oluşturmak veya komut dosyaları kullanın.
  2. Her test tekrarlanabilir olması gerekir
  3. Her test atomik olmalıdır

Veritabanı kurmak için iki ana yaklaşım vardır, ilk bir UnitTest çalıştırmak için DB komut dosyası oluşturun. Bu birim test veritabanınızı her zaman her test (ya da bu sıfırlama ya da bunu sağlamak için bir hareket, her bir test çalıştırabilirsiniz) başında aynı durumda olmasını sağlar.

Diğer seçeneğin ne olduğunu, her bir test için özel ayarlar çalıştırın. Bu iki ana nedenden dolayı en iyi yaklaşım olduğuna inanıyorum:

  • Veritabanı her test için bütün bir şema gerekmez basit
  • Her bir test, eğer bir değeri diğer testler onlarca geçersiz değil komut dosyası oluşturmak değiştirirseniz daha güvenli olur.

Ne yazık ki uzlaşma burada hız. Tüm bu testler, tüm bu Kur Çalıştır/komut yıkmak için alır.

Son bir nokta, çok zor SQL böyle büyük bir miktar, ORM test yazmak için işe olabilir. Bu çok çirkin bir yaklaşım (Burada benimle aynı fikirde olacak titiz) burada aldım. Benim ORM benim test oluşturmak için kullanın! Benim sistemimde her DAL test için ayrı bir komut yerine, nesneleri oluşturur, bu bağlamda onları ekler ve kaydeder test bir kurulum aşaması var. O zaman benim test çalıştırın.

Bu uygulamada ÇOK yönetmek daha kolay olur ancak ideal bir çözüm olmaktan çok uzaktır özellikle binlerce testleri (), aksi takdirde komut büyük bir rakam oluşturuyor. Saflık üzerinde pratiklik.

Şüphesiz benim yaklaşımlar değişirken bu cevap birkaç yıl sonra (ay/gün) bakmak ve kendimi katılmıyorum edeceğim - ancak bu benim geçerli bir yaklaşımdır.

Deneyin ve her şeyi özetlemek için bu tipik DB entegrasyon test yukarıda söyledim:

[Test]
public void LoadUser()
{
  this.RunTest(session => // the NH/EF session to attach the objects to
  {
    var user = new UserAccount("Mr", "Joe", "Bloggs");
    session.Save(user);
    return user.UserID;
  }, id => // the ID of the entity we need to load
  {
     var user = LoadMyUser(id); // load the entity
     Assert.AreEqual("Mr", user.Title); // test your properties
     Assert.AreEqual("Joe", user.Firstname);
     Assert.AreEqual("Bloggs", user.Lastname);
  }
}

Burada dikkat etmeniz gereken en önemli şey, iki döngüler oturumları tamamen bağımsız olmasıdır. RunTest uygulamanızı bağlamında kararlı olduğundan emin olmalısınız ve tahrip ve verilerinizi sadece ikinci bölümü için senin veritabanından gelebilir.

13/10/2014 düzenleyin

Muhtemelen önümüzdeki aylarda bu model revize edeceğimi söyledim. Ben büyük ölçüde yaklaşımı ile ayakta iken biraz test mekanizması güncelledik yukarıda savundu. Ben şimdi TestSetup ve TestTearDown içinde varlıkları oluşturmak eğilimindedir.

[SetUp]
public void Setup()
{
  this.SetupTest(session => // the NH/EF session to attach the objects to
  {
    var user = new UserAccount("Mr", "Joe", "Bloggs");
    session.Save(user);
    this.UserID =  user.UserID;
  });
}

[TearDown]
public void TearDown()
{
   this.TearDownDatabase();
}

Sonra her bir özelliği tek tek test

[Test]
public void TestTitle()
{
     var user = LoadMyUser(this.UserID); // load the entity
     Assert.AreEqual("Mr", user.Title);
}

[Test]
public void TestFirstname()
{
     var user = LoadMyUser(this.UserID);
     Assert.AreEqual("Joe", user.Firstname);
}

[Test]
public void TestLastname()
{
     var user = LoadMyUser(this.UserID);
     Assert.AreEqual("Bloggs", user.Lastname);
}

Bu yaklaşım için çeşitli nedenleri vardır:

  • Ek veritabanı aramaları (bir kur, bir enkaz var
  • Testler çok daha ayrıntılı, her test bir özelliği doğrular
  • Kur/Enkaz mantık Test yöntemlerini kendilerini kaldırılır

Bu test sınıfı daha basit ve daha ayrıntılı testler (single asserts are good) yapar hissediyorum

5/3/2015 düzenleyin

Bu yaklaşım, başka bir revizyon. Sınıf düzeyi kurulumları yükleme özellikleri gibi testler için çok yararlı olsa da farklı kurulumları gerekli olduğu daha az yararlıdır. Bu durumda her dava için yeni bir sınıf kurmak çok tehlikeli.

Bu yardım şimdi iki temel sınıflar SetupPerTest SingleSetup sahip olma eğilimindedir. Bu iki sınıf gerektiği gibi çerçeve kullanır.

SingleSetup benim ilk düzenleme açıklandığı gibi benzer bir mekanizma var. Bir örnek olacaktır

public TestProperties : SingleSetup
{
  public int UserID {get;set;}

  public override DoSetup(ISession session)
  {
    var user = new User("Joe", "Bloggs");
    session.Save(user);
    this.UserID = user.UserID;
  }

  [Test]
  public void TestLastname()
  {
     var user = LoadMyUser(this.UserID); // load the entity
     Assert.AreEqual("Bloggs", user.Lastname);
  }

  [Test]
  public void TestFirstname()
  {
       var user = LoadMyUser(this.UserID);
       Assert.AreEqual("Joe", user.Firstname);
  }
}

Ancak sadece doğru entites yüklü olduğundan emin olun başvuran SetupPerTest bir yaklaşım kullanabilir

public TestProperties : SetupPerTest
{
   [Test]
   public void EnsureCorrectReferenceIsLoaded()
   {
      int friendID = 0;
      this.RunTest(session =>
      {
         var user = CreateUserWithFriend();
         session.Save(user);
         friendID = user.Friends.Single().FriendID;
      } () =>
      {
         var user = GetUser();
         Assert.AreEqual(friendID, user.Friends.Single().FriendID);
      });
   }
   [Test]
   public void EnsureOnlyCorrectFriendsAreLoaded()
   {
      int userID = 0;
      this.RunTest(session =>
      {
         var user = CreateUserWithFriends(2);
         var user2 = CreateUserWithFriends(5);
         session.Save(user);
         session.Save(user2);
         userID = user.UserID;
      } () =>
      {
         var user = GetUser(userID);
         Assert.AreEqual(2, user.Friends.Count());
      });
   }
}

Özet olarak her iki yaklaşımın test için çalışıyoruz ne bağlı olarak çalışır.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • ArkticPlanet

    ArkticPlanet

    9 ŞUBAT 2010
  • bcbauer

    bcbauer

    7 ŞUBAT 2007
  • Codecourse

    Codecourse

    3 ŞUBAT 2009