Hi list, I''m writing an example for a class that represents the "pickaxe" e-book, which I view in Preview.app: describe PickaxeBook do ... it "should tell whether it''s ready to read" do preview = stub(''preview'') preview.stub!(:******this is what I''m not sure about - see below*******).returns("programming_ruby_1.9.pdf") my_pickaxe_book = PickaxeBook.new(preview) my_pickaxe_book.should be_ready_to_read end end class PickaxeBook ... def ready_to_read? #****** this is the dependency I want to stub: preview.front_window.title ******** preview.front_window.title =~ /programming_ruby_1.9\.pdf.*/ end end Can you see the problem? ready_to_read wants to query the object returned by front_window, but how do I stub that? I should note that the Preview class is in a different library, which is why I don''t just change front_window.title I thought of a few things, like introducing a role (something like "PreviewInfoRetriever") with a method "front_window_title" that forwards to preview.front_window.title, but that seems like a lot of complexity. To summarize: what''s the best way to handle a dependency like object.method.method? Thanks! Sean DeNigris sean at clipperadams.com
On Fri, Jan 8, 2010 at 9:37 PM, DeNigris Sean <sean at clipperadams.com> wrote:> Hi list, > > I''m writing an example for a class that represents the "pickaxe" e-book, > which I view in Preview.app: > > describe PickaxeBook do > ... > it "should tell whether it''s ready to read" do > preview = stub(''preview'') > preview.stub!(:******this is what I''m not sure about - see > below*******).returns("programming_ruby_1.9.pdf") > > my_pickaxe_book = PickaxeBook.new(preview) > > my_pickaxe_book.should be_ready_to_read > end > end > > class PickaxeBook > ... > def ready_to_read? > #****** this is the dependency I want to stub: > preview.front_window.title ******** > preview.front_window.title =~ /programming_ruby_1.9\.pdf.*/ > end > end > > Can you see the problem? ready_to_read wants to query the object returned > by front_window, but how do I stub that? I should note that the Preview > class is in a different library, which is why I don''t just change > front_window.title > > I thought of a few things, like introducing a role (something like > "PreviewInfoRetriever") with a method "front_window_title" that forwards to > preview.front_window.title, but that seems like a lot of complexity. > > To summarize: what''s the best way to handle a dependency like > object.method.method? >There is no universally best way. Stubbing it is fairly straightforward: window = stub(''window'', :title => "programming_ruby_1.9.pdf") preview = stub(''preview'', :front_window => window) The risk is that this example is now bound to the internal structure of an object provided by a 3rd party, which can change in a future release. If that happened, this example might continue passing with a false positive, and the app won''t work. If you have good high level specs with something like Cucumber or FitNesse, this risk is diminished. You''ll still have to change the example when the internal structure of Preview changes, but you''re less likely to get burned by deploying code that passes its tests but doesn''t work. If it''s easy and inexpensive to create a real instance of Preview, I''d sooner do that. HTH, David> Thanks! > > Sean DeNigris > sean at clipperadams.com > > > > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rspec-users/attachments/20100109/5e5473e5/attachment.html>
On 9 Jan 2010, at 12:02, David Chelimsky wrote:> On Fri, Jan 8, 2010 at 9:37 PM, DeNigris Sean > <sean at clipperadams.com> wrote: > Hi list, > > I''m writing an example for a class that represents the "pickaxe" e- > book, which I view in Preview.app: > > describe PickaxeBook do > ... > it "should tell whether it''s ready to read" do > preview = stub(''preview'') > preview.stub!(:******this is what I''m not sure about > - see below*******).returns("programming_ruby_1.9.pdf") > > my_pickaxe_book = PickaxeBook.new(preview) > > my_pickaxe_book.should be_ready_to_read > end > end > > class PickaxeBook > ... > def ready_to_read? > #****** this is the dependency I want to stub: > preview.front_window.title ******** > preview.front_window.title =~ / > programming_ruby_1.9\.pdf.*/ > end > end > > Can you see the problem? ready_to_read wants to query the object > returned by front_window, but how do I stub that? I should note > that the Preview class is in a different library, which is why I > don''t just change front_window.title > > I thought of a few things, like introducing a role (something like > "PreviewInfoRetriever") with a method "front_window_title" that > forwards to preview.front_window.title, but that seems like a lot of > complexity. > > To summarize: what''s the best way to handle a dependency like > object.method.method? > > There is no universally best way. Stubbing it is fairly > straightforward: > > window = stub(''window'', :title => "programming_ruby_1.9.pdf") > preview = stub(''preview'', :front_window => window) > > The risk is that this example is now bound to the internal structure > of an object provided by a 3rd party, which can change in a future > release. If that happened, this example might continue passing with > a false positive, and the app won''t work. > > If you have good high level specs with something like Cucumber or > FitNesse, this risk is diminished. You''ll still have to change the > example when the internal structure of Preview changes, but you''re > less likely to get burned by deploying code that passes its tests > but doesn''t work. > > If it''s easy and inexpensive to create a real instance of Preview, > I''d sooner do that.Or wrap the Preview object with your own (maybe PreviewWindow?) and offer a #has_title? method on that wrapper.> > HTH, > David > > Thanks! > > Sean DeNigris > sean at clipperadams.com > > > > _______________________________________________ > 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-userscheers, Matt http://mattwynne.net +447974 430184
> window = stub(''window'', :title => "programming_ruby_1.9.pdf") > preview = stub(''preview'', :front_window => window)Perfect - so easy! Thanks.> If you have good high level specs with something like Cucumber or FitNesse, > this risk is diminished. You''ll still have to change the example when the > internal structure of Preview changes, but you''re less likely to get burned > by deploying code that passes its tests but doesn''t work.This is something I''ve been going back and forth with a lot lately - how much implementation detail to allow to leak out into the examples/ features. If I start using software other than Preview to read my eBooks, obviously all these examples will require reworking. The problem is magnified because I do have Cucumber tests that use the real Preview: Then /^I should see the pickaxe book$/ do front_preview_window = Appscript::app(''System Events'').processes [''Preview''].windows[1] Appscript::app(''System Events'').processes [''Preview''].frontmost.get.should be(true) front_preview_window.name.get.should =~ /programming_ruby_1.9.* \.pdf.*/ end Now details about Preview appear in Cucumber and Rspec! I''m tempted to put an EBookViewer role in right off the bat (similar to what Matt sugested), and use it in both the features and examples, but I don''t want to add too much complexity. I''m very interested in how other people handle external dependencies in features/examples... Thanks again! Sean
On Sat, Jan 9, 2010 at 7:38 PM, Sean DeNigris <trusted08 at clipperadams.com> wrote:>> ? window = stub(''window'', :title => "programming_ruby_1.9.pdf") >> ? preview = stub(''preview'', :front_window => window) > Perfect - so easy! ?Thanks. >There''s also stub_chain, which is probably a Bad Thing but helps break through layers of dependencies.
On Sat, Jan 9, 2010 at 9:38 PM, Sean DeNigris <trusted08 at clipperadams.com>wrote:> > window = stub(''window'', :title => "programming_ruby_1.9.pdf") > > preview = stub(''preview'', :front_window => window) > Perfect - so easy! Thanks. > > > If you have good high level specs with something like Cucumber or > FitNesse, > > this risk is diminished. You''ll still have to change the example when the > > internal structure of Preview changes, but you''re less likely to get > burned > > by deploying code that passes its tests but doesn''t work. > This is something I''ve been going back and forth with a lot lately - > how much implementation detail to allow to leak out into the examples/ > features. If I start using software other than Preview to read my > eBooks, obviously all these examples will require reworking. The > problem is magnified because I do have Cucumber tests that use the > real Preview: > > Then /^I should see the pickaxe book$/ do > front_preview_window = Appscript::app(''System Events'').processes > [''Preview''].windows[1] > Appscript::app(''System Events'').processes > [''Preview''].frontmost.get.should be(true) > front_preview_window.name.get.should =~ /programming_ruby_1.9.* > \.pdf.*/ > end > > Now details about Preview appear in Cucumber and Rspec! I''m tempted > to put an EBookViewer role in right off the bat (similar to what Matt > sugested), and use it in both the features and examples, but I don''t > want to add too much complexity. >I think it''s clear that there is already too much complexity in this case :) I''d go with the wrapper. It should not be expensive to maintain, and it does give you the freedom to change the dependencies, localizing the cost of that change to a single object.> I''m very interested in how other people handle external dependencies > in features/examples... > > Thanks again! > > Sean >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rspec-users/attachments/20100110/4829b515/attachment.html>