RSpec Testlerinizi Paylaşılan Örnekler Kullanarak KURUTMA

" Bir ağacı kesmem için bana altı saat verin, ilk dördünü baltayı bilemekle geçireceğim." - Abraham Lincoln

Birkaç hafta önce bir projeyi yeniden düzenlediğimde, zamanımın çoğunu teknik özellikler yazarak geçirdim. Bazı API'ler için birkaç benzer test senaryosu yazdıktan sonra, bu yinelemenin çoğundan kurtulup kurtulamayacağımı merak etmeye başladım.

Bu yüzden KURUTMA testleri için en iyi uygulamaları okumaya kendimi verdim (Kendini Tekrar Etme). Ve bu Bildiğim geldi nasıl shared examplesve shared contexts.

Benim durumumda, paylaşılan örnekler kullanmaya başladım. Ve işte bunları uygulamaktan şimdiye kadar öğrendiklerim.

Benzer davranışı tanımlayan birden fazla spesifikasyona sahip olduğunuzda, gereksiz örnekleri shared examplesbirden fazla spesifikasyona çıkarmak ve bunları kullanmak daha iyi olabilir .

Kullanıcı ve Gönderi olmak üzere iki modeliniz olduğunu ve bir kullanıcının birçok gönderisi olabileceğini varsayalım . Kullanıcılar, kullanıcı ve gönderi listesini görüntüleyebilmelidir. Kullanıcılarda ve gönderi kontrolörlerinde bir indeks eylemi oluşturmak bu amaca hizmet edecektir.

İlk olarak, kullanıcı denetleyicisi için indeks eyleminizin özelliklerini yazın. Kullanıcıları getirme ve onları uygun düzende oluşturma sorumluluğuna sahip olacaktır. Ardından testlerin başarılı olması için yeterli kod yazın.

# users_controller_spec.rbdescribe "GET #index" do before do 5.times do FactoryGirl.create(:user) end get :index end it { expect(subject).to respond_with(:ok) } it { expect(subject).to render_template(:index) } it { expect(assigns(:users)).to match(User.all) }end
# users_controller.rbclass UsersController < ApplicationController .... def index @users = User.all end ....end

Tipik olarak, herhangi bir denetleyicinin dizin eylemi, gereken şekilde birkaç kaynaktan veri alır ve toplar. Ayrıca sayfalandırma, arama, sıralama, filtreleme ve kapsam belirlemeyi de ekler.

Son olarak, tüm bu veriler API'ler kullanılarak HTML, JSON veya XML aracılığıyla görünümlere sunulur. Örneğimi basitleştirmek için, kontrolörlerin indeks eylemleri sadece verileri alacak, ardından bunları görünümler yoluyla gösterecektir.

Aynısı post kontrolöründeki indeks eylemi için de geçerlidir:

describe "GET #index" do before do 5.times do FactoryGirl.create(:post) end get :index end it { expect(subject).to respond_with(:ok) } it { expect(subject).to render_template(:index) } it { expect(assigns(:posts)).to match(Post.all) }end
# posts_controller.rbclass PostsController < ApplicationController .... def index @posts = Post.all end ....end

Hem kullanıcılar hem de gönderi denetleyicisi için yazılan RSpec testleri çok benzer. Her iki kontrolörde de var:

  • Yanıt kodu - 'Tamam' olmalıdır
  • Her iki dizin eylemi de uygun kısmi veya görünümü oluşturmalıdır - bizim durumumuzda index
  • Gönderiler veya kullanıcılar gibi oluşturmak istediğimiz veriler

İndeks eylemimizin özelliklerini kullanarak KURUYALIM shared examples.

Paylaşılan örneklerinizi nereye koyacaksınız

Paylaşılan örnekleri specs / support / shared_examples dizini içine yerleştirmeyi seviyorum, böylece tüm shared exampleilişkili dosyalar otomatik olarak yüklenir.

shared examplesBurada konumunuzu bulmak için yaygın olarak kullanılan diğer kuralları okuyabilirsiniz : paylaşılan örnekler belgeleri

Paylaşılan bir örnek nasıl tanımlanır

Dizin eyleminiz 200 başarı kodu (Tamam) ile yanıt vermeli ve dizin şablonunuzu oluşturmalıdır.

RSpec.shared_examples "index examples" do it { expect(subject).to respond_with(:ok) } it { expect(subject).to render_template(:index) }end

itBloklarınızın dışında - ve kancalarınızdan önce ve sonra - letbloklar ekleyebilir , bağlam ekleyebilir ve içinde de tanımlanabilen blokları tanımlayabilirsiniz shared examples.

Kişisel olarak paylaşılan örnekleri basit ve öz tutmayı tercih ediyorum ve bağlam eklemiyorum ve bloklara izin vermem. shared examplesBlok da aşağıda ele alacağız parametrelerini kabul eder.

Paylaşılan örnekler nasıl kullanılır

Ekleme include_examples "index examples"kullanıcılarınız ve mesajlar denetleyici özellikleri için testlere “endeks örneklerini” içerir.

# users_controller_spec.rbdescribe "GET #index" do before do 5.times do FactoryGirl.create(:user) end get :index end include_examples "index examples" it { expect(assigns(:users)).to match(User.all) }end
# similarly, in posts_controller_spec.rbdescribe "GET #index" do before do 5.times do FactoryGirl.create(:post) end get :index end include_examples "index examples" it { expect(assigns(:posts)).to match(Post.all) }end

Bu durumda , it_behaves_likeveya it_should_behaves_likeyerine de kullanabilirsiniz include_examples. it_behaves_likeve it_should_behaves_likeaslında takma adlardır ve aynı şekilde çalışırlar, böylece birbirlerinin yerine kullanılabilirler. Ama include_examplesve it_behaves_likefarklılar.

Resmi belgelerde belirtildiği gibi:

  • include_examples - mevcut bağlamdaki örnekleri içerir
  • it_behaves_likeve it_should_behave_likeörnekleri iç içe bir bağlamda dahil edin

Bu ayrım neden önemlidir?

RSpec'in belgeleri uygun bir cevap verir:

Geçerli bağlama birden çok kez parametreleştirilmiş örnekleri dahil ettiğinizde, önceki yöntem tanımlarını geçersiz kılabilir ve son bildirim kazanır.

Eğer bir durumla karşı karşıya Yani parametreli örnekler aynı bağlamda diğer yöntemlerle çelişen, takabilmek yöntemleri içermesi nerede include_examplesile it_behaves_likeyöntemle. Bu, iç içe geçmiş bir bağlam oluşturacak ve bu tür durumlardan kaçınacaktır.

Kullanıcılarınızın denetleyici özelliklerinde aşağıdaki satırı kontrol edin ve denetleyici özelliklerini yayınlayın:

it { expect(assigns(:users)).to match(User.all) }it { expect(assigns(:posts)).to match(Post.all) }

Artık denetleyici özellikleriniz, aşağıdaki gibi paylaşılan örneğe parametreler iletilerek daha da yeniden faktörlendirilebilir:

# specs/support/shared_examples/index_examples.rb
# here assigned_resource and resource class are parameters passed to index examples block RSpec.shared_examples "index examples" do |assigned_resource, resource_class| it { expect(subject).to respond_with(:ok) } it { expect(subject).to render_template(:index) } it { expect(assigns(assigned_resource)).to match(resource_class.all) }end

Şimdi, kullanıcılarınızda aşağıdaki değişiklikleri yapın ve denetleyici özelliklerini yayınlayın:

# users_controller_spec.rbdescribe "GET #index" do before do ... end include_examples "index examples", :users, User.allend
# posts_controller_spec.rbdescribe "GET #index" do before do ... end include_examples "index examples", :posts, Post.allend

Artık denetleyici özellikleri temiz, daha az yedekli ve daha da önemlisi KURU görünüyor. Ayrıca, bu indeks örnekleri, diğer kontrolörlerin indeks eylemini tasarlamak için temel yapılar olarak hizmet edebilir.

Sonuç

Yaygın örnekleri ayrı bir dosyaya taşıyarak, yinelemeyi ortadan kaldırabilir ve uygulamanız genelinde denetleyici eylemlerinizin tutarlılığını artırabilirsiniz. Bu, API'lerin tasarlanması durumunda çok kullanışlıdır, çünkü RSpec testlerinin mevcut yapısını testler tasarlamak ve ortak yanıt yapınıza uyan API'ler oluşturmak için kullanabilirsiniz.

Çoğunlukla, API'lerle çalışırken, shared examplesbenzer API'ler tasarlamak için bana ortak bir yapı sağlamak için kullanıyorum.

Kullanarak özelliklerinizi nasıl KURUYORSANIZ paylaşabilirsiniz shared examples.