2011-09-19 1 views
1
내가 루비를 사용하고

(적은 코드와 유사한 User 클래스 개체를 테스트하기 위해 속성 값) :명백한 'subject 's를 지정하는데 문제가 있습니까? 레일 3.0.9과 RSpect 나는 다음과 같은 방법으로 일부 사양 파일을 리팩토링에 노력하고 2.

describe User do 
    let(:user1) { Factory(:user, :users_attribute_a => 'invalid_value') } 
    let(:user2) { Factory(:user, :users_attribute_b => 'invalid_value') } 
    let(:user3) { Factory(:user, :users_attribute_c => 'invalid_value') } 

    it "foreach user" do 
    [ user1, user2, user3 ].each do |user| 
     subject { user } 

     it "should be whatever" 
     user.should_not be_valid 
     ... 
     end 
    end 
    end 
end 

Failure/Error: it "should be whatever" do 
    NoMethodError: 
    undefined method `it' for #<RSpec::Core::ExampleGroup::Nested_1::Nested_2::Nested_2:0x00000106ccee60> 

문제가 무엇입니까 : 나는 위의 테스트를 실행한다면, 나는 다음과 같은 오류가 발생합니다? 어떻게 해결할 수 있습니까?


@Emily 대답 한 후 UPDATE.

내가 context "foreach user" do ... 대신 it "foreach user" do ...의를 사용하여 위의 코드의 경우, 나는 다음과 같은 오류 얻을 :

undefined local variable or method `user1' for #<Class:0x00000105310758> (NameError) 
+0

참고로, 'subject'는 빨간 ​​청어입니다. 자신의 예에서 설정 한 주제를 실제로 사용하지 않습니다. – Emily

답변

1

당신은 모든 종류의 rspec 물건을 혼합하고 일치시킵니다.

describe User do 
    let(:user1) { Factory(:user, :users_attribute_a => 'invalid_value') } 
    let(:user2) { Factory(:user, :users_attribute_b => 'invalid_value') } 
    let(:user3) { Factory(:user, :users_attribute_c => 'invalid_value') } 

    it "should not be valid" do 
    [ user1, user2, user3 ].each do |user| 
     user.should_not be_valid 
    end 
    end 
end 

내가 그것을 이런 식으로 할 것이다 : 여기에 귀하의 물건, 고정의 당시 멋진, 당신은 "상황"을 갖고 싶어

describe User do 
    subject{Factory.build(:user)} 
    it "should not be valid with invalid users_attribute_a" do 
    subject.users_attribute_a = "invalid_value" 
    subject.should_not be_valid 
    end 
    it "should not be valid with invalid users_attribute_b" do 
    subject.users_attribute_b = "invalid_value" 
    subject.should_not be_valid 
    end 
end 
  • 을,하지만 당신은 전에 변수를 가질 수 없습니다 당신의 컨텍스트 내부의 컨텍스트 당신이 사양을 가지고 싶다면
  • , 다음 하나를 가지고 있지만, 수 순 없습니다 "을"문

UPDATE는 최소한의 코드로

describe User do 

    it "should not be valid with other attributes" do 
    {:users_attribute_a => 'invalid_value', :users_attribute_b => 'invalid_value', :users_attribute_c => 'invalid_value'}.each do |key, value| 
     Factory.build(:user, key => value).should_not be_valid 
    end 
    end 

end 
+0

코드를 적게 쓰려면 두 번째 블록에서 코드를 리팩터링하는 방법은 무엇입니까? – Backo

+0

내가 생각할 수있는 최소한의 코드로 업데이트했습니다. –

+1

당신은'let'을 사용하여 컨텍스트로 변수 필터를 다운시킬 수 있습니다 – iain

2

문제는 또 다른 중첩 한 사양을 가진됩니다. it "foreach user"context "foreach user"으로 대체해야합니다. 추가 편집

: 일부 조사 후, 주변 맥락에서 let 설정 도우미가 it "should ..." 블록 내부에서만 사용할 수 있습니다처럼 보이는, 그리고. 다른 구조적 솔루션을 찾으려고하는 것이 좋습니다. 최선의 해결책은 실제로 테스트하려는 것에 달려 있습니다. 난 당신이 뭘 하려는지 추측하고있어 필요한 속성을 제거 할 때 사용자가 유효하지 않은지 확인해야합니다.

당신이 만드는 인스턴스의 더 복잡한 차이를 필요로 일을하는 경우
describe User do 
    let(:user_attributes){ Factory.attributes_for(:user) } 

    # Testing missing values aren't valid 
    [:name, :email, :phone].each do |required_attribute| 
    it "should not be valid without #{required_attribute}" do 
     User.new(user_attributes.except(required_attribute)).should_not be_valid 
    end 
    end 

    # Testing invalid values aren't valid 
    [[:email, 'not_an_email'], [:phone, 'not a phone']].each do |(attribute, value)| 
    it "should not be valid with bad value for #{attribute}" do 
     User.new(user_attributes.update(attribute => value)).should_not be_valid 
    end 
    end 
end 

, 없을 수도 있습니다 그것을 할 수있는 깨끗한 방법 :이 경우, 내가 무슨 짓을했는지는이 같은 것입니다 반복과 함께. 나는 DRY가 테스트에서 코드의 다른 부분과 마찬가지로 필수적이라고 생각하지 않습니다. 세 가지 사용자 유형에 대해 서로 다른 세 가지 컨텍스트와 각 컨텍스트에서의 유효성 테스트가있는 것은 아무 문제가 없습니다.

describe User do 
    context "with user1" do 
    subject{ Factory(:user, :users_attribute_a => 'invalid_value') } 
    it{ should_not be_valid } 
    end 

    context "with user2" do 
    subject{ Factory(:user, :users_attribute_b => 'invalid_value') } 
    it{ should_not be_valid } 
    end 

    context "with user3" do 
    subject{ Factory(:user, :users_attribute_c => 'invalid_value') } 
    it{ should_not be_valid } 
    end 
end 
+0

질문이 업데이트되었습니다. – Backo

0

문제는 "let"으로 설정된 도우미가 예제 컨텍스트 외부에 존재하지 않는다는 것입니다.

:

it "does something with all users" do 
    [user1, user2, user3] do |user| 
    user.valid?.should be_true 
    end 
end 

두 컨텍스트

가 작동 할 수있는 또 다른 방법 다른가이처럼 (그것을 시도하지 않은)입니다

당신이 할하려는 것은으로 얻을 수있는

context "for all users" do 
    [:user1, :user2, :user3].each do |user| 
    it "does something" do 
     send(user).valid?.should be_true 
    end 
    end 
end 
0

이 작동합니다. 문맥이 어떻게 쓰여지는지주의해라. 그러면 테스트 결과가 더 분명해질 것이다. 이 방법을 쓰는 것에서 이것은 각 속성에 대한 테스트를 별도로해야한다는 것을 의미합니다. 그러나 당신의 선택입니다 :

describe User do 
    let!(:users) { 
    [:users_attribute_a, :users_attribute_b, :users_attribute_c].map do |a| 
     Factory(:user, => 'invalid_value') 
    end 
    } 

    context "Given a user" do 
    context "With an invalid value" do 
     subject { users } 
     it { subject.all?{|user| should_not be_valid } 
    end 
    end 
end