如何在测试中使用上下文?

how to use the context in the tests?

请帮助编写带有上下文的测试。

模特相册:

class Album < ActiveRecord::Base
  validates :title, presence: true, length: { maximum:  50, minimum: 3 }, uniqueness: { case_sensitive: false }
  validates :description, presence: true, length: { maximum:  600, minimum: 10 }
end

我为模型专辑编写了测试:

describe Album do
  it "has a valid factory" do
    expect(FactoryGirl.create(:album)).to be_valid
  end

  it "is invalid without title" do
    expect(FactoryGirl.build(:album, title: nil)).not_to be_valid
  end  

  it "is invalid with duplicate title" do
    FactoryGirl.create(:album, title: 'qwerty')
    expect(FactoryGirl.build(:album, title: 'qwerty')).not_to be_valid
  end 

  it "is valid with different title" do
    FactoryGirl.create(:album, title: 'zxcvbn')
    expect(FactoryGirl.build(:album, title: 'asdfgh')).to be_valid
  end        
end

这些测试工作正常。但我需要使用上下文:

describe Album do
  it "has a valid factory" do
    expect(FactoryGirl.create(:album)).to be_valid
  end

  describe '#title' do
    context "invalid" do
      it "is invalid without title" do
        expect(FactoryGirl.build(:album, title: nil)).not_to be_valid
      end  

      it "is invalid with long title" do
        expect(FactoryGirl.build(:album, title: 'If you liked my series on practical advice for adding reliable tests to your Rails apps, check out the expanded ebook version. Lots of additional, exclusive content and a complete sample Rails application.')).not_to be_valid
      end        

      it "is invalid with duplicate title" do
        FactoryGirl.create(:album, title: 'qwerty')
        expect(FactoryGirl.build(:album, title: 'qwerty')).not_to be_valid
      end       
    end

    context "valid" do
      it "is valid with title" do
        expect(FactoryGirl.build(:album, title: 'good title')).not_to be_valid
      end  

      it "is valid with different title" do
        FactoryGirl.create(:album, title: 'zxcvbn')
        expect(FactoryGirl.build(:album, title: 'asdfgh')).to be_valid
      end  
    end
  end      
end

但这些测试不是 DRY。请再次帮助编写带有上下文的测试。

ps: 我尝试使用的良好做法:

  1. 检查极限情况(非常小的值,非常大的值, 平均值)
  2. 为组织代码使用上下文
  3. 每个测试都应该在一个单独的方法中

您使用 context 进行的测试看起来没问题。但是,您可以按照最佳实践使用 context 编写更好的测试。请参阅 better specs 指南以了解如何编写更好的 RSpec 测试。

此外,请参阅以下使用 context 来自 The RSpec Style Guide

的经典示例
# A classic example for use of contexts in a controller spec is creation or update when the object saves successfully or not.

describe ArticlesController do
  let(:article) { mock_model(Article) }

  describe 'POST create' do
    before { Article.stub(:new).and_return(article) }

    it 'creates a new article with the given attributes' do
      Article.should_receive(:new).with(title: 'The New Article Title').and_return(article)
      post :create, article: { title: 'The New Article Title' }
    end

    it 'saves the article' do
      article.should_receive(:save)
      post :create
    end

    context 'when the article saves successfully' do
      before { article.stub(:save).and_return(true) }

      it 'sets a flash[:notice] message' do
        post :create
        flash[:notice].should eq('The article was saved successfully.')
      end

      it 'redirects to the Articles index' do
        post :create
        response.should redirect_to(action: 'index')
      end
    end

    context 'when the article fails to save' do
      before { article.stub(:save).and_return(false) }

      it 'assigns @article' do
        post :create
        assigns[:article].should be_eql(article)
      end

      it 're-renders the "new" template' do
        post :create
        response.should render_template('new')
      end
    end
  end
end