On 12/13/07, David Chelimsky <[EMAIL PROTECTED]> wrote: > That said, I'd go for a lesser known feature: custom mock argument > matchers. Something like this (completely off the top of my head and > not tested or guaranteed bug-free - but this will give you the idea): > > class EquivalentMessage > def initialize(message) > @message = message > end > > def ==(other) > other.subject == @message.subject && > other.body == @message.body && > other.sender == @message.sender && > other.recipient == @message.recipient > end > end > > def message_equivalent_to(message) > EquivalentMessage.new(message) > end > > it "should be sent on save" do > msg_creation_parms = { > :subject => "Subj", > :body => "hi", > :sender => people(:rick), > :recipient => people(:john) > } > SantasMailbox.should_receive(:deliver_secret_santa). > with(message_equivalent_to(Message.new(msg_creation_parms))) > Message.create(msg_creation_parms) > end > > Try that out and see what you think.
I like this but, I'm running into a snag or two. When I tried this as-is I'm getting a no method exception in EquivalentMessage#== because it's running into a case where other is :no_args. I put in some tracing and determined that it was also getting other with the right message. So (biting my lip because I don't like class tests I changed this to: def ==(other) Message === other && other.subject == @message.subject && other.body == @message.body && other.sender == @message.sender && other.recipient == @message.recipient end Now it fails with: Spec::Mocks::MockExpectationError in 'Message from anyone should be sent on save' Mock 'Class' expected :deliver_secret_santa with (#<EquivalentMessage:0x3519bec @message=#<Message id: nil, subject: "Subj", body: "hi", sender_id: 343839476, recipient_id: 21341157, message_type: 3, created_at: nil, updated_at: nil>>) once, but received it twice Now I'm interpreting this to mean that 1) the deliver_secret_santa message actually got called at least once with no arguments, hence the :no_args and 2) It got called twice with matching args. As to the second, there's only one call to that method, in the after_create call-back, and it passes the message as an argument. So I put some tracing into the callback to print out a back trace, and it does seem to be called twice, BUT it also seems that the Message.create call IN THE SPEC, is being called twice?!? **** after_create #<Message:0x3385808> /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/callbacks.rb:311:in `call' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/callbacks.rb:311:in `callback' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/callbacks.rb:304:in `each' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/callbacks.rb:304:in `callback' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/callbacks.rb:227:in `create_without_timestamps' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/timestamp.rb:29:in `create' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/base.rb:2165:in `create_or_update_without_callbacks' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/callbacks.rb:213:in `create_or_update' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/base.rb:1899:in `save_without_validation' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/validations.rb:901:in `save_without_transactions' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/transactions.rb:108:in `save' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb:66:in `transaction' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/transactions.rb:80:in `transaction' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/transactions.rb:100:in `transaction' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/transactions.rb:108:in `save' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/transactions.rb:120:in `rollback_active_record_state!' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/transactions.rb:108:in `save' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/base.rb:522:in `create' ./spec/models/message_spec.rb:177 /Users/rick/ssanta/vendor/plugins/rspec/lib/spec/example/example.rb:18:in `instance_eval' /Users/rick/ssanta/vendor/plugins/rspec/lib/spec/example/example.rb:18:in `run_in' /Users/rick/ssanta/vendor/plugins/rspec/lib/spec/matchers.rb:143:in `capture_generated_description' /Users/rick/ssanta/vendor/plugins/rspec/lib/spec/example/example.rb:17:in `run_in' /Users/rick/ssanta/vendor/plugins/rspec/lib/spec/example/example_methods.rb:14:in `execute' /opt/local/lib/ruby/1.8/timeout.rb:48:in `timeout' /Users/rick/ssanta/vendor/plugins/rspec/lib/spec/example/example_methods.rb:11:in `execute' /Users/rick/ssanta/vendor/plugins/rspec/lib/spec/example/example_group_methods.rb:260:in `execute_examples' /Users/rick/ssanta/vendor/plugins/rspec/lib/spec/example/example_group_methods.rb:258:in `each' /Users/rick/ssanta/vendor/plugins/rspec/lib/spec/example/example_group_methods.rb:258:in `execute_examples' /Users/rick/ssanta/vendor/plugins/rspec/lib/spec/example/example_group_methods.rb:115:in `run' /Users/rick/ssanta/vendor/plugins/rspec/lib/spec/runner/example_group_runner.rb:22:in `run' /Users/rick/ssanta/vendor/plugins/rspec/lib/spec/runner/example_group_runner.rb:21:in `each' /Users/rick/ssanta/vendor/plugins/rspec/lib/spec/runner/example_group_runner.rb:21:in `run' /Users/rick/ssanta/vendor/plugins/rspec/lib/spec/runner/options.rb:86:in `run_examples' /Users/rick/ssanta/vendor/plugins/rspec/lib/spec/runner/command_line.rb:19:in `run' /Users/rick/ssanta/vendor/plugins/rspec/bin/spec:3 **** after_create #<Message:0x3385808> /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/callbacks.rb:311:in `call' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/callbacks.rb:311:in `callback' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/callbacks.rb:304:in `each' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/callbacks.rb:304:in `callback' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/callbacks.rb:227:in `create_without_timestamps' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/timestamp.rb:29:in `create' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/base.rb:2165:in `create_or_update_without_callbacks' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/callbacks.rb:213:in `create_or_update' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/base.rb:1899:in `save_without_validation' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/validations.rb:901:in `save_without_transactions' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/transactions.rb:108:in `save' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb:66:in `transaction' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/transactions.rb:80:in `transaction' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/transactions.rb:100:in `transaction' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/transactions.rb:108:in `save' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/transactions.rb:120:in `rollback_active_record_state!' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/transactions.rb:108:in `save' /Users/rick/ssanta/vendor/rails/activerecord/lib/active_record/base.rb:522:in `create' ./spec/models/message_spec.rb:177 /Users/rick/ssanta/vendor/plugins/rspec/lib/spec/example/example.rb:18:in `instance_eval' /Users/rick/ssanta/vendor/plugins/rspec/lib/spec/example/example.rb:18:in `run_in' /Users/rick/ssanta/vendor/plugins/rspec/lib/spec/matchers.rb:143:in `capture_generated_description' /Users/rick/ssanta/vendor/plugins/rspec/lib/spec/example/example.rb:17:in `run_in' /Users/rick/ssanta/vendor/plugins/rspec/lib/spec/example/example_methods.rb:14:in `execute' /opt/local/lib/ruby/1.8/timeout.rb:48:in `timeout' /Users/rick/ssanta/vendor/plugins/rspec/lib/spec/example/example_methods.rb:11:in `execute' /Users/rick/ssanta/vendor/plugins/rspec/lib/spec/example/example_group_methods.rb:260:in `execute_examples' /Users/rick/ssanta/vendor/plugins/rspec/lib/spec/example/example_group_methods.rb:258:in `each' /Users/rick/ssanta/vendor/plugins/rspec/lib/spec/example/example_group_methods.rb:258:in `execute_examples' /Users/rick/ssanta/vendor/plugins/rspec/lib/spec/example/example_group_methods.rb:115:in `run' /Users/rick/ssanta/vendor/plugins/rspec/lib/spec/runner/example_group_runner.rb:22:in `run' /Users/rick/ssanta/vendor/plugins/rspec/lib/spec/runner/example_group_runner.rb:21:in `each' /Users/rick/ssanta/vendor/plugins/rspec/lib/spec/runner/example_group_runner.rb:21:in `run' /Users/rick/ssanta/vendor/plugins/rspec/lib/spec/runner/options.rb:86:in `run_examples' /Users/rick/ssanta/vendor/plugins/rspec/lib/spec/runner/command_line.rb:19:in `run' /Users/rick/ssanta/vendor/plugins/rspec/bin/spec:3 Not sure why this is happening, but it seems to be the rspec machinery that's doing it unless I'm missing something. Here's the complete description from the spec: class EquivalentMessage def initialize(msg) @message = msg end def ==(other) Message === other && other.subject == @message.subject && other.body == @message.body && other.sender == @message.sender && other.recipient == @message.recipient end end def message_equivalent_to(message) EquivalentMessage.new(message) end describe Message, "from anyone" do # t.string :subject # t.text :body # t.integer :from_id # t.integer :to_id # t.integer :type # Normal, FromSecretSanta, ToSecretSanta fixtures :people before(:each) do end it "should be sent on save" do msg_creation_parms = { :subject => "Subj", :body => "hi", :sender => people(:rick), :recipient => people(:john), :message_type => Message::FromSecretSanta } SantasMailbox.should_receive(:deliver_secret_santa).with(message_equivalent_to(Message.new(msg_creation_parms))) Message.create(msg_creation_parms) end end -- Rick DeNatale My blog on Ruby http://talklikeaduck.denhaven2.com/ _______________________________________________ rspec-users mailing list rspec-users@rubyforge.org http://rubyforge.org/mailman/listinfo/rspec-users