RSpec에서 모듈 테스트
RSpec에서 모듈을 테스트할 때의 모범 사례는 무엇입니까?저는 몇 가지 모델에 포함된 몇 가지 모듈을 가지고 있으며, 현재는 각 모델에 대해 중복 테스트만 실시하고 있습니다(차이는 거의 없습니다).말릴 수 있는 방법이 있습니까?
래드웨이 =>
let(:dummy_class) { Class.new { include ModuleToBeTested } }
또는 모듈을 사용하여 테스트 클래스를 확장할 수 있습니다.
let(:dummy_class) { Class.new { extend ModuleToBeTested } }
앞에서 'let'을 사용하는 것이 인스턴스 변수를 사용하여 더미 클래스를 정의하는 것보다 좋습니다(:각).
마이크가 한 말.다음은 사소한 예입니다.
모듈 코드...
module Say
def hello
"hello"
end
end
규격 조각...
class DummyClass
end
before(:each) do
@dummy_class = DummyClass.new
@dummy_class.extend(Say)
end
it "get hello string" do
expect(@dummy_class.hello).to eq "hello"
end
분리하여 테스트하거나 클래스를 조롱하여 테스트할 수 있는 모듈의 경우, 저는 다음과 같은 것을 참조하십시오.
모듈:
module MyModule
def hallo
"hallo"
end
end
사양:
describe MyModule do
include MyModule
it { hallo.should == "hallo" }
end
중첩된 예제 그룹을 가로채는 것은 잘못된 것처럼 보일 수 있지만, 저는 간결함이 좋습니다.무슨 생각 있어요?
저는 rspec 홈페이지에서 더 좋은 해결책을 찾았습니다.보아하니 공유 예제 그룹을 지원하는 것 같습니다.출처: https://www.relishapp.com/rspec/rspec-core/v/2-13/docs/example-groups/shared-examples!
공유 예제 그룹
공유 예제 그룹을 만들고 해당 그룹을 다른 그룹에 포함할 수 있습니다.
크고 작은 제품의 모든 에디션에 적용되는 동작이 있다고 가정합니다.
먼저, "공유" 동작을 고려합니다.
shared_examples_for "all editions" do
it "should behave like all editions" do
end
end
그런 다음 대/소 버전에 대한 동작을 정의해야 할 경우 it_should_behave_like() 메서드를 사용하여 공유 동작을 참조합니다.
describe "SmallEdition" do
it_should_behave_like "all editions"
it "should also behave like a small edition" do
end
end
당신의 테스트 스크립트에 더미 클래스를 만들고 모듈을 거기에 포함시킬 수 있습니까?그런 다음 더미 클래스가 예상되는 방식으로 동작하는지 테스트합니다.
편집: 코멘트에서 지적한 것처럼 모듈이 혼합된 클래스에 일부 동작이 존재할 것으로 예상한다면, 저는 그러한 동작의 더미를 구현하려고 합니다.모듈이 자신의 임무를 수행하는 것을 행복하게 만들기에 충분합니다.
즉, 모듈이 호스트 클래스("호스트"라고 부릅니까?)에서 많은 것을 기대할 때 제 설계에 약간 신경이 쓰입니다. 기본 클래스에서 아직 상속되지 않았거나 상속 트리에 새 기능을 주입할 수 없다면 모듈이 가질 수 있는 모든 기대를 최소화하려고 노력할 것입니다.제가 걱정하는 것은 제 디자인이 불쾌한 융통성 없는 부분들을 발전시키기 시작할 것이라는 것입니다.
승인된 답변이 정답이라고 생각합니다만, rpsecs 사용 방법에 대한 예를 추가하고 싶습니다.shared_examples_for그리고.it_behaves_like방법들.코드 스니펫에서 몇 가지 요령을 언급하지만 자세한 내용은 이 relishapp-rspec-guide를 참조하십시오.
이를 통해 모듈이 포함된 모든 클래스에서 모듈을 테스트할 수 있습니다.즉, 애플리케이션에서 사용하는 것을 실제로 테스트하는 것입니다.
예를 들어 보겠습니다.
# Lets assume a Movable module
module Movable
def self.movable_class?
true
end
def has_feets?
true
end
end
# Include Movable into Person and Animal
class Person < ActiveRecord::Base
include Movable
end
class Animal < ActiveRecord::Base
include Movable
end
.movable_spec.rb
shared_examples_for Movable do
context 'with an instance' do
before(:each) do
# described_class points on the class, if you need an instance of it:
@obj = described_class.new
# or you can use a parameter see below Animal test
@obj = obj if obj.present?
end
it 'should have feets' do
@obj.has_feets?.should be_true
end
end
context 'class methods' do
it 'should be a movable class' do
described_class.movable_class?.should be_true
end
end
end
# Now list every model in your app to test them properly
describe Person do
it_behaves_like Movable
end
describe Animal do
it_behaves_like Movable do
let(:obj) { Animal.new({ :name => 'capybara' }) }
end
end
가능한 한 하드 드라이브를 적게 사용하는 내 최근 작업
require 'spec_helper'
describe Module::UnderTest do
subject {Object.new.extend(described_class)}
context '.module_method' do
it {is_expected.to respond_to(:module_method)}
# etc etc
end
end
좋겠다
subject {Class.new{include described_class}.new}
작동했지만 작동하지 않습니다(Ruby MRI 2.2.3 및 Rspec::코어 3.3.0)
Failure/Error: subject {Class.new{include described_class}.new}
NameError:
undefined local variable or method `described_class' for #<Class:0x000000063a6708>
descripted_class는 해당 범위에서 보이지 않습니다.
모듈을 테스트하려면 다음을 사용합니다.
describe MyCoolModule do
subject(:my_instance) { Class.new.extend(described_class) }
# examples
end
여러 사양에 걸쳐 사용하는 일부 항목을 건조하려면 다음과 같이 공유 컨텍스트를 사용할 수 있습니다.
RSpec.shared_context 'some shared context' do
let(:reused_thing) { create :the_thing }
let(:reused_other_thing) { create :the_thing }
shared_examples_for 'the stuff' do
it { ... }
it { ... }
end
end
require 'some_shared_context'
describe MyCoolClass do
include_context 'some shared context'
it_behaves_like 'the stuff'
it_behaves_like 'the stuff' do
let(:reused_thing) { create :overrides_the_thing_in_shared_context }
end
end
리소스:
다음은 어떻습니까?
describe MyModule do
subject { Object.new.extend(MyModule) }
it "does stuff" do
expect(subject.does_stuff?).to be_true
end
end
저는 더 크고 많이 사용되는 모듈의 경우 여기서 @Andrius가 제안한 "공유 예제 그룹"을 선택해야 한다고 제안합니다.여러 개의 파일이 있는 등의 문제를 겪고 싶지 않은 간단한 작업에 적합합니다.다음은 더미 물건의 가시성을 최대한 제어하는 방법입니다(rspec 2.14.6에 따라 코드를 복사하여 사양 파일에 붙여넣고 실행하기만 하면 됩니다).
module YourCoolModule
def your_cool_module_method
end
end
describe YourCoolModule do
context "cntxt1" do
let(:dummy_class) do
Class.new do
include YourCoolModule
#Say, how your module works might depend on the return value of to_s for
#the extending instances and you want to test this. You could of course
#just mock/stub, but since you so conveniently have the class def here
#you might be tempted to use it?
def to_s
"dummy"
end
#In case your module would happen to depend on the class having a name
#you can simulate that behaviour easily.
def self.name
"DummyClass"
end
end
end
context "instances" do
subject { dummy_class.new }
it { subject.should be_an_instance_of(dummy_class) }
it { should respond_to(:your_cool_module_method)}
it { should be_a(YourCoolModule) }
its (:to_s) { should eq("dummy") }
end
context "classes" do
subject { dummy_class }
it { should be_an_instance_of(Class) }
it { defined?(DummyClass).should be_nil }
its (:name) { should eq("DummyClass") }
end
end
context "cntxt2" do
it "should not be possible to access let methods from anohter context" do
defined?(dummy_class).should be_nil
end
end
it "should not be possible to access let methods from a child context" do
defined?(dummy_class).should be_nil
end
end
#You could also try to benefit from implicit subject using the descbie
#method in conjunction with local variables. You may want to scope your local
#variables. You can't use context here, because that can only be done inside
#a describe block, however you can use Porc.new and call it immediately or a
#describe blocks inside a describe block.
#Proc.new do
describe "YourCoolModule" do #But you mustn't refer to the module by the
#constant itself, because if you do, it seems you can't reset what your
#describing in inner scopes, so don't forget the quotes.
dummy_class = Class.new { include YourCoolModule }
#Now we can benefit from the implicit subject (being an instance of the
#class whenever we are describing a class) and just..
describe dummy_class do
it { should respond_to(:your_cool_module_method) }
it { should_not be_an_instance_of(Class) }
it { should be_an_instance_of(dummy_class) }
it { should be_a(YourCoolModule) }
end
describe Object do
it { should_not respond_to(:your_cool_module_method) }
it { should_not be_an_instance_of(Class) }
it { should_not be_an_instance_of(dummy_class) }
it { should be_an_instance_of(Object) }
it { should_not be_a(YourCoolModule) }
end
#end.call
end
#In this simple case there's necessarily no need for a variable at all..
describe Class.new { include YourCoolModule } do
it { should respond_to(:your_cool_module_method) }
it { should_not be_a(Class) }
it { should be_a(YourCoolModule) }
end
describe "dummy_class not defined" do
it { defined?(dummy_class).should be_nil }
end
도우미 유형을 사용할 수도 있습니다.
# api_helper.rb
module Api
def my_meth
10
end
end
# spec/api_spec.rb
require "api_helper"
RSpec.describe Api, :type => :helper do
describe "#my_meth" do
it { expect( helper.my_meth ).to eq 10 }
end
end
설명서는 다음과 같습니다. https://www.relishapp.com/rspec/rspec-rails/v/3-3/docs/helper-specs/helper-spec
당신은 당신의 스펙 파일에 당신의 모듈을 간단히 포함시킬 필요가 있습니다. mudule Test module MyModule def test 'test' end end end 파일에 . RSpec.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
모듈 방법을 테스트하기 위한 하나의 가능한 솔루션으로, 모듈 방법을 포함하는 클래스에 독립적입니다.
module moduleToTest
def method_to_test
'value'
end
end
그리고 그것에 대한 사양.
describe moduleToTest do
let(:dummy_class) { Class.new { include moduleToTest } }
let(:subject) { dummy_class.new }
describe '#method_to_test' do
it 'returns value' do
expect(subject.method_to_test).to eq('value')
end
end
end
또한 DRY 테스트를 수행하려면 shared_examples를 사용하는 것이 좋습니다.
두 개 이상의 모듈을 테스트해야 하기 때문에 반복되는 패턴입니다.따라서 이를 위한 도우미를 만드는 것이 더 바람직합니다.
방법을 설명하는 이 게시물을 찾았지만 사이트가 언제 다운될지 몰라 대처하고 있습니다.
이는 객체 인스턴스가 인스턴스 메서드를 구현하지 않도록 하기 위한 것입니다. : 시도할 때 발생하는 오류는 무엇이든 상관없습니다.allow에 있는 방법.dummy학생들
코드:
spec/support/helpers/dummy_class_helpers.rb
module DummyClassHelpers
def dummy_class(name, &block)
let(name.to_s.underscore) do
klass = Class.new(&block)
self.class.const_set name.to_s.classify, klass
end
end
end
spec/spec_helper.rb
# skip this if you want to manually require
Dir[File.expand_path("../support/**/*.rb", __FILE__)].each {|f| require f}
RSpec.configure do |config|
config.extend DummyClassHelpers
end
사양:
require 'spec_helper'
RSpec.shared_examples "JsonSerializerConcern" do
dummy_class(:dummy)
dummy_class(:dummy_serializer) do
def self.represent(object)
end
end
describe "#serialize_collection" do
it "wraps a record in a serializer" do
expect(dummy_serializer).to receive(:represent).with(an_instance_of(dummy)).exactly(3).times
subject.serialize_collection [dummy.new, dummy.new, dummy.new]
end
end
end
언급URL : https://stackoverflow.com/questions/1542945/testing-modules-in-rspec
'programing' 카테고리의 다른 글
| Postgres ENUM 데이터 유형 또는 CHECK CONSTARINT? (0) | 2023.06.02 |
|---|---|
| Android에서 '컨텍스트'란 무엇입니까? (0) | 2023.06.02 |
| PostgreSQL: psql이 서버에 연결할 수 없는 이유는 무엇입니까? (0) | 2023.06.02 |
| Excel에서 현재 행을 참조하고 특정 열을 참조하려면 어떻게 해야 합니까? (0) | 2023.06.02 |
| 중첩 배열에서 Mongodb $push (0) | 2023.06.02 |