Search code examples
rubyshoulda

How to override setup values, like RSpec `let`, in shoulda contexts?


Here's a nice technique I use with RSpec that I would also like to use in projects that use Shoulda and Shoulda-context. But I don't know if it's possible. Is there a way to do this?

What I want: define a setup (before) block in an outer context that references a let clause in a nested context. That way, inner contexts can configure values that are referenced in the outer setup And the setup can still be DRY across inner contexts.

RSpec example (this example is simple--please assume my real-life examples have a lot more code in the before block that I don't want to duplicate):

describe Thing do
  before do
    # Notice that `user` isn't defined here--it's defined in `let` blocks
    # in nested contexts below.
    login_as user

    # Assume there's lots more code here that I would like to keep
    # DRY across contexts.
  end

  context "when logged in as an admin" do
    # THIS IS THE MAGIC RIGHT HERE:
    let(:user) { Factory(:user, role: "admin") }

    it "should ..." ...
  end

  context "when logged in as a normal user" do
    # THIS IS THE MAGIC RIGHT HERE:
    let(:user) { Factory(:user) }

    it "should ..." ...
  end
end

To summarize: how can I do this with shoulda-context and Test::Unit?

Some things I have already tried that didn't work:

  • def to redefine a method in each subcontext.
  • before_should in each subcontext.

Solution

  • I've found helper methods inside the test class useful for pulling out code repeated between tests. Like this:

    class MyTest < TestCase
      context "when logged in as an admin" do
        setup do
          do_login Factory(:user, role: "admin")
        end
    
        should "..." do
          ...@user...
        end
      end
    
      context "when logged in as an admin" do
        setup do
          do_login Factory(:user)
        end
    
        should "..." do
          ...@user...
        end
      end
    
      def do_login(user)
        login_as user
        @user = user
    
        # lots more setup code here...
      end
    end