RSpec and DRY

39 views
Skip to first unread message

Sebastian Trueman

unread,
Jun 18, 2014, 10:24:35 AM6/18/14
to rs...@googlegroups.com
Hey,

I'm a ruby beginner and I have a problem to keep my tests clean.

My Code:

require 'spec_helper'

describe "Static pages" do

  def checkContentOfPage(content, page)
    it "should have the content '"+content+"'" do
      visit '/static_pages/'+page
      expect(page).to have_content(title)
    end
  end

  describe "Home page" do

    
   checkContentOfPage('Sample App', 'home')

    it "should have the title 'Home'" do
      visit '/static_pages/home'
      expect(page).to have_title("Ruby on Rails Tutorial Sample App | Home")
    end
  end

  describe "Help page" do

    it "should have the content 'Help'" do
      visit '/static_pages/help'
      expect(page).to have_content('Help')
    end

    it "should have the title 'Help'" do
      visit '/static_pages/help'
      expect(page).to have_title("Ruby on Rails Tutorial Sample App | Help")
    end
  end

  describe "About page" do

    it "should have the content 'About Us'" do
      visit '/static_pages/about'
      expect(page).to have_content('About Us')
    end

    it "should have the title 'About Us'" do
      visit '/static_pages/about'
      expect(page).to have_title("Ruby on Rails Tutorial Sample App | About Us")
    end
  end
end

I tried to create  a method checkContentOfPage to reduce the have_content and have_title redundancy. But it doesnt work...

Can you tell me how to keep my tests clean? It seems like java like refactoring is not possible.

regards

Myron Marston

unread,
Jun 18, 2014, 12:42:50 PM6/18/14
to rs...@googlegroups.com
Change `def checkContentOfPage` to `def self.checkContentOfPage` and it should work.  In a `describe` block, `self` is a class, and in an `it` block, `self` is an instance of that class.  When you define `def checkContentOfPage` in a `describe` block, you are defining an instance method that is available to be called from within an example (an `it` block) but not from within a `describe` block.  It needs to be a class method (defined using `def self.`) for that to work.

You may also be interested in RSpec's shared examples feature:


HTH,
Myron

Sebastian Trueman

unread,
Jun 19, 2014, 3:59:18 AM6/19/14
to rs...@googlegroups.com
alright I'll test it soon. But what's about coding standards and best practices? It seems that you solution is not the common way to stay clean.
whats about an iterative looping alternative or to create costum validations. Rapec a lot of functions...
regars

Sebastian Trueman

unread,
Jun 19, 2014, 10:24:56 AM6/19/14
to rs...@googlegroups.com
I tried your solution:

def self.checkContentOfPage(content, page)
    it "should have the content '"+content+"'" do
      visit '/static_pages/'+page
      expect(page).to have_content(title)
    end
  end

But I still get the error :

1) Static pages Home page should have the content 'Sample App'
     Failure/Error: expect(page).to have_content(title)
     NoMethodError:
       undefined method `has_content?' for "home":String
     # ./spec/requests/static_pages_spec.rb:10:in `block in checkContentOfPage'

Aaron Kromer

unread,
Jun 19, 2014, 11:12:20 AM6/19/14
to rs...@googlegroups.com

You’re overwriting the capybara page method with your custom method.

In your spec:

describe "Home page" do


  it "should have the title 'Home'" do
    visit '/static_pages/home'

    # The reference to `page` below is defined by capybara:
    # https://github.com/jnicklas/capybara/blob/f83edc2a/lib/capybara/dsl.rb#L45

    expect(page).to have_title("Ruby on Rails Tutorial Sample App | Home")
  end

end

Your custom method creates a parameter called page. Ruby scoping rules apply thus you overwrite the definition of what page refers to:

def self.checkContentOfPage(content, page)  # <--- you re-write `page` here
  it "should have the content '"+content+"'" do #    ^
    visit '/static_pages/'+page # <---------|        |
    expect(page).to have_content(title) # <-|        |
    # These are not the capybara `page`,    |        |
    # they are the parameter `page`         |--------|
  end
end

I would suggest renaming the parameter to something else. Also, as Myron pointed out, this looks like a shared_example, so you can use that feature as well if you want.

Myron and the rest of the team can correct me if I am wrong, but there is no official “coding standard” or “best practice” when it comes to RSpec. I know that’s not the answer you’re looking for, but RSpec is ever changing and evolving. Additionally, many of it’s users adjust their practices (I know I do) as we try new things out and decide if and when they work. At the end of the day the only things that should matter are those standards and practices that help you and your read consistently write readable / understandable specs.



--
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 rspec+un...@googlegroups.com.
To post to this group, send email to rs...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/rspec/8cfaa405-5ecc-4efb-8992-e73464bfb7a4%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Sebastian Trueman

unread,
Jun 20, 2014, 7:16:06 AM6/20/14
to rs...@googlegroups.com
Alright I got it! thanks for your help and your advices. I think shared_example are almost the same like regular methods. They just improve the readability by extending the syntax.

I'm sure as time went by I'll use your nice features more and more.
Reply all
Reply to author
Forward
0 new messages