3

私は次のビュースペックを持っています:

describe "carts/show" do
  before(:each) do
    book = build_stubbed(:product, title: "book")
    car = build_stubbed(:product, title: "car")
    line_item1 = build_stubbed(:line_item, product: book, quantity: 3)
    line_item2 = build_stubbed(:line_item, product: car, quantity: 1)
    @cart = assign(:cart, build_stubbed(:cart, line_items: [line_item1, line_item2]))
    render
  end

  it "displays a single car" do
    assert_select "li", text: "1 time: car"
  end
  it "displays 3 books" do
    assert_select "li", text: "3 times: book"
  end
  it "has exactly 2 items" do
    assert_select "li", 2
  end

end

この仕様は期待どおりに機能します。ただし、セットアップはbefore(:each)ブロック内にあるため、セットアップとrenderメソッドはブロックごとに1回呼び出されます。これはかなり遅いです。理想的には、describeブロック全体で1回だけ呼び出す必要があります。

に変更before(:each)するbefore(:all)とこれが修正されると思いましたが、エラーが発生しました(show.html.erb_spec.rbの16行目がrender呼び出しです)。

NoMethodError: undefined method `example_group' for nil:NilClass
~/.rvm/gems/ruby-1.9.3-p125/gems/rspec-rails-2.12.0/lib/rspec/rails/example/view_example_group.rb:106:in `_default_file_to_render'
~/.rvm/gems/ruby-1.9.3-p125/gems/rspec-rails-2.12.0/lib/rspec/rails/example/view_example_group.rb:112:in `_default_render_options'
~/.rvm/gems/ruby-1.9.3-p125/gems/rspec-rails-2.12.0/lib/rspec/rails/example/view_example_group.rb:45:in `render'
show.html.erb_spec.rb:16:in `block (2 levels) in <top (required)>'
~/.rvm/gems/ruby-1.9.3-p125/gems/rspec-core-2.12.1/lib/rspec/core/hooks.rb:23:in `instance_eval'
~/.rvm/gems/ruby-1.9.3-p125/gems/rspec-core-2.12.1/lib/rspec/core/hooks.rb:23:in `run'
~/.rvm/gems/ruby-1.9.3-p125/gems/rspec-core-2.12.1/lib/rspec/core/hooks.rb:106:in `run'
~/.rvm/gems/ruby-1.9.3-p125/gems/rspec-core-2.12.1/lib/rspec/core/hooks.rb:424:in `run_hook'
~/.rvm/gems/ruby-1.9.3-p125/gems/rspec-core-2.12.1/lib/rspec/core/example_group.rb:319:in `run_before_all_hooks'
~/.rvm/gems/ruby-1.9.3-p125/gems/rspec-core-2.12.1/lib/rspec/core/example_group.rb:368:in `run'
~/.rvm/gems/ruby-1.9.3-p125/gems/rspec-core-2.12.1/lib/rspec/core/command_line.rb:28:in `block (2 levels) in run'
~/.rvm/gems/ruby-1.9.3-p125/gems/rspec-core-2.12.1/lib/rspec/core/command_line.rb:28:in `map'
~/.rvm/gems/ruby-1.9.3-p125/gems/rspec-core-2.12.1/lib/rspec/core/command_line.rb:28:in `block in run'
~/.rvm/gems/ruby-1.9.3-p125/gems/rspec-core-2.12.1/lib/rspec/core/reporter.rb:34:in `report'
~/.rvm/gems/ruby-1.9.3-p125/gems/rspec-core-2.12.1/lib/rspec/core/command_line.rb:25:in `run'
~/.rvm/gems/ruby-1.9.3-p125/gems/rspec-core-2.12.1/lib/rspec/core/runner.rb:80:in `run'
~/.rvm/gems/ruby-1.9.3-p125/gems/rspec-core-2.12.1/lib/rspec/core/runner.rb:17:in `block in autorun'

ここで他に何ができるかわかりません。この問題を解決する正しい方法は何ですか?

4

2 に答える 2

2

RSpec-Rails のレンダリングは、それが各テスト内で発生することを確実に想定しているため、これは少し扱いに​​くいものになり、見た目から内部状態をいじる必要があります。

rspec-rails を調べてみると、そのrender呼び出しをに委譲しているように見えActionView::TestCase::Behavior#renderます。 @rendered重要な状態 (そしておそらく@view) のようですが、これがさらに問題を引き起こすかどうかはわかりません。

これが私の完全にテストされていないアプローチです:

describe "carts/show" do

  # Memoize the view across test runs for speed; this is some dangerous
  # spelunking in internal state, though!
  rendered_view    = nil
  rendered_content = nil

  before(:each) do
    if rendered_view && rendered_content
      @view     = rendered_view
      @rendered = rendered_content
    else
      book = build_stubbed(:product, title: "book")
      car = build_stubbed(:product, title: "car")
      line_item1 = build_stubbed(:line_item, product: book, quantity: 3)
      line_item2 = build_stubbed(:line_item, product: car, quantity: 1)
      @cart = assign(:cart, build_stubbed(:cart, line_items: [line_item1, line_item2]))

      render

      rendered_view    = @view
      rendered_content = @rendered
    end
  end

  it "displays a single car" do
    assert_select "li", text: "1 time: car"
  end
  it "displays 3 books" do
    assert_select "li", text: "3 times: book"
  end
  it "has exactly 2 items" do
    assert_select "li", 2
  end

end
于 2013-01-28T07:39:03.470 に答える
0

理想的ではありませんが、shared_subject

それを使用するには、基本的に:

  1. 「subject」を「shared_subject」に置き換えて、コンテキスト全体で最初の結果を共有します。
  2. (オプション) 「before(:each)」ブロックを「shared_setup」に置き換えます
  3. 終わり。サブジェクトは 1 つの単一のコンテキスト内で共有されます (ネストされたものは再び再設定されます)。

したがって、例は次のようになります。

describe "carts/show" do
  shared_subject do
    book = build_stubbed(:product, title: "book")
    car = build_stubbed(:product, title: "car")
    line_item1 = build_stubbed(:line_item, product: book, quantity: 3)
    line_item2 = build_stubbed(:line_item, product: car, quantity: 1)
    @cart = assign(:cart, build_stubbed(:cart, line_items: [line_item1, line_item2]))
    render
  end

  it "displays a single car" do
    assert_select "li", text: "1 time: car"
  end
  it "displays 3 books" do
    assert_select "li", text: "3 times: book"
  end
  it "has exactly 2 items" do
    assert_select "li", 2
  end

end
于 2015-11-23T23:41:37.833 に答える