That's a few questions. Let me see if I can provide a little perspective on
them. *Note these are just my opinions and do not reflect any RSpec
standard / best practice / recommendation / etc.*

...is not wise to use before

This is largely a matter of opinion. Now, you may have come across
something stating that before(:all) or it's new more intent revealing alias
before(:context) is not wise to use. In general, I agree with this view.
This is only run once before the entire example group (context) it is
defined in. There are rare cases where this is what you need, but
generally, it's not what you need. It usually leaks mutable state across
specs, which can have very surprising and difficult to debug consequences.
It also has many caveats regarding DB state, transactions, and other system
level dependencies.

On the other hand, before(:each) or the new before(:example), which is the
default if you just write before, it more acceptable to use. It is also
normally what you want. It keeps state clean across specs, it hooks into
transactions, rspec-mocks, etc. Unless you have a provable, with valid data
showing it, case where this is detrimental to performance, it's the proper
choice.

Personally, I feel before and let should be used sparingly. They should be
reserved for cases when you mean to state: *"All of the following specs in
this group really must have this setup action done before each of them."*

Note I wrote "setup action". This does not apply to any action regarding
the object under test. I personally believe those should not be put in any
before block, but explicitly listed in the spec so that it is clear what
you are testing, versus what is setting up the testing environment. Let me
share a code sample explaining this view:

RSpec.describe Array, "list of elements" do
  describe "popping the array" do
    let(:element_list) do
      [:first, :second, :last]
    end

    # This is the same as before(:each) or before(:example)
    before do
      element_list.pop
    end

    # Note we are **cannot** use the same setup state since we need to capture
    # the value
    it "returns the last value of the array" do
      expect([:first, :second, :last].pop).to eq(:last)
    end

    # Note it's very unclear what the test is doing just by looking at it.  We
    # are describing an action on an Array instance. Yet, that isn't clear from
    # this spec at all, since all we see is that we check the array elements
    it "mutates the array removing the last element" do
      expect(element_list).to eq([:first, :second])
    end
  endend

I've seen the above code "cleaned up" to be more expressive by converting
it into something like:

RSpec.describe Array, "list of elements" do
  describe "popping the array" do
    let(:array_with_elements) do
      [:first, :second, :last]
    end

    # This is idiom is often viewed as an implicit `before`.
    #
    # Except, it's not. It's only run once you send the `element_list` message.
    # If you do this in the wrong spot then it may lead to surprising tests.
    #
    # This often leads people to use bang form `subject!`, which is
    # functionally the same as:
    #
    #   subject(:element_list) { ... }
    #   before { element_list }
    #
    # But this is often not the right tool and can have some surprising issues:
    # http://aaronkromer.com/blog/2013-05-19-the-bang-is-for-surprise.html
    #
    # Additionally, using `subject` here, IMO, is just wrong. The subject is
    # not the element returned from `#pop`. It's a specific instance of
    # `Array`. We are testing the behavior of `#pop`.
    subject(:popped_element) do
      array_with_elements.pop
    end

    # Looks clean, but is misleading as to what is actually the subject of the
    # spec. Here it's the popped element, but in reality, it's the return value
    # of calling the action `pop`.
    it "returns the last value of the array" do
      expect(popped_element).to eq(:last)
    end

    # This turns out to appear trickier to test. Often the initial pass looks
    # something like this:
    #
    #   expect(array_with_elements).to eq([:first, :second])
    #
    # That will fail though. Why? Because if we are not using the bang form of
    # `subject!`, a `before`, or something like `preload` (see blog link
    # above) then nothing is actually popped before this spec is run. Thus the
    # array is never mutated. Leaving `array_with_elements` unmodified.
    it "mutates the array removing the last element" do
      popped_element
      expect(array_with_elements).to eq([:first, :second])
    end
  endend

I've also seen people go the following route, as well, it looks a bit
cleaner:

# Looks cleaner using ivars. In general, I am not a fan of ivars and
instead# prefer to use local variables and message passing. This
allows for clean# extractions of ideas / concepts without modifying
lots of code.## For more details see this SO answer:
http://stackoverflow.com/a/5359979/47438RSpec.describe Array, "list of
elements" do
  describe "popping the array" do
    before do
      @element_list = [:first, :second, :last]
      @popped_element = @element_list.pop
    end

    # Looks clean, but is misleading as to what is actually the subject of the
    # spec. Here it's the popped element, but in reality, it's the return value
    # of calling the action `pop`.
    it "returns the last value of the array" do
      expect(@popped_element).to eq(:last)
    end

    # Again, looks clean, but is misleading. Here we are actually looking at
    # the real object under test (the proper subject). But, it's already
    # mutated. We still have to hunt down that mutation.
    it "mutates the array removing the last element" do
      expect(@element_list).to eq([:first, :second])
    end
  endend

Another large issue I have with the last form above is it completely hides
the mutation and behavior being tested in the before block. Just looking at
the before block, it's not obvious what is setup and what is being tested.
It isn't until I've read all of the specs, or a large number of them, that
things become clear to me.

This is why, I prefer a form more along the lines of:

RSpec.describe Array, "list of elements" do
  describe "popping the array" do
    subject(:element_list) do
      [:first, :second, :last]
    end

    it "returns the last value of the array" do
      expect(element_list.pop).to eq(:last)
    end

    it "mutates the array removing the last element" do
      expect{ element_list.pop }.to change{ element_list }
        .from([:first, :second, :last])
        .to([:first, :second])
    end
  endend

To me this is cleaner, more explicit, and more obvious what is happening.
But I'm just one person.

way to test validations

I would test them just as I would any side-effect based protocol:

RSpec.describe Admin, type: :model do
  describe "requires a name" do
    subject(:nameless_admin) do
      Admin.new(name: nil)
    end

    it "is not valid" do
      expect(nameless_admin.valid?).to be false
    end

    it "sets an error on the name attribute" do
      expect{ nameless_admin.valid? }
        .to change{ nameless_admin.errors[:name] }
        .from([])
        .to(include "can't be blank")
    end
  endend

 inout of a form by using capybara

This is a bit broader. In general, I simply go to the web page, fill in the
form, then check the response. These are usually feature type acceptance
specs. When I write these, I sometimes don't adhere to the "one expectation
per spec" guideline. This is because I am often testing a workflow, and I
need to validate my expected assumptions along the path.

RSpec.describe "Signing up for the site", type: :feature do
  it "requires a name to be specified" do
    visit sign_up_url
    click_button "Sign Up"
    expect(current_url).to eq sign_up_url
    expect(page).to have_contenxt "Name can't be blank"
  endend

Checkout the capybara readme (https://github.com/jnicklas/capybara) for
more examples.


Happy testing!


Aaron



On Sun, Aug 10, 2014 at 1:09 PM, Roelof Wobben <[email protected]> wrote:

> Hello,
>
> I read everywhere that I is not wise to use before
>
> Now I wonder what is a good rspec3 way to test validations and later on
> test a inout of a form by using capybara/
>
> I did google a lot but I could not find a good example.
>
> Roelof
>
>  --
> You received this message because you are subscribed to the Google Groups
> "rspec" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> To post to this group, send email to [email protected].
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/rspec/5a32ddf8-f0fc-4bcd-80cd-555118b50ef1%40googlegroups.com
> <https://groups.google.com/d/msgid/rspec/5a32ddf8-f0fc-4bcd-80cd-555118b50ef1%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups 
"rspec" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/rspec/CAKCESdiebUNmf%2BFB3xmC4X-uH%3DaNJxZ59gqF647%2BDT0p5ZAWGA%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to