避免使用subject,let和alternative参数进行过多的rspec嵌套

时间:2015-05-25 10:07:16

标签: ruby-on-rails ruby rspec

我正在尝试进行一些model_spec测试,但是无需进一步嵌套我的rspec代码就遇到了麻烦。如果在这种情况下,我可以只有一组“它”,而不是每次我想要切换变量 var 时都要添加上下文。这是以下代码:

describe "#some_method" do

subject { course.some_method(var) }

context 'given a project' do

  let(:var) {random[1]}
  it 'returns the one after' do
    is_expected.to eq(random[2])
  end

  context 'being the last' do
    let(:vars) {random.last}
    it 'returns nil' do
      is_expected.to be_nil
    end
  end

  context '...you get the point, being something else' do
    let(:vars) { something.else }
    it 'returns nil' do
      is_expected.to.to be_nil
    end
  end

end
end

也许我只是陷入了错误的思维模式,有人可能会想到一个更好的方法让我这样做?我被建议我绝对必须使用我工作的人的主题。

起初,我不同意并认为这有点麻烦,但后来我想保留主题并让(:var)适用于它非常有用......

2 个答案:

答案 0 :(得分:1)

RSpecs主题是一种可用于使测试更简洁的工具。在许多情况下,使用主题是有意义的:

RSpec.describe User do
  # with the help of shoulda-matchers
  it { should validate_uniqueness_of :username } # implicit subject
end

RSpec.describe UsersController do

  describe '#show' do
    it 'is successful' do
       get :show
       expect(response).to have_http_status :success
    end
    it 'renders template show' do
       get :show
       expect(response).to render_template :show
    end
  end

  #vs 
  describe '#show' do
    subject { response }
    before { get :show }
    it { should have_http_status :success }
    it { should render_template :success }
  end      
end

有些情况下使用主题会损害您的测试的可读性和敏锐度。

你的大学坚持认为你总是使用科目是完全错误的。

一个好的规则是,如果你需要it块,那么你就不应该使用主题或is_expected

如果您正在描述方法的呼叫签名,您应该按照与现实生活相同的方式在您的规范中调用它。

let(:decorator){ described_class.new(user) }

describe "#link" do
  it 'takes a class option' do
    expect(decorator.link(class: 'button')).to match /class=\"button/
  end
end

我建议使用--format documentation选项运行rspec并检查输出是否真的有意义。一旦获得100个规格,这一点非常重要,因为它越来越难以记住规范实际涵盖的行为。

答案 1 :(得分:0)

你这样写的怎么样? expect(subject.call(foo))不是很漂亮,但它摆脱了嵌套。

describe "#some_method" do
  subject { course.method(:some_method) }

  it 'returns the one after if given a project' do
    expect(subject.call(random[1])).to eq(random[2])
  end

  it 'returns nil when it is the last' do
    expect(subject.call(random.last)).to be_nil
  end

  it 'returns nil...' do
    expect(subject.call(something.else)).to be_nil
  end
end