If there''s already been a thread on this, let me know (and if you can, point me to it)... In building my stories, I often need to setup a bunch of data where you have multiple levels of models that depend on each other. For example, I''d have models like Doctor, Organization, and Location. To run various scenarios that view doctors, say by organization, or by tags, or whatever, I need to setup fixture-like data for locations, then organizations (which belong to a location), then docs which belong to an organization. I am sure others have this in their apps, and I''m wondering how you organize you Given''s/steps across these things. Right now, for example, I have doctor_steps, organization_steps, and location_steps, which have their respective Givens in them. But, what''s been bugging me is that when one Given depends on another, the only place this is really hinted at is in the plain text story file, where I might have: Scenario: view doctors Given: existing locations And: existing organizations And: existing doctors My steps that depend on other data always check for that existance. e.g. in Organizations given, I''d do a "Location.count.should > 1" or more specific depending on my needs, etc. So, what are folks doing in this regard, any tips, recommendations, suggestions, etc.? Is there some way to indicate dependencies like this that I simply don''t know about? -- Christopher Bailey Cobalt Edge LLC http://cobaltedge.com
On Thu, Jun 26, 2008 at 4:37 AM, Christopher Bailey <chris at cobaltedge.com> wrote:> If there''s already been a thread on this, let me know (and if you can, > point me to it)...I asked something similar about a week or so ago, you can see it here: http://www.ruby-forum.com/topic/156392 It is on ''reusing story specs'' But I have done some more work since then...> In building my stories, I often need to setup a bunch of data where > you have multiple levels of models that depend on each other. For> Scenario: view doctors > Given: existing locations > And: existing organizations > And: existing doctorsYou can use plain text stories and use multiple steps_for to get a similar effect. But in this case, on that set of stories, it would make sense to reduce that Given block down to: # viewing doctors story file... Scenario: view doctors Given: existing doctors in organizations that have a location When... And then I would use some helpers or fixture loading to handle your data loading... # spec helper file... def build_valid_doctor(params) location = Location.create(:blah...) org = Organization.create(:location => location) Doctor.create({:organization => org}.merge(params)) end # steps file.... steps_for :viewing_doctors do Given "existing doctors in organizations that have a location" build_valid_doctor(:surname => ''Hyde'') build_valid_doctor(:surname => ''Jeckle'') end end Of course you can make those factory methods do all sorts of things... Hope that helps Mikel -- http://lindsaar.net/ Rails, RSpec, Puppet andLife blog....
On Jun 25, 2008, at 9:38 PM, Mikel Lindsaar wrote:> On Thu, Jun 26, 2008 at 4:37 AM, Christopher Bailey > <chris at cobaltedge.com> wrote: >> If there''s already been a thread on this, let me know (and if you >> can, >> point me to it)... > > I asked something similar about a week or so ago, you can see it here: > > http://www.ruby-forum.com/topic/156392 > > It is on ''reusing story specs'' > > But I have done some more work since then... > >> In building my stories, I often need to setup a bunch of data where >> you have multiple levels of models that depend on each other. For > >> Scenario: view doctors >> Given: existing locations >> And: existing organizations >> And: existing doctors > > You can use plain text stories and use multiple steps_for to get a > similar effect. > > But in this case, on that set of stories, it would make sense to > reduce that Given block down to: > > # viewing doctors story file... > Scenario: view doctors > Given: existing doctors in organizations that have a location > When... > > And then I would use some helpers or fixture loading to handle your > data loading... > > # spec helper file... > def build_valid_doctor(params) > location = Location.create(:blah...) > org = Organization.create(:location => location) > Doctor.create({:organization => org}.merge(params)) > end > > # steps file.... > steps_for :viewing_doctors do > > Given "existing doctors in organizations that have a location" > build_valid_doctor(:surname => ''Hyde'') > build_valid_doctor(:surname => ''Jeckle'') > end > > end > > > Of course you can make those factory methods do all sorts of things...It really seems you are asking two questions: One about reusability, and one about setting up data. I can''t add anything to the first, but factories are definitely the way to go regarding the second issue (setting up the data). Check out this post by Dan Manges (and look at the fixture options at the end of the post): http://www.dcmanges.com/blog/38 Scott> > > Hope that helps > > Mikel > > -- > http://lindsaar.net/ > Rails, RSpec, Puppet andLife blog.... > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users
In reply to both of the last two replies to my post... I am already doing the factory stuff for data creation. My question is more about dependencies between fixture data sets. So, you have 3 related models: A, B, C. Model A can stand on its own. Model B can''t exist without an A, and C can''t exist without a B (which means it also indirectly requires an A). I have factories that create these things, and helper methods that create sets of them (since I need fairly specific relationships, not just randomly generated ones like say object_daddy or factory_girl plugins/gems help with (although I have used object_daddy and like it - tried to use factory girl, but had problems). It''s not really a true "problem", it''s more that there is an inherant dependency here, where there isn''t a very expressive way of stating that. So, more a point of discussing how other folks are handling this and making things clear in their code that their are dependencies. The idea to combine the 3 givens is a point I''ll look at, as I think I agree that that probably conveys the dependency and association between the three models better. The other thing I''m finding a lot is that I have a lot of the same needs for this fixture type data between my regular RSpec examples (model tests mostly, as I''m going light on controller and view tests and mostly doing stories) and my RSpec stories. Are folks using say a single helper/factory to generate fixture data for both? I guess I only just though of sharing it between them now, as there really is no technological barrier to doing so, although in my examples I do tend to leverage mocks and stubs when I can, but stay strictly "real" with stories. On Wed, Jun 25, 2008 at 7:07 PM, Scott Taylor <mailing_lists at railsnewbie.com> wrote:> > On Jun 25, 2008, at 9:38 PM, Mikel Lindsaar wrote: > >> On Thu, Jun 26, 2008 at 4:37 AM, Christopher Bailey >> <chris at cobaltedge.com> wrote: >>> >>> If there''s already been a thread on this, let me know (and if you can, >>> point me to it)... >> >> I asked something similar about a week or so ago, you can see it here: >> >> http://www.ruby-forum.com/topic/156392 >> >> It is on ''reusing story specs'' >> >> But I have done some more work since then... >> >>> In building my stories, I often need to setup a bunch of data where >>> you have multiple levels of models that depend on each other. For >> >>> Scenario: view doctors >>> Given: existing locations >>> And: existing organizations >>> And: existing doctors >> >> You can use plain text stories and use multiple steps_for to get a >> similar effect. >> >> But in this case, on that set of stories, it would make sense to >> reduce that Given block down to: >> >> # viewing doctors story file... >> Scenario: view doctors >> Given: existing doctors in organizations that have a location >> When... >> >> And then I would use some helpers or fixture loading to handle your >> data loading... >> >> # spec helper file... >> def build_valid_doctor(params) >> location = Location.create(:blah...) >> org = Organization.create(:location => location) >> Doctor.create({:organization => org}.merge(params)) >> end >> >> # steps file.... >> steps_for :viewing_doctors do >> >> Given "existing doctors in organizations that have a location" >> build_valid_doctor(:surname => ''Hyde'') >> build_valid_doctor(:surname => ''Jeckle'') >> end >> >> end >> >> >> Of course you can make those factory methods do all sorts of things... > > > It really seems you are asking two questions: One about reusability, and one > about setting up data. > > I can''t add anything to the first, but factories are definitely the way to > go regarding the second issue (setting up the data). Check out this post by > Dan Manges (and look at the fixture options at the end of the post): > > http://www.dcmanges.com/blog/38 > > Scott > >> >> >> Hope that helps >> >> Mikel >> >> -- >> http://lindsaar.net/ >> Rails, RSpec, Puppet andLife blog.... >> _______________________________________________ >> rspec-users mailing list >> rspec-users at rubyforge.org >> http://rubyforge.org/mailman/listinfo/rspec-users > > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >-- Christopher Bailey Cobalt Edge LLC http://cobaltedge.com
On Thu, Jun 26, 2008 at 12:18 PM, Christopher Bailey <chris at cobaltedge.com> wrote:> The other thing I''m finding a lot is that I have a lot of the same > needs for this fixture type data between my regular RSpec examples > (model tests mostly, as I''m going light on controller and view tests > and mostly doing stories) and my RSpec stories. Are folks using say a > single helper/factory to generate fixture data for both? I guess I > only just though of sharing it between them now, as there really is no > technological barrier to doing so, although in my examples I do tend > to leverage mocks and stubs when I can, but stay strictly "real" with > stories.For me, I tend to use a Model.build_valid pattern to create objects required in my controller view or model specs and then only really stub required behaviour... sort of like cherry picking stubs. So I wouldn''t stub the ''name'' method on a person, instead, I would create a valid person with the name I need. But I would stub that ''save'' returns ''true'' or something of the like as I need to ensure a particular execution path. This arguably makes specs more brittle, but for me, finding and fixing failed dependencies as soon as possible is better than having to manually ensure that every method being called in a view is covered elsewhere by a spec... and in changing a spec later, I get instant feedback on if I have a regression failure elsewhere. The other drawback you have with fixture data in stories is that they are by definition an artificial state. It is not guaranteed that the state you create with fixtures could be reproduced by your code. Only through your code executing can you find the relevant states and you might introduce an arbitrary in your fixture data that creates an impossible state allowing your specs to pass. So I ban fixtures in stories in my team for that reason. Anything you need in a story needs to be encompassed in the Given of that story and the story needs to be able to be read in isolation with all requirements visible, see my blog post on "Being clever in specs is for dummies" at http://www.lindsaar.net/2008/6/24/tip-24-being-clever-in-specs-is-for-dummies For more on what I mean about that, the example is mainly for a describe BDD block, but it applies equally well to a story. Regards Mikel -- http://lindsaar.net/ Rails, RSpec, Puppet andLife blog....
I agree in general on fixtures, depending on how you define "fixtures". I never use the standard Rails fixtures, or any YAML based fixture data. I always generate my data from a factory or real ActiveRecord call to create the object. But, I still consider this essentially "fixture" data, it''s just created a different way. It''s a trade-off. If in my stories I had to walk through the view and create the 30+ objects I needed just to setup my test, well, that test just might not get written. So to me, I use real ActiveRecord calls (via a factory or helper of whatever kind), so that at least I know the model creation is going through the real code, and is pretty close to the path that the controller would do. Then I test whatever it is I''m testing that needs to have data like that. For tests of new/create views, I of course actually create the models via the view (I use Webrat), and such, so that is definitely real, and that to me covers that case sufficiently. On Wed, Jun 25, 2008 at 7:38 PM, Mikel Lindsaar <raasdnil at gmail.com> wrote:> On Thu, Jun 26, 2008 at 12:18 PM, Christopher Bailey > <chris at cobaltedge.com> wrote: >> The other thing I''m finding a lot is that I have a lot of the same >> needs for this fixture type data between my regular RSpec examples >> (model tests mostly, as I''m going light on controller and view tests >> and mostly doing stories) and my RSpec stories. Are folks using say a >> single helper/factory to generate fixture data for both? I guess I >> only just though of sharing it between them now, as there really is no >> technological barrier to doing so, although in my examples I do tend >> to leverage mocks and stubs when I can, but stay strictly "real" with >> stories. > > For me, I tend to use a Model.build_valid pattern to create objects > required in my controller view or model specs and then only really > stub required behaviour... sort of like cherry picking stubs. > > So I wouldn''t stub the ''name'' method on a person, instead, I would > create a valid person with the name I need. But I would stub that > ''save'' returns ''true'' or something of the like as I need to ensure a > particular execution path. > > This arguably makes specs more brittle, but for me, finding and fixing > failed dependencies as soon as possible is better than having to > manually ensure that every method being called in a view is covered > elsewhere by a spec... and in changing a spec later, I get instant > feedback on if I have a regression failure elsewhere. > > The other drawback you have with fixture data in stories is that they > are by definition an artificial state. It is not guaranteed that the > state you create with fixtures could be reproduced by your code. Only > through your code executing can you find the relevant states and you > might introduce an arbitrary in your fixture data that creates an > impossible state allowing your specs to pass. > > So I ban fixtures in stories in my team for that reason. Anything you > need in a story needs to be encompassed in the Given of that story and > the story needs to be able to be read in isolation with all > requirements visible, see my blog post on "Being clever in specs is > for dummies" at > > http://www.lindsaar.net/2008/6/24/tip-24-being-clever-in-specs-is-for-dummies > > For more on what I mean about that, the example is mainly for a > describe BDD block, but it applies equally well to a story. > > Regards > > Mikel > > > -- > http://lindsaar.net/ > Rails, RSpec, Puppet andLife blog.... > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >-- Christopher Bailey Cobalt Edge LLC http://cobaltedge.com
On Jun 25, 2008, at 9:38 PM, Mikel Lindsaar wrote:> http://www.lindsaar.net/2008/6/24/tip-24-being-clever-in-specs-is-for-dummiesThat post is fantastic. Thanks!
On 26-jun-2008, at 15:48, David Chelimsky wrote:> On Jun 25, 2008, at 9:38 PM, Mikel Lindsaar wrote: >> http://www.lindsaar.net/2008/6/24/tip-24-being-clever-in-specs-is- >> for-dummies > > That post is fantastic. Thanks!Couldn''t agree more with that post... For instance, restful_authentication now comes with specs, but, ehrm... See for yourself: http://pastie.org/222670 gr, bartz
On Fri, Jun 27, 2008 at 1:25 AM, Bart Zonneveld <loop at superinfinite.com> wrote:> On 26-jun-2008, at 15:48, David Chelimsky wrote: >> On Jun 25, 2008, at 9:38 PM, Mikel Lindsaar wrote: >>> http://www.lindsaar.net/2008/6/24/tip-24-being-clever-in-specs-is-for-dummies >> That post is fantastic. Thanks! > Couldn''t agree more with that post... For instance, restful_authenticationThanks guys. spread the word... I am sick of having to mentally translate everything in specs :) -- http://lindsaar.net/ Rails, RSpec, Puppet andLife blog....
On Jun 26, 2008, at 11:25 AM, Bart Zonneveld wrote:> > On 26-jun-2008, at 15:48, David Chelimsky wrote: > >> On Jun 25, 2008, at 9:38 PM, Mikel Lindsaar wrote: >>> http://www.lindsaar.net/2008/6/24/tip-24-being-clever-in-specs-is-for-dummies >> >> That post is fantastic. Thanks! > > Couldn''t agree more with that post... For instance, > restful_authentication now comes with specs, but, ehrm... See for > yourself: http://pastie.org/222670 >haha. I have no idea what''s going on there.
Scott Taylor wrote:> > On Jun 26, 2008, at 11:25 AM, Bart Zonneveld wrote: > >> >> On 26-jun-2008, at 15:48, David Chelimsky wrote: >> >>> On Jun 25, 2008, at 9:38 PM, Mikel Lindsaar wrote: >>>> http://www.lindsaar.net/2008/6/24/tip-24-being-clever-in-specs-is-for-dummies >>>> >>> >>> That post is fantastic. Thanks! >> >> Couldn''t agree more with that post... For instance, >> restful_authentication now comes with specs, but, ehrm... See for >> yourself: http://pastie.org/222670 >> > > haha. I have no idea what''s going on there. > >This is slightly OT.. but looking at those specs brings up one of my other pet peeves, and that is excluding the "should" from the specs. I have seen a lot of projects and developers that I respect highly not use the word "should" in there specs. I have accepted it as just one of those things that people disagree on, but I think there is a lot of value of having the "should". For one it makes removing the example easier when it becomes incorrect (meaning, the expected behaviour has changed.) I guess I just see the "should" as being a bigger part of BDD than some people. Am I the only one who thinks this or what are the arguments for not using ''should''? -Ben
>>>>> http://www.lindsaar.net/2008/6/24/tip-24-being-clever-in-specs-is-for-dummies >>>> >>>> That post is fantastic. Thanks! >>> >>> Couldn''t agree more with that post... For instance, >>> restful_authentication now comes with specs, but, ehrm... See for >>> yourself: http://pastie.org/222670 >> >> haha. I have no idea what''s going on there. > > This is slightly OT.. but looking at those specs brings up one of my > other pet peeves, and that is excluding the "should" from the > specs. I have seen a lot of projects and developers that I respect > highly not use the word "should" in there specs. I have accepted it > as just one of those things that people disagree on, but I think > there is a lot of value of having the "should". For one it makes > removing the example easier when it becomes incorrect (meaning, the > expected behaviour has changed.) I guess I just see the "should" as > being a bigger part of BDD than some people. > > Am I the only one who thinks this or what are the arguments for not > using ''should''?I''ve been meaning to ask the list about this for a while now. I don''t always use "should", but I''ve been trying to come up with a standard way to approach the Rails has_one, has_many, etc. as opposed to methods on the object such as name, description etc. What I mean is that I want to write specs so that I know if something refers to an associated object or not, without resorting to writing technically oriented specs that define implementation rather than behavior. "project should have an owner" unfortunately doesn''t let me know if it''s a method that returns a value, or a method that returns another object. Does anyone have advice or experience in writing the specs to provide that kind of information? I hope this isn''t too much of a thread hijack. But to bring it back around, I totally agree with the article, and it''s particularly apropos for open source projects (assuming the project owner wants new users to get involved in development) -Jim
David Chelimsky
2008-Jun-28 02:07 UTC
[rspec-users] Should(not?) test associations (was: Dealing with dependent data)
On Jun 27, 2008, at 6:58 PM, Jim Gay wrote:> I''ve been meaning to ask the list about this for a while now. > > I don''t always use "should", but I''ve been trying to come up with a > standard way to approach the Rails has_one, has_many, etc. as > opposed to methods on the object such as name, description etc. > What I mean is that I want to write specs so that I know if > something refers to an associated object or not, without resorting > to writing technically oriented specs that define implementation > rather than behavior. > "project should have an owner" unfortunately doesn''t let me know if > it''s a method that returns a value, or a method that returns another > object.An association does not want you to know that it''s an association. It wants you to think of it as any other attribute. Why do you care what it IS? Focus on what it DOES.> Does anyone have advice or experience in writing the specs to > provide that kind of information? > > I hope this isn''t too much of a thread hijack.We''ll make a new thread then :) My opinion is that attributes and associations are equally about structure, not behaviour. The fact that a project has an owner is not behaviour. The fact that the owner has an email address is not behaviour. The facts that you can''t save a project without an owner, and you can''t save an owner without a valid email address are behaviour. And by setting expectations around those, the attributes and associations themselves are handled implicitly: describe Project do it "should not be valid without an owner" do Project.new(:owner => nil).should_not be_valid end end Watch that fail saying that Project does not respond to ''owner='' method. Add a migration and an association. Now it fails saying that it was valid. Add the validation and watch the example pass. That''s TDD (yes, starting with a T). Any time I have a an attribute or an association that I *think* is supposed to be on a model, I try to think of what might be interesting about that attribute or association and set expectations about that. There are many who believe that we should have examples like "project.should have_one(:owner)." I can''t say that those people are wrong if doing that is adding value to their process and helping them deliver quality software. For me, personally, it''s just unnecessary noise that adds maintenance burden later when things move around. And it definitely ain''t behaviour. Cheers, David
Jim Gay
2008-Jun-28 02:55 UTC
[rspec-users] Should(not?) test associations (was: Dealing with dependent data)
On Jun 27, 2008, at 10:07 PM, David Chelimsky wrote:> An association does not want you to know that it''s an association. > It wants you to think of it as any other attribute. Why do you care > what it IS? Focus on what it DOES.Good point. Being a newbie I sometimes find myself where I *think* I''m doing it well, but find out that it''s not quite that good afterall.> > My opinion is that attributes and associations are equally about > structure, not behaviour. The fact that a project has an owner is > not behaviour. The fact that the owner has an email address is not > behaviour. > > The facts that you can''t save a project without an owner, and you > can''t save an owner without a valid email address are behaviour. And > by setting expectations around those, the attributes and > associations themselves are handled implicitly: > > describe Project do > it "should not be valid without an owner" do > Project.new(:owner => nil).should_not be_valid > end > end > > Watch that fail saying that Project does not respond to ''owner='' > method. Add a migration and an association. Now it fails saying that > it was valid. Add the validation and watch the example pass. That''s > TDD (yes, starting with a T). > > Any time I have a an attribute or an association that I *think* is > supposed to be on a model, I try to think of what might be > interesting about that attribute or association and set expectations > about that. > > There are many who believe that we should have examples like > "project.should have_one(:owner)." I can''t say that those people are > wrong if doing that is adding value to their process and helping > them deliver quality software. For me, personally, it''s just > unnecessary noise that adds maintenance burden later when things > move around. And it definitely ain''t behaviour.Thanks for the response. Perhaps I''m over thinking things. I agree that "project.should have_one(:owner)" is unnecessary. Somewhere the ideas get mangled for me. Suppose a simple spec like this: Project "should not be valid without a name" Owner "should not be valid without a name" How do you spec that the Owner may have 0 or more projects? Owner "should be valid with 0 projects" Owner "should be valid with more than 0 projects" Or would you combine them Owner "should have 0 or more projects" Or should I not care at all about that and just specify that a Project "should not be valid without an owner"?
David Chelimsky
2008-Jun-28 09:32 UTC
[rspec-users] Should(not?) test associations (was: Dealing with dependent data)
On Jun 27, 2008, at 9:55 PM, Jim Gay wrote:> On Jun 27, 2008, at 10:07 PM, David Chelimsky wrote: >> An association does not want you to know that it''s an association. >> It wants you to think of it as any other attribute. Why do you care >> what it IS? Focus on what it DOES. > > Good point. Being a newbie I sometimes find myself where I *think* > I''m doing it well, but find out that it''s not quite that good > afterall.There''s a great bit of advice in The Inner Game of Tennis that suggests that judging your progress with statements like "I''m doing well" or "I''m doing badly" is counter-productive; that it''s more productive to think in terms of observing whether your actions get you to your goal and adjusting based on your observations. You''re doing fine.>> My opinion is that attributes and associations are equally about >> structure, not behaviour. The fact that a project has an owner is >> not behaviour. The fact that the owner has an email address is not >> behaviour. >> >> The facts that you can''t save a project without an owner, and you >> can''t save an owner without a valid email address are behaviour. >> And by setting expectations around those, the attributes and >> associations themselves are handled implicitly: >> >> describe Project do >> it "should not be valid without an owner" do >> Project.new(:owner => nil).should_not be_valid >> end >> end >> >> Watch that fail saying that Project does not respond to ''owner='' >> method. Add a migration and an association. Now it fails saying >> that it was valid. Add the validation and watch the example pass. >> That''s TDD (yes, starting with a T). >> >> Any time I have a an attribute or an association that I *think* is >> supposed to be on a model, I try to think of what might be >> interesting about that attribute or association and set >> expectations about that. >> >> There are many who believe that we should have examples like >> "project.should have_one(:owner)." I can''t say that those people >> are wrong if doing that is adding value to their process and >> helping them deliver quality software. For me, personally, it''s >> just unnecessary noise that adds maintenance burden later when >> things move around. And it definitely ain''t behaviour. > > Thanks for the response. Perhaps I''m over thinking things. I agree > that "project.should have_one(:owner)" is unnecessary. > > Somewhere the ideas get mangled for me. > Suppose a simple spec like this: > > Project "should not be valid without a name" > Owner "should not be valid without a name" > > How do you spec that the Owner may have 0 or more projects?Again, structure. Why do you care? Does an owner behave differently if there are 0 projects or more than 0? Is there a maximum number of projects? Maybe projects should be tagged and you want to be able to get an owner''s projects by tag? Now THAT''s interesting behaviour that you can write examples for.> Owner "should be valid with 0 projects" > Owner "should be valid with more than 0 projects" > > Or would you combine them > > Owner "should have 0 or more projects" > > Or should I not care at all about that and just specify that a > Project "should not be valid without an owner"?I''m beginning to regret the validity example, because it is somewhat structural as well. The behaviour is not whether it''s valid or not, but rather whether you can save it or not. So scratch the example I gave earlier and think about this: describe Project do describe "when trying to save" do it "should complain if it has no owner" do lambda do Project.new(:owner => nil).save! end.should raise_error(ActiveRecord::RecordInvalid) end end end (Zach Dennis - this nesting structure should make you happy :) ) That make a bit more sense? One key aspect of BDD is working Outside-In. I try to start with a story and to drive things down from the view to the model (in Rails). So maybe my story is that as an owner I can edit my projects, but not other people''s projects. This is going to naturally lead me towards examples that will implicitly cover the fact that an owner can more than 0 projects without actually specifying that directly. HTH, David
Jim Gay
2008-Jun-28 13:52 UTC
[rspec-users] Should(not?) test associations (was: Dealing with dependent data)
On Jun 28, 2008, at 5:32 AM, David Chelimsky wrote:> I''m beginning to regret the validity example, because it is somewhat > structural as well. The behaviour is not whether it''s valid or not, > but rather whether you can save it or not. So scratch the example I > gave earlier and think about this: > > describe Project do > describe "when trying to save" do > it "should complain if it has no owner" do > lambda do > Project.new(:owner => nil).save! > end.should raise_error(ActiveRecord::RecordInvalid) > end > end > end > > (Zach Dennis - this nesting structure should make you happy :) ) > > That make a bit more sense?Absolutely!> One key aspect of BDD is working Outside-In. I try to start with a > story and to drive things down from the view to the model (in > Rails). So maybe my story is that as an owner I can edit my > projects, but not other people''s projects. This is going to > naturally lead me towards examples that will implicitly cover the > fact that an owner can more than 0 projects without actually > specifying that directly.Trying to wrap my head around how to go about BDD has been difficult and I think I now understand why. Many of the examples I''ve seen for RSpec have used things like "should be valid" when that doesn''t actually describe behavior at all. The first RSpec generated Rails specs that I used had plenty of this but that seems to be more about implementation than behavior, so I''ve had trouble understanding how to really describe behavior. Little by little I''m getting it, but I unfortunately don''t feel like I have time to go BDD cold turkey. I still do some code first and then spec, but I understand the benefits of BDD and I''m sure I''ll get to that point eventually.
David Chelimsky
2008-Jun-28 14:34 UTC
[rspec-users] Should(not?) test associations (was: Dealing with dependent data)
On Jun 28, 2008, at 8:52 AM, Jim Gay wrote:> On Jun 28, 2008, at 5:32 AM, David Chelimsky wrote: >> I''m beginning to regret the validity example, because it is >> somewhat structural as well. The behaviour is not whether it''s >> valid or not, but rather whether you can save it or not. So scratch >> the example I gave earlier and think about this: >> >> describe Project do >> describe "when trying to save" do >> it "should complain if it has no owner" do >> lambda do >> Project.new(:owner => nil).save! >> end.should raise_error(ActiveRecord::RecordInvalid) >> end >> end >> end >> >> (Zach Dennis - this nesting structure should make you happy :) ) >> >> That make a bit more sense? > > Absolutely! > >> One key aspect of BDD is working Outside-In. I try to start with a >> story and to drive things down from the view to the model (in >> Rails). So maybe my story is that as an owner I can edit my >> projects, but not other people''s projects. This is going to >> naturally lead me towards examples that will implicitly cover the >> fact that an owner can more than 0 projects without actually >> specifying that directly. > > Trying to wrap my head around how to go about BDD has been difficult > and I think I now understand why. Many of the examples I''ve seen for > RSpec have used things like "should be valid" when that doesn''t > actually describe behavior at all. The first RSpec generated Rails > specs that I used had plenty of thisUgh! You''re right. I''m going to review the generators (they were written a lot of water-under-the-bridge-ago).> ... but that seems to be more about implementation than behavior, so > I''ve had trouble understanding how to really describe behavior. > > Little by little I''m getting it, but I unfortunately don''t feel like > I have time to go BDD cold turkey. I still do some code first and > then spec, but I understand the benefits of BDD and I''m sure I''ll > get to that point eventually.Try this as a next step: * code a little * comment out your code * write a small example for a small bit of the commented code * watch it fail * uncomment just enough to make it pass * watch it pass * repeat the last 4 steps This is NOT the end-game, but it will give you a feel for the TDD flow. Plus, at some level, we''re all usually operating with some knowledge about the code we''re going to write. When we''re not, it''s common practice from old-school-TDD to code a little, throw out the code entirely (not comment it, but actually delete it) and then start w/ examples. The reason we throw it out is the "code a little" phase quite often introduces something we just don''t need. In the comment/ uncomment approach, those unnecessary bits tend to stick around because we *think* we need them. One great promise of TDD is that it encourages less code because we''re working against executable examples rather than assumptions about what the code does based on looking at it. Cheers, David