8
\$\begingroup\$

I'm working on writing tests for a rails application using cucumber and capybara. I have a scenario for a user editing a post, and making it invalid.

The scenario looks like this:

Scenario: I edit a post and make the data invalid.
  Given I have 1 post
  And I view my 1st post
  Then I click "Edit"
  And I fill in the edit post form with bad data
  When I click the "Update post" button
  Then I should see "Title is too short (minimum is 3 characters)"
  And I should see "Body is too short (minimum is 30 characters)"

Should I leave the scenario as-is, or create a scenario for entering the title incorrectly, and another scenario for entering the body incorrectly, like this:

Scenario: I edit a post and make the title too short.
  Given I have 1 post
  And I view my 1st post
  Then I click "Edit"
  And I fill in the edit post form with a title that is too short
  When I click the "Update post" button
  Then I should see "Title is too short (minimum is 3 characters)"

Scenario: I edit a post and make the body too short.
  Given I have 1 post
  And I view my 1st post
  Then I click "Edit"
  And I fill in the edit post form with a body that is too short
  When I click the "Update post" button
  Then I should see "Body is too short (minimum is 30 characters)"

If the post has several more fields, should I still create a scenario for each one, or would it be more DRY to use one scenario?

\$\endgroup\$
3
  • 3
    \$\begingroup\$ I have retracted my vote to close after looking at Cucumber website, I did not realize at first that this was actual code. \$\endgroup\$
    – Phrancis
    Commented Apr 3, 2016 at 0:35
  • \$\begingroup\$ @Hosch250 This is actual code that tests a rails application. The given/when/then/and lines tell cucumber what to do (They correspond to ruby code in another file, but I was wondering what was the best way to write the cucumber steps and scenarios would be in the feature file.) The current way I have works (it is the second example in the question), but was wondering if it was implemented correctly (so I think it falls under "Best practices and design pattern usage"). \$\endgroup\$ Commented Apr 3, 2016 at 0:35
  • \$\begingroup\$ Cool. I thought it might not be pseudocode, but I don't know Cucumber, so I thought I'd better ask. Good question. \$\endgroup\$
    – user34073
    Commented Apr 3, 2016 at 1:11

2 Answers 2

7
\$\begingroup\$

Personally, I only write feature tests for critical and very common cases, and outsource more specific tests (i.e is a certain field on a model validated) to model specs.

I wouldn't consider it a feature that a certain validation error is shown to the user, but I consider it a feature that the user gets informed that something went wrong and his post couldn't be created.

TL;DR Test the user experience in a feature spec and data integrity in model / controller specs.

Use different thinking hats for different tests:

  • Feature tests: Think in the user's perspective, how does the user interact with your app? what is the user expecting from your app?
  • Model tests: Think compulsive orderliness, how can you ensure data integrity?
  • Controller tests: Think paranoid, who can access what? does your controller comply with your API specs?

I would test in a feature spec for a "post":

  • That the user is able to create a post with an expected set of information (i.e the minimum that is required to create a post) and is redirected to the new post which shows the entered information.

  • That the user is unable to create a post by just hitting the "Submit" button without filling anything in and is shown a validation error. After correcting the user's mistake he should be able to create the post and be redirecred to the new post which shows the entered information.

This ensures the following "features":

  • Posts can be created
  • The user is informed about mistakes
  • Mistakes can be fixed
  • The user is assured that his post has been created.

I would test in a model spec:

Spec.describe Post, type: :model do
  subject { create(:post) }

  context 'validations' do
    it { should validate_presence_of(:title) }
    # for my taste, it's good enough to test that we validate the length
    it { should validate_length_of(:title) }

    it { should validate_presence_of(:body) }
    # if you want to be super-strict, you can check the length
    it { should validate_length_of(:body).is_at_least(100) }
  end
end
\$\endgroup\$
3
  • 1
    \$\begingroup\$ Could you perhaps in your answer expand on why you prefer to do this in model specs? \$\endgroup\$
    – jacwah
    Commented Apr 3, 2016 at 1:30
  • \$\begingroup\$ I added some lines about it, I don't consider it a feature that a very specific validation error is shown. But let's say you provide a set of choices if the user doesn't enter something - then it's a feature to test that these choices appear if the user didn't fill in that field. \$\endgroup\$
    – sled
    Commented Apr 3, 2016 at 1:35
  • \$\begingroup\$ @jacwah also note that my answer is just my opinion from experience - unfortunately there's no scientifically correct answer :/ \$\endgroup\$
    – sled
    Commented Apr 3, 2016 at 1:59
2
\$\begingroup\$

I personally would use a Scenario Outline in this situation.

Feature: Shortest Length Validation

Rules
 - Title must be more than 3 characters long
 - Body must be more than 30 characters long

Scenario Outline: I edit posts making various lengths too short.
  Given I have 1 post
  And I view my 1st post
  Then I click "Edit"
  And I fill in the edit post form with a <type> that is too short
  When I click the "Update post" button
  Then I should see "<capType> is too short (minimum is <minLength> characters)"

Examples:
| type  | minLength | capType | 
| title | 3         | Title   |
| body  | 30        | Body    |

If you want to add more to it, you can add more to the table, and replace the values to change with the heading of the column that you would like to replace it with, in between these brackets: <>.

If you wish to make lots of Scenarios that fundamentally do the same thing but in different ways, this is almost definitely the best way of doing it.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.