2008-09-04 13 views
8

Google test blogunu okuyordum ve global durumun kötü olduğunu ve test yazmayı zorlaştırdığını söylüyor. İnanıyorum - kodumun şu anda test edilmesi zor. Peki küresel durumdan nasıl kaçınırım?Genel durumdan nasıl kurtulabilirim?

Global durumu kullandığım en büyük şey (anladığım kadarıyla) geliştirme, kabul ve üretim ortamları arasındaki önemli bilgileri yönetmektir. Örneğin, "DBConnectionString" adlı statik bir üyeye sahip "Globals" adlı statik bir sınıfım var. Uygulama yüklendiğinde, hangi bağlantı dizesinin yükleneceğini belirler ve Globals.DBConnectionString değerini doldurur. Globals sınıfında dosya yollarını, sunucu adlarını ve diğer bilgileri yüklerim.

Bazı işlevlerim global değişkenlere dayanıyor. Yani, işlevlerimi test ettiğimde, önce belirli küreselleri ayarlamayı veya testlerin başarısız olacağını hatırlamalıyım. Bundan kaçınmak isterim.

Durum bilgisini yönetmenin iyi bir yolu var mı? (Ya da global durumu yanlış anlıyor muyum?)

cevap

10

Bağımlılık enjeksiyonu, aradığınız şeydir. Bu işlevler dışarı çıkmak ve bağımlılıklarını aramak yerine, bağımlılıkları işlevlere enjekte eder. Yani, işlevleri çağırdığınızda, onlara istedikleri verileri iletirsiniz. Bu şekilde bir sınıfa bir deneme çerçevesi koymak kolaydır, çünkü uygun durumlarda sahte nesneleri basitçe enjekte edebilirsiniz.

Bazı global durumlardan kaçınmak zor, ancak bunu yapmanın en iyi yolu, uygulamanızın en üst düzeyindeki fabrika sınıflarını kullanmaktır ve bu en üst seviyenin altındaki her şey bağımlılık enjeksiyonuna dayanmaktadır.

İki temel fayda: Bir, test çok daha kolay bir iştir ve iki, uygulamanız çok daha gevşek bir şekilde birleştirilmiştir. Uygulaması yerine bir sınıfın arayüzüne karşı programlayabilmeye güveniyorsunuz.

1

Harika bir ilk soru.

Kısa yanıt: uygulamanızın tüm girişlerinden (örtük olanlar da dahil) kendi çıktılarına bir işlev olduğundan emin olun.

Tanımladığınız sorun, genel durum gibi görünmüyor. En azından değişmez durum. Daha ziyade, tanımladığınız şey genellikle "Yapılandırma Sorunu" olarak adlandırılana benziyor ve bir takım çözümlere sahip. Java kullanıyorsanız, Guice gibi hafif ağırlıklı enjeksiyon çerçevelerine bakmak isteyebilirsiniz. Scala'da, bu genellikle implicits ile çözülür. Bazı dillerde, programınızı çalışma zamanında yapılandırmak için başka bir program yükleyebileceksiniz. Smalltalk'ta yazılan sunucuları yapılandırmak için kullandığımız gibi, yapılandırma dosyası başka bir Haskell programı olan Xmonad adlı Haskell'de yazılmış bir pencere yöneticisi kullanıyorum. Testlerinizi entegrasyon testleri yerine ünite testleri ne yapıyorsun böyle ardından veritabanları veya dosya sistemleri olarak fiili kaynaklarını içeren eğer

2

unutmayın. Entegrasyon testleri bazı ön kurulumları gerektirirken, birim testleri bağımsız olarak çalışabilmelidir.

Böyle Kale Windsor olarak ancak gibi yol yaklaşımının bir orta almak mümkün olabilir basit durumlar için bağımlılık enjeksiyon çerçeve kullanıma görünebilir: En olurdu Gerçekte

public interface ISettingsProvider 
{ 
    string ConnectionString { get; } 
} 

public class TestSettings : ISettingsProvider 
{   
    public string ConnectionString { get { return "testdatabase"; } }; 
} 

public class DataStuff 
{ 
    private ISettingsProvider settings; 

    public DataStuff(ISettingsProvider settings) 
    { 
     this.settings = settings; 
    } 

    public void DoSomething() 
    { 
     // use settings.ConnectionString 
    } 
} 

muhtemelen uygulamanızdaki yapılandırma dosyalarından okunur.Eğer bunun için hazırsanız, değiştirilebilen konfigürasyonlara sahip tam üfleme bir DI çerçevesi gitmenin yoludur, ancak bunun Globals.ConnectionString'i kullanmanın en azından daha iyi olduğunu düşünüyorum.

0

bir MVC ortamda bağımlılık enjeksiyon örneği, buraya:

index.php

$container = new Container(); 
include_file('container.php'); 

container.php

container.add("database.driver", "mysql"); 
container.add("database.name","app"); 

...

$container.add(new Database($container->get('database.driver', "database.name")), 'database'); 
$container.add(new Dao($container->get('database')), 'dao'); 
$container.add(new Service($container->get('dao'))); 
$container.add(new Controller($container->get('service')), 'controller'); 

$container.add(new FrontController(),'frontController'); 

index.php burada devam ediyor:

$frontController = $container->get('frontController'); 
$controllerClass = $frontController->getController($_SERVER['request_uri']); 
$controllerAction = $frontController->getAction($_SERVER['request_uri']); 
$controller = $container->get('controller'); 
$controller->$action(); 

Ve orada o var, kontrolör bağlı olan bir servis katmanı nesneye bağlıdır veritabanı sürücüsüne bağlıdır sahip bir veritabanı nesnesi bağlı olan bir dao (veri erişim nesnesi) nesne, isim vb

İlgili konular