Arayüzler ne zaman kullanılır (birim testi, IoC?)


17

Burada bir öğrenci hatası yaptığımı sanıyorum ve açıklama arıyorum. Benim çözüm (C #) sınıfların birçoğu - ben çoğunluk söylemeye cesaret - Ben karşılık gelen bir arayüz yazma sona erdi. Örneğin, bir "ICalculator" arayüzü ve onu uygulayan bir "Hesap Makinesi" sınıfı, bu hesap makinesini asla farklı bir uygulama ile değiştirmeme rağmen. Ayrıca, bu sınıfların çoğu bağımlılıklarıyla aynı projede yer alır - gerçekten sadece olmaları gerekir internal, ancak publicilgili arayüzlerini uygulamanın bir yan etkisi haline gelmiştir.

Bence her şey için arayüz oluşturma uygulaması birkaç yanlışlıktan kaynaklandı: -

1) Başlangıçta birim test alayları oluşturmak için bir arayüzün gerekli olduğunu düşündüm (Moq kullanıyorum), ancak o zamandan beri bir sınıfın üyeleri varsa alay edebileceğini virtualve parametresiz bir kurucuya sahip olduğunu keşfettim. Hatalıyım).

2) Başlangıçta IoC çerçevesine (Windsor Kalesi) bir sınıf kaydetmek için bir arayüz gerekli olduğunu düşündüm, ör.

Container.Register(Component.For<ICalculator>().ImplementedBy<Calculator>()...

Aslında beton tipini kendisine karşı kaydedebildiğim zaman:

Container.Register(Component.For<Calculator>().ImplementedBy<Calculator>()...

3) Bağımlılık enjeksiyonu için kurucu parametreleri gibi arayüzler kullanmak, "gevşek kuplaj" ile sonuçlanır.

Arayüzlere kızdım mı ?! "Normalde" bir arayüz kullanacağınız senaryoların farkındayım, örneğin herkese açık bir API'yı açığa çıkarmak veya "takılabilir" işlev gibi şeyler için. Benim çözüm bu tür kullanım durumlarına uyan az sayıda sınıf var, ama diğer tüm arayüzlerin gereksiz olup olmadığını ve kaldırılması gerektiğini merak ediyorum? Yukarıdaki 3. maddeyle ilgili olarak, eğer bunu yapsaydım "gevşek bağlantıyı" ihlal etmeyecek miyim?

Düzenleme : - Ben sadece Moq ile bir oyun yaşıyorum, ve bu yöntemleri alay edebilmek için genel ve sanal olmak ve genel bir parametresiz yapıcı olması için yöntemler gerektirir gibi görünüyor . Öyleyse iç dersleri alamıyorum gibi mi?


Eminim C #, arayüz herkese açık olsa bile, bir arayüz uygulamak için bir sınıfı herkese açık hale getirmenizi gerektirmez ...
vaughandroid

1
Özel üyeleri test etmeniz gerekmiyor . Bu, tanrı sınıfı anti-paterninin bir göstergesi olarak görülebilir. Özel işlevselliği birim olarak test etme gereğini hissediyorsanız, bu işlevselliği kendi sınıfında kapsüllemek genellikle iyi bir fikirdir.
Spoike

@ Söz konusu projenin, tüm sınıfları dahili hale getirmenin doğal göründüğü bir UI projesidir, ancak yine de birim teste ihtiyaçları var mı? Başka bir yerde dahili yöntemleri test etmeye ihtiyaç duymadığı hakkında okudum, ama bunun nedenlerini hiç anlamadım.
Andrew Stephens

Önce kendinize test edilen ünitenin ne olduğunu sorun. Bütün sınıf mı yoksa bir yöntem mi? Ünitenin düzgün bir şekilde test edilebilmesi için bu ünitenin halka açık olması gerekir. UI projelerinde, test edilebilir mantığı genellikle herkese açık yöntemleri olan denetleyicilere / görünüm modellerine / hizmetlere ayırırım. Gerçek görünümler / widget'lar denetleyicilere / görünüm modellerine / hizmetlere bağlanır ve düzenli duman testi ile test edilir (yani uygulamayı başlatın ve tıklamaya başlayın). Altta yatan işlevselliği test etmeniz ve widget'lar üzerinde birim testlerin yapılması kırılgan testlere yol açacak ve dikkatle yapılması gereken senaryolara sahip olabilirsiniz.
Spoike

@Spoike, VM yöntemlerinizi sadece birim testlerimiz için erişilebilir hale getirmek üzere halka açıyor musunuz? Belki de yanlış yaptığım yer, herşeyi içselleştirmeye çalışmak. Bence ellerim Moq'a bağlı olabilir, bu da onları taklit etmek için sınıfların (sadece yöntemler değil) halka açık olmasını gerektirir (Telastyn'in cevabı hakkındaki yorumuma bakın).
Andrew Stephens

Yanıtlar:


7

Genel olarak, sadece bir uygulayıcısı olan bir arayüz yaparsanız, sadece iki kez bir şeyler yazıyorsunuz ve zamanınızı boşa harcıyorsunuz. Tek başına arabirimler tek bir uygulamaya sıkıca bağlıysa gevşek bağlantı sağlamaz ... Bu, birim testlerde bu şeylerle alay etmek istiyorsanız, genellikle kaçınılmaz olarak gerçekte birden fazla uygulayıcıya ihtiyacınız olacağının harika bir işaretidir. kodu.

Hemen hemen tüm sınıflarınız olsa arabirimleri varsa bir kod kokusu biraz düşünün. Yani neredeyse hepsi birbirleriyle şu ya da bu şekilde çalışıyorlar. Sınıfların çok fazla performans gösterdiğinden şüphelenirim (yardımcı sınıf olmadığı için) ya da çok fazla soyutladınız (oh, bu değişebileceğinden yerçekimi için bir sağlayıcı arayüzü istiyorum !).


1
Cevap için teşekkürler. Belirtildiği gibi, çoğu arayüzün asla birden fazla uygulamasının olmayacağını bilsem de, yaptığım şeyi yapmamın yanlış yönlendirilmiş birkaç nedeni var. Sorunun bir parçası, alay arayüzleri için harika olan Moq çerçevesini kullanıyorum, ancak bir sınıfı alay etmek için herkese açık olmalı, genel parametresiz bir ctr olmalı ve alay edilecek yöntemler 'genel sanal' olmalıdır).
Andrew Stephens

Birim testi yaptığım sınıfların çoğu içseldir ve onları test edilebilir yapmak için herkese açık hale getirmek istemiyorum (tartışabilmenize rağmen, tüm bu arayüzleri bunun için yazdım). Arabirimlerimden kurtulursam, muhtemelen yeni bir alaycı çerçeve bulmam gerekecek!
Andrew Stephens

1
@AndrewStephens - dünyadaki her şeyin alay konusu olması gerekmez. Sınıflar arabirimlere ihtiyaç duymayacak kadar sağlam (veya sıkıca bağlanmışsa), birim testinde olduğu gibi kullanmak için yeterince sağlamdır. Bunları birleştiren zaman / karmaşıklık test avantajlarına değmez.
Telastyn

-1, çünkü kodu ilk kez yazarken kaç uygulayıcıya ihtiyacınız olduğunu bilmiyorsunuz. Başından itibaren bir arabirim kullanıyorsanız, ek uygulayıcılar yazarken istemcileri değiştirmeniz gerekmez.
Wilbert

1
@wilbert - elbette, küçük bir arabirim sınıftan daha okunabilir, ancak birini veya diğerini seçmiyorsunuz, sınıf veya sınıf ve arabiriminiz var. Ve cevabımı çok fazla okuyor olabilirsiniz. Asla tek bir uygulama için arayüz oluşturmayacağını söylemiyorum - çoğu etkileşim, çoğu etkileşim bu esnekliği gerektirmelidir. Ancak soruyu tekrar okuyun. Her şey için bir arayüz oluşturmak sadece kargo danışmanlığıdır. IoC bir sebep değil. Alaylar bir sebep değil. Gereksinimler bu esnekliği uygulamak için bir nedendir.
Telastyn

4

1) Somut sınıflar mockable olsa bile, yine de üye oluşturmanızı virtualve rahatsız edici ve istenmeyen olabilecek parametresiz bir kurucu sağlamanızı gerektirir . Siz (veya yeni ekip üyeleri) kısa bir süre sonra kendinizi virtual"yeni şeyler böyle yürüyor" diye, ikinci bir düşünce olmadan her yeni sınıfın sistemlerini ve parametresiz kurucularını ekleyerek bulacaksınız .

Bir arayüz, bir bağımlılığı taklit etmeniz gerektiğinde IMO'yu çok daha iyi bir fikirdir, çünkü uygulamayı gerçekten ihtiyacınız olana kadar ertelemenize izin verir ve bağımlılığın güzel bir anlaşmasını yapar.

3) Bu nasıl bir yanlışlık?

Arayüzlerin, birlikte çalışan nesneler arasındaki mesajlaşma protokollerini tanımlamak için harika olduğuna inanıyorum. Örneğin etki alanı varlıklarında olduğu gibi, bunlara olan ihtiyacın tartışmalı olduğu durumlar olabilir. Bununla birlikte, iletişim kurmanız gereken sabit bir ortağınız (yani, geçici bir referansın aksine enjekte edilen bir bağımlılığın) nerede olursanız olun, genellikle bir arayüz kullanmayı düşünmelisiniz.


3

IoC fikri, beton tiplerini değiştirilebilir yapmaktır. Bu yüzden (şu anda) yalnızca ICalculator'ı uygulayan tek bir Hesap Makinesi'niz olsa bile, ikinci bir uygulama Hesap Makinesi'nden uygulama ayrıntılarına değil, yalnızca arabirime bağlı olabilir.

Bu nedenle, IoC-Container kaydınızın ilk sürümü doğru ve gelecekte kullanmanız gereken sürümdür.

Sınıflarınızı kamuya ya da içsel hale getirirseniz, gerçekten de ilişkili değildir ve moq-ing de yoktur.


2

Tüm projenizdeki her türden "alay etme" gereğini hissettiğiniz için gerçekten daha fazla endişelenirim.

Test çiftleri çoğunlukla kodunuzu dış dünyadan (üçüncü taraf kütüphaneleri, disk IO, ağ IO, vb.) Veya gerçekten pahalı hesaplamalardan izole etmek için yararlıdır. Yalıtım çerçevenizle çok liberal olmak (GERÇEKTEN bile ihtiyacınız var mı? Projeniz karmaşık mı?) Kolayca uygulamaya bağlı testlere yol açabilir ve tasarımınızı daha sert hale getirir. Yöntem X ve Y olarak adlandırılan bazı sınıfların bu sırayla doğrulandığını doğrulayan ve a, b ve c parametrelerini Z yöntemine ileten bir grup test yazarsanız, GERÇEKTEN değer alıyor musunuz? Bazen günlük kaydını veya üçüncü taraf kütüphaneleriyle etkileşimi test ederken böyle testler alırsınız, ancak kural değil istisna olmalıdır.

Yalıtım çerçeveniz, işleri herkese açık hale getirmeniz gerektiğini ve her zaman parametresiz kuruculara sahip olmanız gerektiğini söylediği anda, halttan kurtulmak için zamanı geldi, çünkü bu noktada çerçeveniz kötü (daha kötü) kod yazmanız için ZORUNLU.

Arayüzler hakkında daha spesifik olarak konuşursak, birkaç önemli durumda yararlı olduklarını görüyorum:

  • Farklı türlere yöntem çağrıları göndermeniz gerektiğinde, örneğin birden fazla uygulamanız olduğunda (bu çok açıktır, çünkü çoğu dilde bir arayüzün tanımı sadece sanal yöntemlerin bir koleksiyonudur)

  • Kodunuzun geri kalanını bir sınıftan ayırmanız gerektiğinde. Bu, dosya sistemini ve ağ erişimini ve veritabanını ve benzerlerini uygulamanızın temel mantığından soyutlamanın normal yoludur.

  • Uygulama sınırlarını korumak için kontrolün ters çevrilmesi gerektiğinde. Bu, bağımlılıkları yönetmek için mümkün olan en güçlü yollardan biridir. Hepimiz yüksek seviyeli modüllerin ve düşük seviyeli modüllerin birbirlerini bilmemesi gerektiğini biliyoruz, çünkü bunlar farklı nedenlerle değişecek ve etki alanı modelinizde HttpContext'e veya matris çarpma kütüphanenizdeki bazı Pdf oluşturma çerçevesine bağımlılık istemiyorsunuz . Sınır sınıflarınızı arayüzler uygulamak (daha önce hiç değiştirilmeseler bile) katmanlar arasındaki bağlantıyı gevşetmeye yardımcı olur ve çok fazla başka türü bilen türlerden katmanlardan sızma bağımlılığını önemli ölçüde azaltır.


1

Bazı mantık özel ise, o zaman bu mantığın uygulanmasının hiç kimse için endişe duymaması ve bu nedenle test edilmemesi gerektiği fikrine yaslanıyorum. Bazı mantık, test etmek istediğiniz kadar karmaşıksa, bu mantığın muhtemelen farklı bir rolü vardır ve bu nedenle herkese açık olmalıdır. Örneğin, özel bir yardımcı yöntemde bazı kodları çıkarırsam, bunun genellikle ayrı bir ortak sınıfta (bir biçimlendirici, bir ayrıştırıcı, bir haritacı, her neyse) oturabileceği bir şey olduğunu bulurum.
Arayüzlere gelince, sınıfın saplaması veya alay edilmesine ihtiyaç duymam beni tahrik ediyor. Depolar gibi şeyler, genellikle saplama veya alay etmek istiyorum. Bir entegrasyon testindeki bir haritacı (genellikle) çok fazla değil.

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.