Rick DeNatale
2008-Mar-14 20:12 UTC
[rspec-users] Branching scenarios, GivenScenario and database
I''m trying to use stories to drive some high-level design. I''ve got some branching scenarios where I want to follow a scenario, to establish a base situation, and then have different scenarios which ''branch'' out from that state, possibly several levels deep. I asked a bit about this a few days ago, and David pointed out the rather undocumented GivenScenario which seems to give the basic ability to do what I''m after. So far it''s been working fairly well, but I''ve run into a few quirks. 1) I''ve been working through my scenarios, and I''d commented out the later ones to cut down on the ''pending'' output while I develop the steps. I''d get one scenario working and then go on to the next. So at one point my plain text story looked something like this: Scenario A Given ... When ... Then ... #Scenario B # GivenScenario A # Given ... # ... And I got Scenario A working and uncommented the next scenario, or so I thought: Scenario A Given ... When ... Then ... #Scenario B GivenScenario A Given ... It took me a while to debug the resulting infinite loop. Perhaps GivenScenario should check to see that it''s not asking for the CURRENT scenario. 2) Having figured that out and moving on, I now have another problem, which is what''s the best way to clean up the database so that Scenario A can run again if it assumes that the stuff it put in the DB isn''t there each time it runs. Cleaning the DB after running the scenario won''t work since it defeats the purpose of using the scenario as a pre-condition. Cleaning it before is more difficult, particularly if I''m using parameterized steps. It would be nice if I could somehow use database transactions, but I don''t see a nice way to do that either. Has anyone faced issues like these? Any ideas? -- Rick DeNatale My blog on Ruby http://talklikeaduck.denhaven2.com/
David Chelimsky
2008-Mar-16 09:43 UTC
[rspec-users] Branching scenarios, GivenScenario and database
On Fri, Mar 14, 2008 at 8:12 PM, Rick DeNatale <rick.denatale at gmail.com> wrote:> I''m trying to use stories to drive some high-level design. > > > I''ve got some branching scenarios where I want to follow a scenario, > to establish a base situation, and then have different scenarios which > ''branch'' out from that state, possibly several levels deep. > > I asked a bit about this a few days ago, and David pointed out the > rather undocumented GivenScenario which seems to give the basic > ability to do what I''m after. So far it''s been working fairly well, > but I''ve run into a few quirks. > > 1) I''ve been working through my scenarios, and I''d commented out the > later ones to cut down on the ''pending'' output while I develop the > steps. I''d get one scenario working and then go on to the next. So > at one point my plain text story looked something like this: > > Scenario A > Given ... > When ... > Then ... > > #Scenario B > # GivenScenario A > # Given ... > # ... > > And I got Scenario A working and uncommented the next scenario, or so I thought: > Scenario A > Given ... > When ... > Then ... > > #Scenario B > GivenScenario A > Given ... > > It took me a while to debug the resulting infinite loop. Perhaps > GivenScenario should check to see that it''s not asking for the CURRENT > scenario.Patches welcome :)> > 2) Having figured that out and moving on, I now have another > problem, which is what''s the best way to clean up the database so that > Scenario A can run again if it assumes that the stuff it put in the DB > isn''t there each time it runs. Cleaning the DB after running the > scenario won''t work since it defeats the purpose of using the scenario > as a pre-condition. Cleaning it before is more difficult, > particularly if I''m using parameterized steps. It would be nice if I > could somehow use database transactions, but I don''t see a nice way to > do that either.This should just work. If you look at story_adapter.rb, which defines the RailsStory class (maybe we should align :) ) you''ll see that the transaction is opened when the scenario starts and rolled back when it is finished. GivenScenario should not result in a call to any of the scenario finished methods (scenario_succeeded, _pending, _failed), so it should get rolled back. If that''s not happening, please do file a ticket. Cheers, David> > Has anyone faced issues like these? Any ideas? > > -- > Rick DeNatale > > My blog on Ruby > http://talklikeaduck.denhaven2.com/ > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
Rick DeNatale
2008-Mar-16 14:37 UTC
[rspec-users] Branching scenarios, GivenScenario and database
On 3/16/08, David Chelimsky <dchelimsky at gmail.com> wrote:> On Fri, Mar 14, 2008 at 8:12 PM, Rick DeNatale <rick.denatale at gmail.com> wrote: > > I''m trying to use stories to drive some high-level design.> > ... So far it''s been working fairly well, > > but I''ve run into a few quirks. > > > > 1) I''ve been working through my scenarios, and I''d commented out the > > later ones to cut down on the ''pending'' output while I develop the > > steps. I''d get one scenario working and then go on to the next. So > > at one point my plain text story looked something like this: > > > > Scenario A > > Given ... > > When ... > > Then ... > > > > #Scenario B > > # GivenScenario A > > # Given ... > > # ... > > > > And I got Scenario A working and uncommented the next scenario, or so I thought: > > Scenario A > > Given ... > > When ... > > Then ... > > > > #Scenario B > > GivenScenario A > > Given ... > > > > It took me a while to debug the resulting infinite loop. Perhaps > > GivenScenario should check to see that it''s not asking for the CURRENT > > scenario. > > > Patches welcome :)Fair enough, I''ll look at that when I find the time.> > 2) Having figured that out and moving on, I now have another > > problem, which is what''s the best way to clean up the database so that > > Scenario A can run again if it assumes that the stuff it put in the DB > > isn''t there each time it runs. Cleaning the DB after running the > > scenario won''t work since it defeats the purpose of using the scenario > > as a pre-condition. Cleaning it before is more difficult, > > particularly if I''m using parameterized steps. It would be nice if I > > could somehow use database transactions, but I don''t see a nice way to > > do that either. > > > This should just work. If you look at story_adapter.rb, which defines > the RailsStory class (maybe we should align :) ) you''ll see that the > transaction is opened when the scenario starts and rolled back when it > is finished. GivenScenario should not result in a call to any of the > scenario finished methods (scenario_succeeded, _pending, _failed), so > it should get rolled back. > > If that''s not happening, please do file a ticket.Okay, right now, I''m not actually using rails stories since I''m working through pure business logic sans a UI so there''s been no need for Rails "integration" testing. On the other hand I guess it wouldn''t hurt to "declare" them as rails stories. -- Rick DeNatale My blog on Ruby http://talklikeaduck.denhaven2.com/
Pat Maddox
2008-Mar-16 17:21 UTC
[rspec-users] Branching scenarios, GivenScenario and database
On Sun, Mar 16, 2008 at 7:37 AM, Rick DeNatale <rick.denatale at gmail.com> wrote:> Okay, right now, I''m not actually using rails stories since I''m > working through pure business logic sans a UI so there''s been no need > for Rails "integration" testing. > > On the other hand I guess it wouldn''t hurt to "declare" them as rails stories.I assume that stories don''t get transactional goodness unless they''re Rails stories. Pat
Rick DeNatale
2008-Mar-17 20:11 UTC
[rspec-users] Branching scenarios, GivenScenario and database
On 3/16/08, David Chelimsky <dchelimsky at gmail.com> wrote:> On Fri, Mar 14, 2008 at 8:12 PM, Rick DeNatale <rick.denatale at gmail.com> wrote:> > 2) Having figured that out and moving on, I now have another > > problem, which is what''s the best way to clean up the database so that > > Scenario A can run again if it assumes that the stuff it put in the DB > > isn''t there each time it runs. Cleaning the DB after running the > > scenario won''t work since it defeats the purpose of using the scenario > > as a pre-condition. Cleaning it before is more difficult, > > particularly if I''m using parameterized steps. It would be nice if I > > could somehow use database transactions, but I don''t see a nice way to > > do that either. > > > This should just work. If you look at story_adapter.rb, which defines > the RailsStory class (maybe we should align :) ) you''ll see that the > transaction is opened when the scenario starts and rolled back when it > is finished. GivenScenario should not result in a call to any of the > scenario finished methods (scenario_succeeded, _pending, _failed), so > it should get rolled back.I''ve gotten stuck here. To recap, when I don''t make the story a RailsStory, then the the first scenario (A) works but fails when invoked from B as a GivenScenario. One of the steps is failing because of a validates_uniqueness in on of the models which fails because of stuff left in the DB from the initial running. When I change it to a RailsStory then Scenario A fails in the same step the FIRST time. In this case it''s because records which it needs aren''t there. The records in question have been loaded by a helper which calls Fixtures.create_fixtures to load them. These particular tables are basically ''constants'' for the app. A few more tidbits. There''s are models called Role, Membership, and a join model MembershipRole Role has_many :membership_roles has_many :memberships :through => :membership_roles end Membership has_many :membership_roles has_many :membersships, :through => :membership_roles end MembershipRole belongs_to :membership belongs_to :role validates uniqueness_of :role_id, :scope => :membership_id end Role has a class method get which takes a string and effectivly does this: def self.get(name) @role_objects ||= {} @role_objects[name] ||= find_by_name(name) end And the method ultimately invoked by the failing step has a skeleton like this: class Membership < ActiveRecord::Base def add_role(name) if role = Role.get(name) ... else raise "Can''t find Role named #{name} end end If I change the Role.get method to bypass the cache then the exception gets raised the first time the step is executed for a RailsStory, and second time for a non-RailsStory. With that method left alone, the Role objects are found at some time previous to the step and cached, in which case the failure happens inside the if where a simplified version of that ... looks like this: unless self.roles(true).include(role) membership_role = MembershipRole.create(:membership => self, :role => role) end role.dependencies.each {|dependency| add_role(dependency) The problem is that the validates_uniqueness_of in MemberRole is failing, again the second time the step in question is called for a non-RailsStory, and the first time for a RailsStory. The reason is that the query generated by the roles association is doing a join on roles and membership roles and the roles aren''t in the DB, but then validates_uniqueness of just checks the membership_id and role_id fields. It looks to me as though running as a RailsStory is causing the roles records to be deleted before the scenario runs, but after the class cached them. s Any ideas? -- Rick DeNatale My blog on Ruby http://talklikeaduck.denhaven2.com/
Rick DeNatale
2008-Mar-18 14:11 UTC
[rspec-users] Branching scenarios, GivenScenario and database
On 3/17/08, Rick DeNatale <rick.denatale at gmail.com> wrote:> [quite a lot]Okay, I''ve got it working now. The problem seems to be wrapped up in the use of transactional fixtures to load the db, and the fact that fixture teardown actually happens in the SETUP phase, in other words when you declare a fixture in Rails, it first deletes all records from any tables with declared fixtures, and then loads the fixtures. -- Rick DeNatale My blog on Ruby http://talklikeaduck.denhaven2.com/