Brian Takita
2006-Nov-21 09:52 UTC
[rspec-users] Specification Reuse to avoid Combinatorial Explosions
Hello, While reading Dan North''s BDD tutorial <http://dannorth.net/introducing-bdd>, I tried to implement his ATM example as spec stubs. When I first implemented it creating a context for each of his scenarios, I noticed that there is duplication and a combinatorial explosion of the specs. I attached the full files to this email. For brevity, I will use scenario 1 in the body of this email. For the purpose of this exercise, one should imagine that each specification is at least 5 lines. Here is how I implemented scenario 1: context %{A Withdrawal where an Account is in credit AND the card is valid AND the dispenser contains cash AND the customer requests cash} do specify "should debit the account" do end specify "should dispense cash" do end specify "should return the card" do end end That got me experimenting on reusing specifications by using a module to create the specs. This is in customer_withdraws_cash_spec.rb: module CustomerWithdrawsCashSpec def should_debit_the_account specify "should debit the account" do end end ... end ... context %{A Withdrawal where an Account is in credit AND the card is valid AND the dispenser contains cash AND the customer requests cash} do extend CustomerWithdrawsCashSpec should_debit_the_account should_dispense_cash should_return_the_card end This is currently possible with rspec 0.7.2. Whats interesting about putting all of the specifications into a module is that you can reduce the context to a few lines. This makes each context (scenario readable) making it more feasible to have multiple contexts in a single file such as this group of scenarios represented as contexts. I also played with a more DSL-like syntax for this, which does not work for rspec 0.7.2. This is in customer_withdraws_cash_alternative_spec.rb:: CustomerWithdrawsCashSpec = context_module do specify "should debit the account" do end ... end context %{A Withdrawal where an Account is in credit AND the card is valid AND the dispenser contains cash AND the customer requests cash} do extend CustomerWithdrawsCashSpec specify "should debit the account" specify "should dispense cash" specify "should return the card" end As well as: context %{A Withdrawal where an Account is in credit AND the card is valid AND the dispenser contains cash AND the customer requests cash} do specify "should debit the account", CustomerWithdrawsCashSpec specify "should dispense cash", CustomerWithdrawsCashSpec specify "should return the card", CustomerWithdrawsCashSpec end Or just keep the underscore syntax: context %{A Withdrawal where an Account is in credit AND the card is valid AND the dispenser contains cash AND the customer requests cash} do extend CustomerWithdrawsCashSpec should_debit_the_account should_dispense_cash should_return_the_card end Thanks, Brian -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/rspec-users/attachments/20061121/64922509/attachment-0001.html -------------- next part -------------- A non-text attachment was scrubbed... Name: customer_withdraws_cash_spec.rb Type: application/x-ruby Size: 2383 bytes Desc: not available Url : http://rubyforge.org/pipermail/rspec-users/attachments/20061121/64922509/attachment-0002.bin -------------- next part -------------- A non-text attachment was scrubbed... Name: customer_withdraws_cash_alternative_spec.rb Type: application/x-ruby Size: 2300 bytes Desc: not available Url : http://rubyforge.org/pipermail/rspec-users/attachments/20061121/64922509/attachment-0003.bin
David Chelimsky
2006-Nov-21 13:48 UTC
[rspec-users] [rspec-devel] Specification Reuse to avoid Combinatorial Explosions
On 11/21/06, Brian Takita <brian.takita at gmail.com> wrote:> Hello, > > While reading Dan North''s BDD tutorial, I tried to implement his ATM example > as spec stubs. > When I first implemented it creating a context for each of his scenarios, I > noticed that there is duplication and a combinatorial explosion of the > specs. > > I attached the full files to this email. For brevity, I will use scenario 1 > in the body of this email. For the purpose of this exercise, one should > imagine that each specification is at least 5 lines. > > Here is how I implemented scenario 1: > > context %{A Withdrawal where an Account is in credit > AND the card is valid > AND the dispenser contains cash > AND the customer requests cash} do > > specify "should debit the account" do > end > specify "should dispense cash" do > end > specify "should return the card" do > end > end > > That got me experimenting on reusing specifications by using a module to > create the specs. This is in > customer_withdraws_cash_spec.rb: > > module CustomerWithdrawsCashSpec > def should_debit_the_account > specify "should debit the account" do > end > end > ... > end > ... > context %{A Withdrawal where an Account is in credit > AND the card is valid > AND the dispenser contains cash > AND the customer requests cash} do > > extend CustomerWithdrawsCashSpec > should_debit_the_account > should_dispense_cash > should_return_the_card > end > > This is currently possible with rspec 0.7.2. > Whats interesting about putting all of the specifications into a module is > that you can reduce the context to a few lines. > This makes each context (scenario readable) making it more feasible to have > multiple contexts in a single file such as this group of scenarios > represented as contexts. > > I also played with a more DSL-like syntax for this, which does not work for > rspec 0.7.2. This is in > customer_withdraws_cash_alternative_spec.rb:: > > CustomerWithdrawsCashSpec = context_module do > specify "should debit the account" do > end > ... > end > > context %{A Withdrawal where an Account is in credit > AND the card is valid > AND the dispenser contains cash > AND the customer requests cash} do > > extend CustomerWithdrawsCashSpec > specify "should debit the account" > specify "should dispense cash" > specify "should return the card" > end > > As well as: > > context %{A Withdrawal where an Account is in credit > AND the card is valid > AND the dispenser contains cash > AND the customer requests cash} do > > specify "should debit the account", CustomerWithdrawsCashSpec > specify "should dispense cash", CustomerWithdrawsCashSpec > specify "should return the card", CustomerWithdrawsCashSpec > end > > Or just keep the underscore syntax: > > context %{A Withdrawal where an Account is in credit > AND the card is valid > AND the dispenser contains cash > AND the customer requests cash} do > > extend CustomerWithdrawsCashSpec > should_debit_the_account > should_dispense_cash > should_return_the_card > endInteresting ideas. If we pursue this, I''d like to find an approach that aligns w/ RSpecs current lack of constructs like classes and modules. So rather than CustomerWithdrawsCashSpec = context_module do ... context "..." do extend CustomerWithdrawsCashSpec I''d like something like context_module :customer_withdraws_cash do context "...", :customer_withdraws_cash do That''s not exactly right, but you get the idea. Also - I think it would be really helpful for this discussion if you *would* post the full specs so we can see what this stuff really looks like in context. Thanks Brian. David
Brandon Keepers
2006-Nov-21 20:51 UTC
[rspec-users] [rspec-devel] Specification Reuse to avoid Combinatorial Explosions
One of the things I''ve often wished for is nested contexts. This could help eliminate some duplication. context "A Widthdrawal" do context "where an Account is in credit" do context "and the card is valid" context "and the dispenser contains cash" do specify "should debit the account" do end specify "should dispense cash" do end specify "should return the card" do end end context "and the dispenser does not contain cash" do specify "should inform the user" do end end end end end Brandon On Nov 21, 2006, at 8:48 AM, David Chelimsky wrote:> On 11/21/06, Brian Takita <brian.takita at gmail.com> wrote: >> Hello, >> >> While reading Dan North''s BDD tutorial, I tried to implement his >> ATM example >> as spec stubs. >> When I first implemented it creating a context for each of his >> scenarios, I >> noticed that there is duplication and a combinatorial explosion of >> the >> specs. >> >> I attached the full files to this email. For brevity, I will use >> scenario 1 >> in the body of this email. For the purpose of this exercise, one >> should >> imagine that each specification is at least 5 lines. >> >> Here is how I implemented scenario 1: >> >> context %{A Withdrawal where an Account is in credit >> AND the card is valid >> AND the dispenser contains cash >> AND the customer requests cash} do >> >> specify "should debit the account" do >> end >> specify "should dispense cash" do >> end >> specify "should return the card" do >> end >> end >> >> That got me experimenting on reusing specifications by using a >> module to >> create the specs. This is in >> customer_withdraws_cash_spec.rb: >> >> module CustomerWithdrawsCashSpec >> def should_debit_the_account >> specify "should debit the account" do >> end >> end >> ... >> end >> ... >> context %{A Withdrawal where an Account is in credit >> AND the card is valid >> AND the dispenser contains cash >> AND the customer requests cash} do >> >> extend CustomerWithdrawsCashSpec >> should_debit_the_account >> should_dispense_cash >> should_return_the_card >> end >> >> This is currently possible with rspec 0.7.2. >> Whats interesting about putting all of the specifications into a >> module is >> that you can reduce the context to a few lines. >> This makes each context (scenario readable) making it more >> feasible to have >> multiple contexts in a single file such as this group of scenarios >> represented as contexts. >> >> I also played with a more DSL-like syntax for this, which does not >> work for >> rspec 0.7.2. This is in >> customer_withdraws_cash_alternative_spec.rb:: >> >> CustomerWithdrawsCashSpec = context_module do >> specify "should debit the account" do >> end >> ... >> end >> >> context %{A Withdrawal where an Account is in credit >> AND the card is valid >> AND the dispenser contains cash >> AND the customer requests cash} do >> >> extend CustomerWithdrawsCashSpec >> specify "should debit the account" >> specify "should dispense cash" >> specify "should return the card" >> end >> >> As well as: >> >> context %{A Withdrawal where an Account is in credit >> AND the card is valid >> AND the dispenser contains cash >> AND the customer requests cash} do >> >> specify "should debit the account", CustomerWithdrawsCashSpec >> specify "should dispense cash", CustomerWithdrawsCashSpec >> specify "should return the card", CustomerWithdrawsCashSpec >> end >> >> Or just keep the underscore syntax: >> >> context %{A Withdrawal where an Account is in credit >> AND the card is valid >> AND the dispenser contains cash >> AND the customer requests cash} do >> >> extend CustomerWithdrawsCashSpec >> should_debit_the_account >> should_dispense_cash >> should_return_the_card >> end > > Interesting ideas. If we pursue this, I''d like to find an approach > that aligns w/ RSpecs current lack of constructs like classes and > modules. So rather than > > CustomerWithdrawsCashSpec = context_module do ... > > context "..." do > extend CustomerWithdrawsCashSpec > > I''d like something like > > context_module :customer_withdraws_cash do > > context "...", :customer_withdraws_cash do > > That''s not exactly right, but you get the idea. > > Also - I think it would be really helpful for this discussion if you > *would* post the full specs so we can see what this stuff really looks > like in context. > > Thanks Brian. > > David > _______________________________________________ > rspec-devel mailing list > rspec-devel at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-devel
David Chelimsky
2006-Nov-21 21:08 UTC
[rspec-users] [rspec-devel] Specification Reuse to avoid Combinatorial Explosions
On 11/21/06, Brandon Keepers <bkeepers at gmail.com> wrote:> One of the things I''ve often wished for is nested contexts. This > could help eliminate some duplication.We''ve been through this a couple of times. Give this one a read please: http://rubyforge.org/pipermail/rspec-devel/2006-June/000175.html
David Chelimsky
2006-Nov-21 21:12 UTC
[rspec-users] [rspec-devel] Specification Reuse to avoid Combinatorial Explosions
On 11/21/06, David Chelimsky <dchelimsky at gmail.com> wrote:> On 11/21/06, Brandon Keepers <bkeepers at gmail.com> wrote: > > One of the things I''ve often wished for is nested contexts. This > > could help eliminate some duplication. > > We''ve been through this a couple of times. Give this one a read please: > > http://rubyforge.org/pipermail/rspec-devel/2006-June/000175.htmlSpecifically this reply from me: http://rubyforge.org/pipermail/rspec-devel/2006-June/000201.html
Brian Takita
2006-Nov-22 01:35 UTC
[rspec-users] [rspec-devel] Specification Reuse to avoid Combinatorial Explosions
On 11/21/06, David Chelimsky <dchelimsky at gmail.com> wrote:> > On 11/21/06, Brian Takita <brian.takita at gmail.com> wrote: > > Hello, > > > > While reading Dan North''s BDD tutorial, I tried to implement his ATM > example > > as spec stubs. > > When I first implemented it creating a context for each of his > scenarios, I > > noticed that there is duplication and a combinatorial explosion of the > > specs. > > > > I attached the full files to this email. For brevity, I will use > scenario 1 > > in the body of this email. For the purpose of this exercise, one should > > imagine that each specification is at least 5 lines. > > > > Here is how I implemented scenario 1: > > > > context %{A Withdrawal where an Account is in credit > > AND the card is valid > > AND the dispenser contains cash > > AND the customer requests cash} do > > > > specify "should debit the account" do > > end > > specify "should dispense cash" do > > end > > specify "should return the card" do > > end > > end > > > > That got me experimenting on reusing specifications by using a module to > > > create the specs. This is in > > customer_withdraws_cash_spec.rb: > > > > module CustomerWithdrawsCashSpec > > def should_debit_the_account > > specify "should debit the account" do > > end > > end > > ... > > end > > ... > > context %{A Withdrawal where an Account is in credit > > AND the card is valid > > AND the dispenser contains cash > > AND the customer requests cash} do > > > > extend CustomerWithdrawsCashSpec > > should_debit_the_account > > should_dispense_cash > > should_return_the_card > > end > > > > This is currently possible with rspec 0.7.2 . > > Whats interesting about putting all of the specifications into a module > is > > that you can reduce the context to a few lines. > > This makes each context (scenario readable) making it more feasible to > have > > multiple contexts in a single file such as this group of scenarios > > represented as contexts. > > > > I also played with a more DSL-like syntax for this, which does not work > for > > rspec 0.7.2. This is in > > customer_withdraws_cash_alternative_spec.rb:: > > > > CustomerWithdrawsCashSpec = context_module do > > specify "should debit the account" do > > end > > ... > > end > > > > context %{A Withdrawal where an Account is in credit > > AND the card is valid > > AND the dispenser contains cash > > AND the customer requests cash} do > > > > extend CustomerWithdrawsCashSpec > > specify "should debit the account" > > specify "should dispense cash" > > specify "should return the card" > > end > > > > As well as: > > > > context %{A Withdrawal where an Account is in credit > > AND the card is valid > > AND the dispenser contains cash > > AND the customer requests cash} do > > > > specify "should debit the account", CustomerWithdrawsCashSpec > > specify "should dispense cash", CustomerWithdrawsCashSpec > > specify "should return the card", CustomerWithdrawsCashSpec > > end > > > > Or just keep the underscore syntax: > > > > context %{A Withdrawal where an Account is in credit > > AND the card is valid > > AND the dispenser contains cash > > AND the customer requests cash} do > > > > extend CustomerWithdrawsCashSpec > > should_debit_the_account > > should_dispense_cash > > should_return_the_card > > end > > Interesting ideas. If we pursue this, I''d like to find an approach > that aligns w/ RSpecs current lack of constructs like classes and > modules. So rather than > > CustomerWithdrawsCashSpec = context_module do ... > > context "..." do > extend CustomerWithdrawsCashSpec > > I''d like something like > > context_module :customer_withdraws_cash do > > context "...", :customer_withdraws_cash do > > That''s not exactly right, but you get the idea. > > Also - I think it would be really helpful for this discussion if you > *would* post the full specs so we can see what this stuff really looks > like in context.I sent the files as attachments. I guess they got rejected. Here is the file that works now: require "rubygems" require "spec" ARGV << "--format" ARGV << "specdoc" =begin Title: Customer withdraws cash As a customer, I want to withdraw cash from an ATM, so that I don''t have to wait in line at the bank. =end module CustomerWithdrawsCashSpec def should_debit_the_account specify "should debit the account" do end end def should_display_a_rejection_message specify "should display a rejection message" do end end def should_display_an_error_message specify "should display an error message" do end end def should_dispense_cash specify "should dispense cash" do end end def should_not_dispense_cash specify "should not dispense cash" do end end def should_return_the_card specify "should return the card" do end end def should_not_return_the_card specify "should not return the card" do end end end context %{A Withdrawal where an Account is in credit AND the card is valid AND the dispenser contains cash AND the customer requests cash} do extend CustomerWithdrawsCashSpec should_debit_the_account should_dispense_cash should_return_the_card end context %{A Withdrawal where an Account is in credit AND the card is NOT valid AND NOT stolen AND the dispenser contains cash AND the customer requests cash} do extend CustomerWithdrawsCashSpec should_display_a_rejection_message should_not_dispense_cash should_return_the_card end context %{A Withdrawal where an Account is in credit AND the card is NOT valid AND stolen AND the dispenser contains cash AND the customer requests cash} do extend CustomerWithdrawsCashSpec should_display_a_rejection_message should_not_dispense_cash should_not_return_the_card end context %{A Withdrawal where an Account is in credit AND the card is valid AND the dispenser DOES NOT contain cash AND the customer requests cash} do extend CustomerWithdrawsCashSpec should_display_an_error_message should_not_dispense_cash should_return_the_card end context %{A Withdrawal where an Account is overdrawn AND the card is valid AND the customer requests cash} do extend CustomerWithdrawsCashSpec should_display_a_rejection_message should_not_dispense_cash should_return_the_card end And here is the alternative source: require "rubygems" require "spec" ARGV << "--format" ARGV << "specdoc" =begin Title: Customer withdraws cash As a customer, I want to withdraw cash from an ATM, so that I don''t have to wait in line at the bank. =end CustomerWithdrawsCashSpec = context_module do specify "should debit the account" do end specify "should display a rejection message" do end specify "should display an error message" do end specify "should dispense cash" do end specify "should not dispense cash" do end specify "should return the card" do end specify "should not return the card" do end end context %{A Withdrawal where an Account is in credit AND the card is valid AND the dispenser contains cash AND the customer requests cash} do extend CustomerWithdrawsCashSpec specify "should debit the account" specify "should dispense cash" specify "should return the card" end context %{A Withdrawal where an Account is in credit AND the card is NOT valid AND NOT stolen AND the dispenser contains cash AND the customer requests cash} do specify "should display a rejection message", CustomerWithdrawsCashSpec specify "should not dispense cash", CustomerWithdrawsCashSpec specify "should return the card", CustomerWithdrawsCashSpec end context %{A Withdrawal where an Account is in credit AND the card is NOT valid AND stolen AND the dispenser contains cash AND the customer requests cash} do extend customer_withdraws_cash specify "should display a rejection message" specify "should not dispense cash" specify "should not return the card" end context %{A Withdrawal where an Account is in credit AND the card is valid AND the dispenser DOES NOT contain cash AND the customer requests cash} do specify "should display an error message", customer_withdraws_cash specify "should not dispense cash", customer_withdraws_cash specify "should return the card", customer_withdraws_cash end context %{A Withdrawal where an Account is overdrawn AND the card is valid AND the customer requests cash} do extend CustomerWithdrawsCashSpec should_display_a_rejection_message should_not_dispense_cash should_return_the_card end Thanks Brian.> > David > _______________________________________________ > rspec-devel mailing list > rspec-devel at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-devel >-------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/rspec-users/attachments/20061121/199e7d57/attachment.html