2013-03-06 13 views
36

W dokumencie rspec podano, że powinienem użyć metody double w celu utworzenia podwójnego testu. Ale widzę, że działa doskonale, nawet jeśli nie używam double. Czy jest coś nie tak z nieużywaniem double? Również jeśli nie używam podwójnie jak MyClass dostaje stub i inne metody rspec? Czy są one dostępne dla wszystkich obiektów podczas działania w rspec?Do czego służy metoda podwójna w rspec?

require 'spec_helper' 

class MyClass 

    def self.run 
     new.execute 
    end 

    def execute 
     'foo' 
    end 

end 

describe MyClass do 

    it 'should stub instance method' do 
     obj = MyClass.new 
     obj.stub(:execute).and_return('bar') 
     obj.execute.should == 'bar' 
    end 

    it 'should stub class method' do 
     MyClass.stub(:run).and_return('baz') 
     MyClass.run.should == 'baz' 
    end 

end 

Odpowiedz

40

Edit: Właśnie ponownie przeczytać pytanie i zrozumiał, że nie dość odpowiedzieć. Pozostawiając moją oryginalną odpowiedź, ponieważ jest ona powiązana, ale tutaj jest twoja konkretna odpowiedź:

Powodem, dla którego nie potrzebujesz podwójnego, jest upieranie metod klasowych, a nie metod instancji. double jest użyteczny tylko w przypadku wystąpienia instancji klasy, a nie samej klasy.

Old odpowiedź, która wyjaśnia niektóre dwukrotnie więcej:

Należy zawsze kiedy można używać prawdziwych klas zamiast podwójnej testowych. Spowoduje to zwiększenie liczby kodu i sprawi, że testy staną się bardziej kompleksowe. Podwójne testy są używane w sytuacjach, gdy nie możesz lub nie powinieneś używać prawdziwego obiektu. Na przykład, jeśli nie można utworzyć instancji klasy bez trafienia w zasób zewnętrzny (np. Sieć lub bazę danych) lub ma dużą liczbę zależności, a testujesz coś, co go używa, możesz utworzyć podwójne i odgadnij niektóre metody na podwójnym.

Oto bardziej szczegółowy przykład: powiedzmy, że testują MyClass, ale w celu utworzenia wystąpienia MyClass, trzeba przejść w FooLogger:

mylogger = FooLogger.new 
myclass = MyClass.new logger: mylogger 

Jeśli FooLogger.new otwiera gniazdo syslog i zaczyna spamowanie to dobrze za każdym razem, gdy przeprowadzisz testy, będziesz się logował. Jeśli nie chcesz spamować dzienników podczas tego testu, można zamiast tworzyć dublet dla FooLogger i skrótową się metodę na nim:

mylogger = double(FooLogger) 
mylogger.stub(:log) 
myclass = MyClass.new logger: mylogger 

Ponieważ większość dobrze zaprojektowane klasy mogą być instancja bez ubocznych efekty, zazwyczaj można użyć zamiast tego zwykłego obiektu zamiast podwójnego, a zamiast tego stosować metody pośrednie. Istnieją inne scenariusze, w których klasy mają wiele zależności, które sprawiają, że są trudne do utworzenia, a duble są sposobem na pokonanie cruftu i przetestowanie rzeczy, na której naprawdę zależy.

Z mojego doświadczenia wynika, że ​​potrzeba użycia podwójnego to zapach kodu, ale często musimy używać klas, których nie możemy łatwo zmienić (np. Z klejnotu), więc jest to narzędzie, którego możesz potrzebować od czasu do czasu .

+0

Rzeczywiście, jeśli spojrzeć na moim przykładzie, pierwsze Spec stubs metody instancji ** ** a drugi stubs ** metody klasy **. Wygląda na to, że obie działają dobrze, bez wcześniej używanego "podwójnego". Dlatego zastanawiam się, co daje mi dodatkowa magia "double". – grafthez

+0

Spójrz na ten przykład Stworzyłem https://gist.github.com/anonymous/5101448. Jeśli chcę przetestować 'SchedulerJob', potrzebuję stub' RequestSchedule' i fałszywe 'RequestToQueuePusher' w prawo? Również przeszkadza mi to, że 'SchedulerJob' jest ściśle sprzężony z dwiema pozostałymi klasami. Ponieważ pochodzę ze świata Java, normalnie wyodrębniam je jako zależności, ponieważ nie ma łatwego sposobu na fałszowanie obiektów, które są tworzone na sztywno. W Ruby nie wydaje się to problemem. Widzę wiele obiektów takich jak moje 'SchedulerJob'. Wiem, że istnieje sposób na łatwe ich sfałszowanie, ale dla mnie jest to niezgodne z niektórymi zasadami SOLID – grafthez

+0

To także kiepski projekt w świecie Ruby. Powinien istnieć sposób wstrzyknięcia zależności RequestSchedule, aby ułatwić testowanie. Możesz zrobić coś takiego: 'fakeschedule = double (RequestSchedule); RequestSchedule.stub (: new) .and_return (fakeschedule); '. To z pewnością powinno być refaktoryzowane. –

0

Z RSpec Mocks 3.0 zmieniło się zachowanie podwójnych. Możesz teraz verify doubles, co oznacza, że ​​"RSpec sprawdzi, czy metody stubbed są rzeczywiście obecne na obiekcie bazowym, jeśli są dostępne", ale "nie sprawdzi się, jeśli ukryty obiekt lub klasa nie jest zdefiniowana".

Weryfikacja podwójnych żądań specyficznych dla podwójnego typu (instancja, klasa, obiekt, klasa dynamiczna, częściowa).Oto przykład z RSpec Relish na wystąpienie podwójnego:

RSpec.describe User, '#suspend!' do 
    it 'notifies the console' do 
    notifier = instance_double("ConsoleNotifier") 

    expect(notifier).to receive(:notify).with("suspended as") 

    user = User.new(notifier) 
    user.suspend! 
    end 
end