Jakie są najlepsze praktyki dotyczące testowania modułów w rspec? Mam kilka modułów, które są zawarte w kilku modelach i na razie po prostu mam zduplikowane testy dla każdego modelu (z kilkoma różnicami). Czy jest sposób, aby go WYSUSZAĆ?
ruby
unit-testing
rspec
Andrius
źródło
źródło
let(:dummy_class) { Class.new { include ModuleToBeTested } }
let(:class_instance) { (Class.new { include Super::Duper::Module }).new }
ten sposób otrzymuję zmienną instancji, która jest najczęściej używana do testowania w jakikolwiek sposób.include
nie działa dla mnie, aleextend
działalet(:dummy_class) { Class.new { extend ModuleToBeTested } }
subject(:instance) { Class.new.include(described_class).new }
Co powiedział Mike. Oto trywialny przykład:
kod modułu ...
fragment specyfikacji ...
źródło
include Say
znalazłeś się w deklaracji DummyClass zamiast dzwonićextend
?extend
wchodzi do instancji klasy, czyli ponew
wywołaniu. Jeśli robiłeś to wcześniej,new
to masz rację, byś użyłinclude
DummyClass
stałą? Dlaczego nie po prostu@dummy_class = Class.new
? Teraz zanieczyszczasz środowisko testowe niepotrzebną definicją klasy. Ta DummyClass jest zdefiniowana dla każdej z twoich specyfikacji, aw następnej specyfikacji, w której zdecydujesz się użyć tego samego podejścia i ponownie otworzyć definicję DummyClass, może już coś zawierać (chociaż w tym trywialnym przykładzie definicja jest całkowicie pusta, w prawdziwym życiu przypadków użycia jest prawdopodobne, że coś zostanie dodane w pewnym momencie, a potem to podejście stanie się niebezpieczne.)W przypadku modułów, które można testować w izolacji lub przez wyśmiewanie klasy, podoba mi się coś w stylu:
moduł:
specyfikacja:
Przejmowanie zagnieżdżonych grup przykładów może wydawać się niewłaściwe, ale podoba mi się zwięzłość. jakieś pomysły?
źródło
let
metody opisanej przez @metakungfu jest lepsze.Znalazłem lepsze rozwiązanie na stronie domowej rspec. Najwyraźniej obsługuje wspólne grupy przykładowe. Z https://www.relishapp.com/rspec/rspec-core/v/2-13/docs/example-groups/shared-examples !
źródło
Na samą myśl, czy mógłbyś utworzyć fikcyjną klasę w swoim skrypcie testowym i dołączyć do niej moduł? Następnie sprawdź, czy fikcyjna klasa zachowuje się w oczekiwany sposób.
EDYCJA: Jeśli, jak wskazano w komentarzach, moduł oczekuje pewnych zachowań w klasie, do której jest zmieszany, to spróbuję zaimplementować manekiny tych zachowań. Wystarczająco, aby moduł był szczęśliwy z wykonywania swoich obowiązków.
To powiedziawszy, byłbym trochę zdenerwowany moim projektem, gdy moduł oczekuje dużo od swojej klasy hosta (czy mówimy „host”?) - Jeśli nie dziedziczę już z klasy bazowej lub nie mogę wstrzyknąć nową funkcjonalność w drzewie dziedziczenia, myślę, że spróbuję zminimalizować wszelkie takie oczekiwania, jakie może mieć moduł. Martwię się, że mój projekt zacznie rozwijać pewne obszary nieprzyjemnej sztywności.
źródło
Zaakceptowana odpowiedź jest właściwą, myślę, ale chciałem dodać przykład, jak używać rpseców
shared_examples_for
iit_behaves_like
metod. Wspominam o kilku sztuczkach we fragmencie kodu, ale aby uzyskać więcej informacji, zobacz ten przewodnik relishapp-rspec .Dzięki temu możesz przetestować swój moduł w dowolnej klasie, która go zawiera. Więc naprawdę testujesz to, czego używasz w swojej aplikacji.
Zobaczmy przykład:
Teraz stwórzmy specyfikację dla naszego modułu:
movable_spec.rb
źródło
Co powiesz na:
źródło
Sugerowałbym, aby w przypadku większych i często używanych modułów wybrać „Wspólne grupy przykładowe”, zgodnie z sugestią @Andrius tutaj . W przypadku prostych rzeczy, dla których nie chcesz mieć kłopotów z posiadaniem wielu plików itp., Oto jak zapewnić maksymalną kontrolę nad widocznością twoich atrap (testowane z rspec 2.14.6, po prostu skopiuj i wklej kod do pliku spec i uruchom go):
źródło
subject { dummy_class.new }
działa. Sprawa zsubject { dummy_class }
nie działa dla mnie.moja ostatnia praca, przy użyciu jak najmniejszej ilości okablowania
chciałbym
zadziałało, ale nie działa (jak w Ruby MRI 2.2.3 i RSpec :: Core 3.3.0)
Oczywiście opisana klasa nie jest widoczna w tym zakresie.
źródło
Aby przetestować swój moduł, użyj:
Aby wysuszyć niektóre rzeczy, których używasz w wielu specyfikacjach, możesz użyć wspólnego kontekstu:
Zasoby:
źródło
Możesz także użyć typu pomocnika
Oto dokumentacja: https://www.relishapp.com/rspec/rspec-rails/v/3-3/docs/helper-specs/helper-spec
źródło
musisz po prostu dołączyć swój moduł do pliku
mudule Test module MyModule def test 'test' end end end
specyfikacji w pliku specyfikacjiRSpec.describe Test::MyModule do include Test::MyModule #you can call directly the method *test* it 'returns test' do expect(test).to eql('test') end end
źródło
Jedno z możliwych rozwiązań do testowania metod modułów, które są niezależne od klasy, która je będzie zawierała
I specyfikację tego
A jeśli chcesz je przetestować na SUCHO , to shared_examples jest dobrym podejściem
źródło
subject(:module_to_test_instance) { Class.new.include(described_class) }
. W przeciwnym razie nie widzę nic złego w Twojej odpowiedzi.Jest to powtarzający się wzorzec, ponieważ będziesz musiał przetestować więcej niż jeden moduł. Z tego powodu tworzenie pomocnika do tego jest bardziej niż pożądane.
Znalazłem ten post, który wyjaśnia, jak to zrobić, ale radzę sobie tutaj, ponieważ witryna może zostać w pewnym momencie usunięta.
Ma to na celu uniknięcie sytuacji, w których instancje obiektu nie implementują metody instancji:: dowolny błąd, który otrzymasz podczas próby użycia
allow
metoddummy
klasy.Kod:
W
spec/support/helpers/dummy_class_helpers.rb
W
spec/spec_helper.rb
W twoich specyfikacjach:
źródło