Bağımlılık enjeksiyonuna kademeli yaklaşımlar


12

Bağımlılık enjeksiyonunu kullanarak sınıflarımı birim test edilebilir hale getirmeye çalışıyorum. Ancak bu sınıfların bazılarının çok fazla müşterisi var ve henüz bağımlılıkları geçmeye başlamak için hepsini yeniden düzenlemeye hazır değilim. Bu yüzden yavaş yavaş yapmaya çalışıyorum; Şimdilik varsayılan bağımlılıkları koruyor, ancak test için geçersiz kılınmasına izin veriyor.

Koyduğum bir yaklaşım, tüm "yeni" çağrıları kendi yöntemlerine taşımaktır, örneğin:

public MyObject createMyObject(args) {
  return new MyObject(args);
}

Sonra benim birim testleri, sadece bu sınıfın alt sınıf ve oluşturma işlevleri geçersiz kılabilir, böylece yerine sahte nesneler oluşturun.

Bu iyi bir yaklaşım mı? Herhangi bir dezavantajı var mı?

Daha genel olarak, test için değiştirebileceğiniz sürece kodlanmış bağımlılıklara sahip olmak uygun mudur? Tercih edilen yaklaşımın bunları yapıcıda açıkça talep etmek olduğunu biliyorum ve sonunda oraya ulaşmak istiyorum. Ama bunun iyi bir ilk adım olup olmadığını merak ediyorum.

Benim başıma gelen bir dezavantaj: test etmeniz gereken gerçek alt sınıflarınız varsa, ana sınıf için yazdığınız test alt sınıfını tekrar kullanamazsınız. Her gerçek alt sınıf için bir test alt sınıfı oluşturmanız gerekir ve aynı oluşturma işlevlerini geçersiz kılmanız gerekir.


Neden şimdi birim test edilemediklerini açıklayabilir misiniz?
Austin Salonen

Statik sınıfların ve singletonların birçok kullanımının yanı sıra, kod boyunca dağılmış bir sürü "yeni X" vardır. Bu yüzden bir sınıfı test etmeye çalıştığımda, gerçekten bir sürü testi test ediyorum. Bağımlılıkları yalıtabilir ve sahte nesnelerle değiştirebilirsem, test üzerinde daha fazla kontrole sahip olurum.
JW01

Yanıtlar:


13

Bu, başlamanız için iyi bir yaklaşımdır. O Not en önemli ünite testleri ile mevcut kod kapatmak olmasına testleri yaptıktan sonra, tasarımınızı daha da geliştirmek için daha özgürce yeniden düzenleyebilirsiniz.

Bu yüzden ilk nokta, tasarımı zarif ve parlak yapmak değil - sadece kod birimini en az riskli değişikliklerle test edilebilir yapmak . Birim testleri olmadan, kodunuzu kırmamak için ekstra muhafazakar ve dikkatli olmalısınız. Bu ilk değişiklikler, kodun bazı durumlarda daha beceriksiz veya çirkin görünmesine bile neden olabilir - ancak ilk birim testlerini yazmanıza izin verirlerse, sonunda aklınızdaki ideal tasarıma yeniden bakabilirsiniz.

Bu konuda okunacak temel çalışma Eski Kod ile Etkili Çalışmaktır . Yukarıda gösterdiğiniz hileyi ve daha birçok dili kullanarak çok daha fazlasını açıklar.


Sadece bu konuda bir açıklama "testleri bir kez, daha özgürce refactor olabilir" - Eğer testleri yoksa, yeniden düzenleme değil, sadece kodu değiştiriyorsunuz.
ocodo

@Slomojo Sizi anlıyorum, ancak yine de testler olmadan birçok güvenli yeniden düzenleme yapabilirsiniz, özellikle (Java için tutulmada) yöntemlere yinelenen kod çıkarma, her şeyi yeniden adlandırma, hareketli sınıflar ve alanları çıkarma, sabitler vs
Alb

Gerçekten sadece bir test çerçevesi tarafından regresyon hatalarından korunan gelişmiş kalıplara kod değiştiren Refactoring teriminin kökenleri atıfta bulunuyorum. Tabii ki, IDE tabanlı yeniden düzenleme yazılımı 'refactor' için çok daha önemsiz hale getirdi, ancak yazılımımın testi yoksa kendi yanılsamasından kaçınmayı tercih ediyorum ve sadece "refactor" kodunu değiştiriyorum. Tabii ki, başka birine söylediğim bu olmayabilir;)
ocodo

1
@Alb, testler olmadan yeniden düzenleme her zaman daha risklidir. Otomatik yeniden düzenleme işlemleri bu riski azalttığından emin olmakla birlikte sıfıra indirmez. Aletlerin doğru şekilde işleyemeyeceği her zaman zor kenarlı durumlar vardır. Daha iyi durumda sonuç, araçtan bir hata mesajıdır, ancak en kötü durumda sessizce ince hataları ortaya çıkarabilir. Bu nedenle, otomatik araçlarla bile mümkün olan en basit ve en güvenli değişiklikleri yapmanız önerilir.
Péter Török

3

Guice-millet,

@Inject
public void setX(.... X x) {
   this.x = x;
}

tanımlarına @Inject eklemek yerine tüm özellikler için. Bu, onları newtest ederken (ve özellikleri manuel olarak ayarlarken) ve @ Üretimde enjekte ederken yapabileceğiniz normal fasulye olarak işlemenizi sağlar.


3

Bu tür bir sorunla karşılaştığımda sınıftan sınava her bağımlılığımı belirleyeceğim ve bunları geçirmeme izin verecek korumalı bir kurucu oluşturacağım. Bu, her biri için bir ayarlayıcı oluşturmakla aynı şeydir, ancak Gelecekte bunları somutlaştırmayı unutmamak için kurucularıma bağımlılıklar bildirmek.

Yeni birim test edilebilir sınıfımda 2 kurucu olacak:

public MyClass() { 
  this(new Client1(), new Client2()); 
}

public MyClass(Client1 client1, Client2 client2) { 
  this.client1 = client1; 
  this.client2 = client2; 
}

2

Enjekte edilen bağımlılığı kullanabilene kadar "alıcı yaratır" deyimini dikkate almak isteyebilirsiniz.

Örneğin,

public class Example {
  private MyObject myObject=null;

  public MyObject getMyObject() {
    if (myObject==null) {
      myObject=new MyObject();
    } 
    return myObject;
  }

  public void setMyObject(MyObject myObject) {
    this.myObject=myObject;
  }

  private void myMethod() {
    if (getMyObject().doSomething()) {
      // Instance automatically created
    }
  }
}

Bu, myObject'inize alıcıdan başvurabilmeniz için dahili olarak yeniden düzenleme yapmanıza olanak tanır. Asla aramak zorunda değilsin new. Gelecekte, tüm istemciler bağımlılık enjeksiyonuna izin verecek şekilde yapılandırıldığında, yapmanız gereken tek şey oluşturma kodunu tek bir yerde kaldırmaktır - alıcı. Ayarlayıcı, sahte nesneleri gerektiği gibi enjekte etmenize izin verecektir.

Yukarıdaki kod sadece bir örnektir ve doğrudan dahili durumu ortaya koyar. Bu yaklaşımın kod tabanınız için uygun olup olmadığını dikkatlice düşünmelisiniz.

Ayrıca , büyük bir yeniden düzenleme başarısı elde etmek için birçok yararlı ipucu içeren " Eski Kodla Etkili Çalışma " yı okumanızı da tavsiye ederim .


Teşekkürler. Bazı durumlarda bu yaklaşımı düşünüyorum. Ancak MyObject yapıcısı yalnızca sınıfınızın içinden erişilebilen parametreler gerektirdiğinde ne yaparsınız? Ya da sınıfınızın ömrü boyunca birden fazla MyObject oluşturmanız gerektiğinde? Bir MyObjectFactory enjekte etmek zorunda mısınız?
JW01

@ JW01 Alıcının yaratıcısı kodunu sınıfınızdan dahili durumu okuyacak ve sadece sığacak şekilde yapılandırabilirsiniz. Ömür boyunca birden fazla örnek oluşturmak düzenleme yapmak zor olacaktır. Bu durumla karşılaşırsanız, etrafta çalışmak yerine yeniden tasarlamayı öneririm. Alıcılarınızı çok karmaşık hale getirmeyin, yoksa boynunuzda bir değirmen taşı haline gelirler. Hedefiniz yeniden düzenleme sürecini kolaylaştırmaktır. Çok zor görünüyorsa, onu düzeltmek için farklı bir alana gidin.
Gary Rowe

bu bir singleton. Sadece singleton O_O kullanmayın
CoffeDeveloper

@DarioOO Aslında çok zayıf bir singleton. Daha iyi bir uygulama Josh Bloch'a göre bir numaralandırma kullanır. Singletonlar geçerli bir tasarım modelidir ve kullanımları vardır (pahalı bir kerelik oluşturma vb.).
Gary Rowe
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.