2012-02-20 15 views
7

Her biri benzer özel arabirimler uygulayan C# serilerinde bir dizi koleksiyon dersi yazıyorum. Bir arabirim için tek bir birim testi koleksiyonu yazmak mümkün mü ve hepsini çeşitli farklı uygulamalarda otomatik olarak çalıştırmak mümkün mü? Her uygulama için çoğaltılan test kodundan kaçınmak istiyorum.Bir arabirimin uygulanmasını test etmek için bir dizi yeniden kullanılabilir test yapabilir miyim?

Bunu yapmak için herhangi bir çerçeveye (NUnit, vb.) Veya Visual Studio uzantısına bakmaya hazırım. aynı şeyi isteyenler için


, ben an answer olarak, avandeursen's accepted solution dışına göre benim somut çözüm yayınlanmıştır.

+1

Soru ve yanıt LSP'ye bağlı sınıf hiyerarşisine uygulandığından [lsp] (http://stackoverflow.com/questions/tagged/lsp) etiketi olarak eklendi. – avandeursen

cevap

6

Evet, bu mümkün. Hile, birim sınıf sınama hiyerarşinizin kodunuzun sınıf hiyerarşisini izlemesine izin vermektir.

ve C2 uygulama sınıflarıyla birlikte bir Itf arabiriminiz olduğunu varsayalım.

İlk olarak Itf (ItfTest) için bir test sınıfı oluşturun. Testi gerçekten uygulamak için, Itf arabiriminizin sahte bir uygulamasını oluşturmanız gerekir.

Bu ItfTest numaralı telefondaki tüm testler Itf (!) Uygulamasının herhangi bir uygulamasından geçmelidir. Değilse, uygulama C1 için bir test vakası oluşturmak için, Böylece

Liskov Substitution Principle (OO tasarım Martin'in SOLID ilkeleri "L") uymuyor, sizin C1Test sınıf ItfTest uzatabilir. Uzantınız, sahte nesne oluşturulmasını, bir C1 nesnesinin oluşturulmasıyla (GoF factory method kullanarak) değiştirmelidir. Bu şekilde, tüm ItfTest kasaları, C1 türlerine uygulanır. Ayrıca, C1Test sınıfınız, C1'a özgü ek test durumları içerebilir.

Benzer şekilde C2 için. Ve daha derin iç içe geçmiş sınıflar ve arayüzler için numarayı tekrarlayabilirsiniz.

Referanslar: Bağlayıcı Polymorphic Server Test desen, ve McGregor'un PACT - Bileşen Testi için Paralel Mimari.

+1

Sahte uygulamaları önlemek için, sadece "ItfTest" sınıfımı soyut olarak bildirdim ve "korumalı bir soyut Itf CreateInstance();" işlev sapı olarak bildirildi. (Hem "ItfTest" hem de "C1Test" in "[TestClass]' özniteliğine sahip olması gerektiğini unutmayın.) – dlras2

+1

Evet, daha basit olduğu için fabrika yöntemini de kullandım. Bu test yaklaşımını JUnit'te kullandım, burada [TestClass] 'özniteliği yok, fakat üst sınıflardaki 'Test' ek açıklamaları kalıtsal sınıf testlerinin alt sınıflarda yeniden çalıştırılmasına neden oluyor. Ve: Düzenleme için teşekkürler. – avandeursen

2

Bunu yapmak için MBUnit'da [RowTest] öznitelikleri kullanabilirsiniz. , Herhangi bir keyfi sayıda geçebilir niteliklerini [Row] olarak

[RowTest] 
[Row("Class1")] 
[Row("Class2")] 
[Row("Class3")] 
public void TestMethod(string type) 
{ 
    IMyInterface foo = Activator.CreateInstance(Type.GetType(type)) as IMyInterface; 

    //Do tests on foo: 
} 

: Eğer yöntemini ardından örneğini ve istediğiniz arabirimi uygulama sınıfı belirtmek için bir dize geçer gösterileri Aşağıdaki örnek yansıma yoluyla bu sınıfı oluşturur Giriş parametrelerinin, örneğin girişin test değerleri veya metodun çağrılması ile iade edilmesi beklenen değerler. Test yöntemi giriş argümanları olarak karşılık gelen tiplerin argümanlarını eklemeniz gerekecektir.

+0

Uygulamanızı nasıl test edeceğimi tam olarak açıklamak için cevabınızı düzenleyebilir misiniz? Her bir birim testinin tüm uygulamalar için bir anahtar ifadesine ihtiyacı olduğunu söylüyorsunuz, ki bu benim istediğim şey değil. – dlras2

+0

İstemiyorsanız bir anahtar ifadesi kullanmanıza gerek yoktur. Ben de yansımayı kullanabileceğinden bahsetmiştim. Bunun bir örneği için Anthony'nin cevabına bakınız. Ayrıca, post'umu, arayüzün çeşitli somut uygulamalarını somutlaştırmak için bir yansımayı kullanma örneğini içerecek şekilde güncelledim. –

+0

Muhtemelen bunu sadece isim yerine 'IMyInterface' örneklerini almak için yazabilirim, ama yine de +1. – dlras2

2

Joe's yanıtında, NUnit'teki [TestCaseSource] özniteliğini MBUnit's RowTest'e benzer şekilde kullanabilirsiniz. Sınıf isimlerinizle bir test örneği kaynağı oluşturabilirsiniz. Sonra TestCaseSource özniteliği olan her testi süsleyebilirsiniz. Daha sonra Activator.CreateInstance kullanarak arayüze yayınlayabilirsiniz ve siz de ayarlanacaksınız.Böyle

şey (not - derlenmiş kafa)

string[] MyClassNameList = { "Class1", "Class2" }; 

[TestCaseSource(MyClassNameList)] 
public void Test1(string className) 
{ 
    var instance = Activator.CreateInstance(Type.FromName(className)) as IMyInterface; 

    ... 
} 
1

Bu avandeursen's answer off my somut uygulama dayanır:

:

[TestClass] 
public abstract class IMyInterfaceTests 
{ 
    protected abstract IMyInterface CreateInstance(); 

    [TestMethod] 
    public void SomeTest() 
    { 
     IMyInterface instance = CreateInstance(); 
     // Run the test 
    } 
} 

Her arabirim uygulaması daha sonra aşağıdaki test sınıfını tanımlar

[TestClass] 
public class MyImplementationTests : IMyInterfaceTests 
{ 
    protected override IMyInterface CreateInstance() 
    { 
     return new MyImplementation(); 
    } 
} 

SomeTest bir kez çalıştırılır Her bir beton TestClassIMyInterfaceTests'dan türetilmiştir. Soyut bir temel sınıf kullanarak, herhangi bir sahte uygulama ihtiyacını ortadan kaldırırım. Her iki sınıfa da TestClassAttribute eklediğinizden emin olun, aksi takdirde bu işe yaramaz. Son olarak, istenirse, çocuk sınıfına uygulamaya özel testler (kurucular gibi) ekleyebilirsiniz.

+0

belirli bir test çerçevesi kullanıyor musunuz? VS2012'de dahil edilen birim testlerini kullanıyorum ve başka bir “paylaşılan” test projesinden (isim alanı) alınan testler alınıyor. – drzaus

+0

garip - aynı proje içinde devralınan testler, farklı isim alanı iyi gösteriyor. Sadece kayıt olmadıkları farklı bir projede olduklarında. Neyi kaçırıyorum? – drzaus

İlgili konular