2013-06-07 10 views
5

Birim sınamaları yazdığım zamanlar, initialize yönteminin çağrılmasına gerek kalmadan bir sınıfı başlatmam gerekir. Mesela, kurucu yine de saplamalarla değiştireceğim diğer sınıfları başlattığında. Örneğin:Bir Ruby sınıfını başlatmayı çağırmadan başlatmak mümkün mü?

class SomeClassThatIWillTest 
    def initialize 
    @client = GoogleAnalyticsClient.new 
    @cache = SuperAdvancedCacheSystem.new 
    end 

    # ... 
end 

bir testte ben muhtemelen taslakları ile hem @client ve @cache yerini alacak, bu yüzden oldukça yapıcı çağrılan asla ediyorum. Bana yardımcı olabilecek herhangi bir kara büyü var mı?

+0

Alt sınıftaki "SomeClassThatIWillTest" alt sınıfını ve üzerine yazma işlemini başlatmaya ne dersiniz? Kara büyü yok;) – tessi

+0

@tessi: Bu gerçekten güzel bir fikir! Ve ışıl ışıl çalıştı. – Hubro

+0

@Codemonkey Hayır Kısmen geri alıyorum - eğer bunları içsel olarak imhadan tahribata (eğer harici modifikasyon olmadan) yönetecekse, enjekte edilmeleri gerekmeyebilir. üzerinde http://programmers.stackexchange.com/questions/130711/should-i-pass-an-object-into-a-constructor-or-instantiate-in-class –

cevap

1

Alt sınıfta SomeClassThatIWillTest alt sınıflama ve initialize üzerine yazma hakkında ne dersiniz? katılan hiçbir kara büyü; onun bize gösterdi daha fazlası), ve sonrasında @client ve @cache değiştirirseniz)

hatta super başlatıcı diyebiliriz Bu şekilde (kendi kodunu test etmek. Bu yöntemi kullanarak bir MiniTest spec

Örnek: can

describe MyTestClass do 

    subject { 
    Class.new(MyTestClass) { 
     def initialize; end 
    } 
    } 

    it "must do something" do 
    subject.new.do_something.must_equal something 
    # ... 
    end 

end 
+0

Cevabınız için teşekkürler.Yorumunuzu okuduktan sonra bir kod örneği ile kendi yanıtımı yazdım, bu yüzden cevabımı sildim ve kod örneğini cevabınıza ekledim. Umarım bu iyidir. – Hubro

+0

Daha da fazlası serin :) Örnekler çok yardımcı oluyor. – tessi

+2

test edilmek üzere sınıfa tabi tutulan sınıfi artık test etmiyorsunuz, ancak (istenmeyen) davranışı değiştirebilecek bir alt sınıfa tabi tutuyorsunuz ve test ettiğinizin davranışını değiştirmek istemiyorsunuz (bu soru aslında bildiğim –

0

Hayır yapamazsınız (tessi'nin yorumuyla ilgili olarak alt sınıftan kısaltılmış). Ama bunun yerine bu:

def initialize 
    @client = GoogleAnalyticsClient.new 
    @cache = SuperAdvancedCacheSystem.new 
    end 
end 

getters tembel yükleme @client ve @cache düşünün ve örneğin kullanım için ayarlayıcılar ekleyerek

testlerinde.

4

Test edilmek üzere test edilen sınıfın davranışını değiştirmemelisiniz. Sınıfınız kurucuda daha fazla eyleme sahipse, her seferinde taklit etmeniz gerekecektir. Testiniz korumak için can sıkıcı olacak. Nesneleri (veya sınıfları) iki katına çıkarın.

Belki de oluşturulmuş nesnelere yapıcı için argümanlar olarak sağlanabilir? Sınıflarda new yöntemini kullanmadan çiftler kullanmanıza izin verir. yapabilirsiniz

sen RSpec kullanıyorsanız,:

GoogleAnalyticsClient.stub(new: double) 
SuperAdvancedCacheSystem.stub(new: double) 

beklenen arabirimi, ve işte eşleşmesi için çiftler tanımlayın! Kirli numaralar gerekmez.

15

Tabi. Class#new, bir nesneyi el ile ayırmaya ve başlatmaya gerek kalmadan kaydeden bir kolaylık yönteminden başka bir şey değildir. Onun uygulama aşağıdaki gibi kabaca görünür: Sadece yerine el Class#allocate arama ve initialize diyemezsin

class Class 
    def new(*args, **kwargs, &blk) 
    obj = allocate 
    obj.send(:initialize, *args, **kwargs, &blk) 
    obj 
    end 
end 

.

+0

'def self.new' değil mi? Bilgi için teşekkürler. – Surya

+0

Hayır, 'new',' Class' sınıfı bir örnek yöntemidir. * Ayrıca * bir 'Class :: new' singleton yöntemi vardır, ancak bu yeni sınıflar oluşturur, yani 'Class' örnekleri. 'Class # new'' Class' örneklerinin örneklerini, yani sınıfların örneklerini oluşturur. –

İlgili konular