Step definitions generated by factories can create instance variables #366

Closed
wants to merge 7 commits into
from

Projects

None yet

3 participants

@chrisbloom7

Given the FactoryGirl::StepDefinitions.create_instance_variables setting is true
When factory girl step definitions are used
Then each step will instantiate an instance variable based on the name of the factory being created

FactoryGirl steps that accept a table or object count will instantiate their instance variables as an array of factoried objects, while the other steps will result in instance variables that contain only a single factoried object.

This is based off of some 2-year-old code that github user @blaix posted as a Gist. I updated it to work with the latest version of FG, added test coverage, added a config variable to toggle the behavior off, and made it more robust.

chrisbloom7 added some commits Apr 27, 2012
@chrisbloom7 chrisbloom7 Step definitions generated by factories can create instance variables.
Given the FactoryGirl::StepDefinitions.create_instance_variables setting is true
When factory girl step definitions are used
Then each step will instantiate an instance variable based on the name of the factory be

Steps that accept a table or object count will instantiate their instance
variables as an array of factoried objects, while the other steps will result
in instance variables that contain only a single factoried object.
fe019da
@chrisbloom7 chrisbloom7 Step definitions generated by factories can create instance variables.
Given the FactoryGirl::StepDefinitions.create_instance_variables setting is true
When factory girl step definitions are used
Then each step will instantiate an instance variable based on the name of the factory be

Steps that accept a table or object count will instantiate their instance
variables as an array of factoried objects, while the other steps will result
in instance variables that contain only a single factoried object.
c7cbe21
@chrisbloom7 chrisbloom7 Merge branch 'master' of github.com:chrisbloom7/factory_girl
Conflicts:
	features/step_definitions/factory_girl_steps_instance_variables_steps.rb
7d91ef9
@chrisbloom7 chrisbloom7 Adding some debugging info for testing 7f03b30
@chrisbloom7 chrisbloom7 Changing instance variable setter to use human names that are passed …
…in instead of factory names so we can use alias names too
f279dd2
@chrisbloom7 chrisbloom7 Updating instance variable setter to dehumanize the human names, so w…
…e can again generate instance variables from multi-word factories
b5209ca
@chrisbloom7 chrisbloom7 Removing debugging statements after testing 547a5b9
@joshuaclayton
Member

I've found time and time again that instance variables in Cucumber end up being an anti-pattern. Steps then become dependent on state (signified by the existence/state of one or many instance variables) of other steps, not state based on the current page. Sorry for your trouble, but this isn't something I can include in FactoryGirl. Thanks.

@chrisbloom7

FYI - For some reason I could not get the FactoryGirl::StepDefinitions.create_instance_variables flag to work from the included features/env.rb file. I think it has something to do with how you are requiring the factory_girl base there, but then only requiring factory_girl/step_definitions from inside the features/support/factories.rb file. I tried moving these lines around to be more like the setup you recommend in the GETTING_STARTED guide under "Cucumber Integration", but was getting some weird results with other step definitions suddenly going missing. However, I created a separate project and bundled this version of FG, and there I was able to set FactoryGirl::StepDefinitions.create_instance_variables to both true and false in the features/env.rb file and have it work as expected.

@billy-ran-away

So @joshuaclayton how would you implement the following scenario:

@javascript
Scenario: Edit an existing todo
  Given I am on the todos page
  And a todo exists with a name of "Clean Carpets"
  When I change its name to "Replace Carpets"
  Then I should see the site "Replace Carpets"

In my When step I obviously need to reference the original Todo. I'm really interested in not following an anti-pattern.

@joshuaclayton
Member

I'd do something like

@javascript
Scenario: Edit an existing todo
  Given a todo exists with a name of "Clean Carpets"
  When I rename the todo "Clean Carpets" to "Replace Carpets"
  Then "Replace Carpets" should be in my list of todos

There are a number of differences here. First, all concepts of specific page interaction (URL, actually 'seeing' something, etc.) has been removed. This abstracts the visual (which you're testing in the steps, but the steps themselves don't need to reveal that) and the URL hierarchy (usually, you don't care about explicit routes - and when you do, you'd test that separately from the core behavior of the application, usually through a request spec).

I think the steps themselves should be pretty straightforward as to their implementation, they're still just as easy to follow (if not a little more abstract, which is a good thing!), and you won't have to use any instance variables.

Please let me know if you have any more questions... or even better, head to my Intro to Test-Driven Rails workshop - I teach it every 6 - 8 weeks, it's two days, and I cover good testing practices like this, along with RSpec.

Good luck!

@billy-ran-away

Thanks! It seems so obvious now but I hadn't consider passing the identifier to the When step...

@chrisbloom7

I swear I had at least 50 good use-case scenarios for using instance variables in steps, but after reading @joshuaclayton's suggestions and then looking at my scenarios again I am hard pressed to find a reason why I couldn't avoid using them in the first place. I guess I was solving a tunnel-vision problem.

@chrisbloom7

@joshuaclayton - Do you offer an online version of that workshop? I used to live in Massachusetts and in fact attended a Rails workshop at the Thoughtbot offices, but I have since moved south to a warmer climate.

@joshuaclayton
Member

@chrisbloom7 when I started learning Cucumber, I was using instance variables; when I did, however, I found that a lot of my steps were coupled to ivars that may or may not exist, since certain ones were dependent on others to have run beforehand (and assign the ivars). I kicked myself over and over again because I kept on getting bit by steps that weren't able to be used independently; a lot of times, it's just trial and error before you really get it ingrained in your head as to why something won't work :-)

As for online versions of the workshop, sadly, I don't offer one. There are basically no slides - we build two Rails apps in two days and it's extremely interactive. I've found that this helps students learn more, but it's not a lecture format so it's not conducive to being recorded...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment