Forum: RSpec Cucumber ".should contain(expected) does but fails anyway

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
171ea139761951336b844e708d1547ab?d=identicon&s=25 James Byrne (byrnejb)
on 2009-04-22 16:52
This is the step definition:

When /the xml document should have the Bank of Canada title/ do
  expected = '<title>Bank of Canada: Noon Foreign Exchange
Rates</title>'
  fx_doc = ForexCASource.new(@xchg_source)
  puts fx_doc.xpath('//rdf:RDF/xmlns:channel/xmlns:title')
  fx_doc.xpath('//rdf:RDF/xmlns:channel/xmlns:title').should
contain(expected)
end

When I exercise the feature I see this:

    When the currency exchange retrieval script runs
      #
features/app/models/currency_exchange_rates/step_definitions/currency_exchange_rates_steps.rb:9

<title>Bank of Canada: Noon Foreign Exchange Rates</title> <= from puts

    Then the xml document should have the Bank of Canada title
      #
features/app/models/currency_exchange_rates/step_definitions/currency_exchange_rates_steps.rb:13

      expected the following element's content to include
"<title>Bank of Canada: Noon Foreign Exchange Rates</title>":

      Bank of Canada: Noon Foreign Exchange Rates
(Spec::Expectations::ExpectationNotMetError)
      ./features/app/models/currency_exchange_rates/step_definitions/currency_exchange_rates_steps.rb:17:in
`/the xml document should have the Bank of Canada title/'
      features/app/models/currency_exchange_rates/currency_exchange_rates.feature:10:in
`Then the xml document should have the Bank of Canada title'

1 scenario
1 failed step
2 passed steps

Now, other than the double quotes surrounding the comparison string in
the failure message there is no difference between what I expected and
what was returned.  Nonetheless the specification failed?  What am I
doing wrong?
171ea139761951336b844e708d1547ab?d=identicon&s=25 James Byrne (byrnejb)
on 2009-04-22 17:02
When I change the test to:

  expected = '<title>Bank of Canada: Noon Foreign Exchange
Rates</title>'
  fx_doc.xpath('//rdf:RDF/xmlns:channel/xmlns:title').should =~ expected

Then I see this instead:

  expected: "<title>Bank of Canada: Noon Foreign Exchange
Rates</title>",
       got: <title>Bank of Canada: Noon Foreign Exchange Rates</title>
(using =~)

What is adding the double quotes?
5d38ab152e1e3e219512a9859fcd93af?d=identicon&s=25 David Chelimsky (Guest)
on 2009-04-22 17:17
(Received via mailing list)
On Wed, Apr 22, 2009 at 10:02 AM, James Byrne <lists@ruby-forum.com>
wrote:
> Rates</title>",
>       got: <title>Bank of Canada: Noon Foreign Exchange Rates</title>
> (using =~)
>
> What is adding the double quotes?

Ruby. Try this in irb:

'this'
=> "this"
171ea139761951336b844e708d1547ab?d=identicon&s=25 James Byrne (byrnejb)
on 2009-04-22 18:08
David Chelimsky wrote:

> Ruby. Try this in irb:
>
> 'this'
> => "this"

This passes:

  assert_equal (expected,
                fx_doc.xpath('//rdf:RDF/xmlns:channel/xmlns:title').to_s,
                "#{expected} not found")

This does not:

  fx_doc.xpath('//rdf:RDF/xmlns:channel/xmlns:title').to_s.should \
                contain(expected)

Or this:

  fx_doc.xpath('//rdf:RDF/xmlns:channel/xmlns:title').to_s.should \
                equal(expected)

gives this lovely, and illogical error:

      expected "<title>Bank of Canada: Noon Foreign Exchange
Rates</title>"
           got "<title>Bank of Canada: Noon Foreign Exchange
Rates</title>"

      (compared using equal?)
       (Spec::Expectations::ExpectationNotMetError)

Do not even start on how equal? in Ruby is defined completely at odds
with common usage. I am just pointing out that this type of thing
definitely violates the principal of least surprise.

So, test unit it is.
5d38ab152e1e3e219512a9859fcd93af?d=identicon&s=25 David Chelimsky (Guest)
on 2009-04-22 18:54
(Received via mailing list)
On Wed, Apr 22, 2009 at 11:08 AM, James Byrne <lists@ruby-forum.com>
wrote:
>                fx_doc.xpath('//rdf:RDF/xmlns:channel/xmlns:title').to_s,
>                equal(expected)
>
> Do not even start on how equal? in Ruby is defined completely at odds
> with common usage. I am just pointing out that this type of thing
> definitely violates the principal of least surprise.

Yeah - this is one of those decisions I made early on that I wish I
could take back, but doing so would break a lot of people's specs.
Maybe we should look into changing in it in rspec-2. The original
rspec had should_equal (equivalence) and should_be (object identity).

In the mean time, I'm not sure what better message we can give beyond
"compared using .equal?" without getting into a long treatise on
equality in Ruby, which seems out of place in a failure message.

> So, test unit it is.

The original issue you posted is with the contain matcher, which is in
webrat, not rspec. Why it's not working, I'm not quite sure, but if
you're going to throw out the baby with the bath water, you might
consider figuring out who the parents are :)

Looking at the webrat code for the contain matcher, it uses Nokogiri
under the hood. Not sure what's happening there, but you might try
have_tag instead:

should have_tag("title", "Bank of Canada: Noon Foreign Exchange Rates")

Let me know if it works.

Cheers,
David
171ea139761951336b844e708d1547ab?d=identicon&s=25 James Byrne (byrnejb)
on 2009-04-22 20:45
David Chelimsky wrote:
>
>
> The original issue you posted is with the contain matcher, which is in
> webrat, not rspec. Why it's not working, I'm not quite sure, but if
> you're going to throw out the baby with the bath water, you might
> consider figuring out who the parents are :)
>

Yes, I figured out that #contain was the culprit when I discovered that
this worked:

fx_doc.xpath('//rdf:RDF/xmlns:channel/xmlns:title').to_s.should \
                ==(expected)

Ugly, to me, but it works so the problem is not RSpec.  Strangely,
however, this construct also failed:

fx_doc.xpath('//rdf:RDF/xmlns:channel/xmlns:title').to_s.should \
                =~(expected)

I am not throwing out RSpec or using it any less.  I just had to get
around a specific problem and took the first route I found that worked.

> In the mean time, I'm not sure what better message we can give beyond
> "compared using .equal?" without getting into a long treatise on
> equality in Ruby, which seems out of place in a failure message.

How about:

        expected "<title>Bank of Canada: Noon Foreign Exchange
Rates</title>"
             got "<title>Bank of Canada: Noon Foreign Exchange
Rates</title>"

      (equal?: expected object is not the object returned, did you mean
'==')
       (Spec::Expectations::ExpectationNotMetError)
5d38ab152e1e3e219512a9859fcd93af?d=identicon&s=25 David Chelimsky (Guest)
on 2009-04-22 21:01
(Received via mailing list)
On Wed, Apr 22, 2009 at 1:45 PM, James Byrne <lists@ruby-forum.com>
wrote:
> this worked:
> I am not throwing out RSpec or using it any less.  I just had to get
>             got "<title>Bank of Canada: Noon Foreign Exchange
> Rates</title>"
>
>      (equal?: expected object is not the object returned, did you mean
> '==')
>       (Spec::Expectations::ExpectationNotMetError)

I can live with that. Do you want to make a patch? If not I'll just add
it.
171ea139761951336b844e708d1547ab?d=identicon&s=25 James Byrne (byrnejb)
on 2009-04-22 21:09
David Chelimsky wrote:
> On Wed, Apr 22, 2009 at 1:45 PM, James Byrne <lists@ruby-forum.com>
> wrote:
>> this worked:
>> I am not throwing out RSpec or using it any less. �I just had to get
>> � � � � � � got "<title>Bank of Canada: Noon Foreign Exchange
>> Rates</title>"
>>
>> � � �(equal?: expected object is not the object returned, did you mean
>> '==')
>> � � � (Spec::Expectations::ExpectationNotMetError)
>
> I can live with that. Do you want to make a patch? If not I'll just add
> it.

I'll try and make a patch first.  If that does not work out then I will
beg a boon of you to do it.

I think that the error message should change too. Instead of:

        expected "<title>Bank of Canada: Noon Foreign Exchange
Rates</title>"
             got "<title>Bank of Canada: Noon Foreign Exchange
Rates</title>"

An equal? failure probably should return the metaclass like:

        expected "#<Class:#<String:0x2b6950315300>>"
             got "#<Class:#<String:0x2b695026e898>>"

yada yada....

WDYT?
5d38ab152e1e3e219512a9859fcd93af?d=identicon&s=25 David Chelimsky (Guest)
on 2009-04-22 22:01
(Received via mailing list)
On Wed, Apr 22, 2009 at 2:09 PM, James Byrne <lists@ruby-forum.com>
wrote:
>>> � � � (Spec::Expectations::ExpectationNotMetError)
> Rates</title>"
> WDYT?
I like the idea, though I think it's helpful to also have the strings
in the case of String objects. But having the class and object id
would really help tell the story we're looking for.

wdYt?
171ea139761951336b844e708d1547ab?d=identicon&s=25 James Byrne (byrnejb)
on 2009-04-22 22:22
David Chelimsky wrote:
> On Wed, Apr 22, 2009 at 2:09 PM, James Byrne <lists@ruby-forum.com>
> wrote:
>>>> � � � (Spec::Expectations::ExpectationNotMetError)
>> Rates</title>"
>> WDYT?
> I like the idea, though I think it's helpful to also have the strings
> in the case of String objects. But having the class and object id
> would really help tell the story we're looking for.
>
> wdYt?

After I posted I reconsidered the situation.  When equal? is the
comparison then the first step should be to check for identical objects
(duhh). If that fails then do a supplementary == check. If that passes
then append the ", did you mean '==' notice and display the values
together with the object.metaclass.  Otherwise, just display the objects
are different warning and the object.metaclass for each.

However, on reconsideration again, it seems best to skip the second
check and just display this sort of thing for all equal? failures:

  expected: "#<Class:#<String:0x2b6950315300>> => '<title>Bank of
Canada: Noon Foreign Exchange Rates</title>'"
       got: "#<Class:#<String:0x2b695026e898>> => '<title>Bank of
Canada: Noon Foreign Exchange Rates</title>'"

   (equal?: expected object is not the object returned, did you mean
'==')
   (Spec::Expectations::ExpectationNotMetError)

Of course, to support this outside Rails, RSpec will have to provide and
require the metaclass.rb (shamelessly stolen from Rails).

  unless Object.respond_to? :metaclass do
    class Object
      # Get object's meta (ghost, eigenclass, singleton) class
      def metaclass
        class << self
          self
        end
      end
    end
  end



Thoughts?
171ea139761951336b844e708d1547ab?d=identicon&s=25 James Byrne (byrnejb)
on 2009-04-22 22:35
David Chelimsky wrote:

> I like the idea, though I think it's helpful to also have the strings
> in the case of String objects. But having the class and object id
> would really help tell the story we're looking for.

The relationship between "#<Class:#<String:0x2b22de53e018>>" and the
object's id is rather bizarre.

irb(main):022:0> x.metaclass
=> #<Class:#<String:0x2b22de53e018>>
irb(main):023:0> x.object_id
=> 23714379460620
irb(main):024:0> 0x2b22de53e018.to_s(10)
=> "47428758921240"
irb(main):025:0> 0x2b22de53e018.to_i
=> 47428758921240
irb(main):026:0> 23714379460620 * 2
=> 47428758921240

Obviously an extra bit is getting set somewhere; or unset in #object_id.
3f37c31a4f7c9ae3743b4464dbbd4652?d=identicon&s=25 John Goodsen (Guest)
on 2009-04-23 02:43
(Received via mailing list)
+1.  I like it.

--
John Goodsen                 RADSoft / Better Software Faster
jgoodsen@radsoft.com            Lean/Agile/XP/Scrum Coaching and
Training
http://www.radsoft.com          Ruby on Rails and Java Solutions
171ea139761951336b844e708d1547ab?d=identicon&s=25 James Byrne (byrnejb)
on 2009-04-23 16:27
David Chelimsky wrote:
> On Wed, Apr 22, 2009 at 2:09 PM, James Byrne <lists@ruby-forum.com>
> wrote:
>>>> � � � (Spec::Expectations::ExpectationNotMetError)
>> Rates</title>"
>> WDYT?
> I like the idea, though I think it's helpful to also have the strings
> in the case of String objects. But having the class and object id
> would really help tell the story we're looking for.
>
> wdYt?

I have come up with this spec.  Before I poke at the code itself I would
like you to comment.

      it "should display object and value, expected and actual, on
#failure_message" do
        target = 1
        matcher = equal("1")
        matcher.matches?(target)
        matcher.failure_message_for_should.should == \
          "\n" +
          "expected \"#{matcher.metaclass} => 1\"\n" +
          "     got \"#{target.metaclass} => 1\n" +
          "     \n(compared using equal?, did you mean '==')\n"
      end
171ea139761951336b844e708d1547ab?d=identicon&s=25 James Byrne (byrnejb)
on 2009-04-23 18:08
Another question: Where should metaclass.rb go; lib? lib/spec? or should
the method be put inside the spec_helper file?
5d38ab152e1e3e219512a9859fcd93af?d=identicon&s=25 David Chelimsky (Guest)
on 2009-04-23 18:44
(Received via mailing list)
On Thu, Apr 23, 2009 at 11:08 AM, James Byrne <lists@ruby-forum.com>
wrote:
> Another question: Where should metaclass.rb go; lib? lib/spec? or should
> the method be put inside the spec_helper file?

This is a utility for matchers to give good messages, so I'd put it in
lib/spec/matchers

I don't think we should call it metaclass though, but I'm not sure
what I *do* want to call it. Metaclass != eigenclass, which is what
this really is, so maybe eigenclass.rb - don't let that hang you up
though, I can always change the names after.

Thanks!

David
171ea139761951336b844e708d1547ab?d=identicon&s=25 James Byrne (byrnejb)
on 2009-04-23 20:56
David Chelimsky wrote:
>
>
> I don't think we should call it metaclass though, but I'm not sure
> what I *do* want to call it. Metaclass != eigenclass, which is what
> this really is, so maybe eigenclass.rb - don't let that hang you up
> though, I can always change the names after.
>

The thing is, Rails already defines #metaclass.  So, I thought to check
for that method before extending Object with my own. If
Object.respond_to? :metaclass == true then we are in Rails, or some
other framework that provides the same thing, and so we need not provide
our own.  Otherwise we add it.

Comments?
5d38ab152e1e3e219512a9859fcd93af?d=identicon&s=25 David Chelimsky (Guest)
on 2009-04-23 21:02
(Received via mailing list)
On Thu, Apr 23, 2009 at 1:56 PM, James Byrne <lists@ruby-forum.com>
wrote:
> for that method before extending Object with my own. If
> Object.respond_to? :metaclass == true then we are in Rails, or some
> other framework that provides the same thing, and so we need not provide
> our own.  Otherwise we add it.
>
> Comments?

I'd rather always define our own so the results are consistent from
RSpec regardless of other frameworks in the midst. Does that make
sense to you?
171ea139761951336b844e708d1547ab?d=identicon&s=25 James Byrne (byrnejb)
on 2009-04-23 21:22
David Chelimsky wrote:
> On Thu, Apr 23, 2009 at 1:56 PM, James Byrne <lists@ruby-forum.com>
> wrote:
>> for that method before extending Object with my own. If
>> Object.respond_to? :metaclass == true then we are in Rails, or some
>> other framework that provides the same thing, and so we need not provide
>> our own. �Otherwise we add it.
>>
>> Comments?
>
> I'd rather always define our own so the results are consistent from
> RSpec regardless of other frameworks in the midst. Does that make
> sense to you?

Yes.
171ea139761951336b844e708d1547ab?d=identicon&s=25 James Byrne (byrnejb)
on 2009-04-23 21:26
David Chelimsky wrote:

> I'd rather always define our own so the results are consistent from
> RSpec regardless of other frameworks in the midst. Does that make
> sense to you?

Instead of metaclass how about object_handle ?

wdt?
5d38ab152e1e3e219512a9859fcd93af?d=identicon&s=25 David Chelimsky (Guest)
on 2009-04-23 21:33
(Received via mailing list)
On Thu, Apr 23, 2009 at 2:26 PM, James Byrne <lists@ruby-forum.com>
wrote:
> David Chelimsky wrote:
>
>> I'd rather always define our own so the results are consistent from
>> RSpec regardless of other frameworks in the midst. Does that make
>> sense to you?
>
> Instead of metaclass how about object_handle ?
>
> wdt?

Go for it. I think that's good enough for now. It's for internal
consumption only. Also, I'm better at making naming decisions when I
see things in context, I may change it later if I come up w/ something
that speaks to me more clearly.

Good?
171ea139761951336b844e708d1547ab?d=identicon&s=25 James Byrne (byrnejb)
on 2009-04-23 22:16
David Chelimsky wrote:
> On Thu, Apr 23, 2009 at 2:26 PM, James Byrne <lists@ruby-forum.com>
> wrote:
>> David Chelimsky wrote:
>>
>>> I'd rather always define our own so the results are consistent from
>>> RSpec regardless of other frameworks in the midst. Does that make
>>> sense to you?
>>
>> Instead of metaclass how about object_handle ?
>>
>> wdt?
>
> Go for it. I think that's good enough for now. It's for internal
> consumption only. Also, I'm better at making naming decisions when I
> see things in context, I may change it later if I come up w/ something
> that speaks to me more clearly.
>
> Good?

OK.  I have made the changes to the code in a local branch.  I just need
to stick the object_handle method in the right place and get the revised
specs to pass.  I should have a patch for you tomorrow. If not, then by
Monday.
5d38ab152e1e3e219512a9859fcd93af?d=identicon&s=25 David Chelimsky (Guest)
on 2009-04-23 22:19
(Received via mailing list)
On Thu, Apr 23, 2009 at 3:16 PM, James Byrne <lists@ruby-forum.com>
wrote:
>>>
> to stick the object_handle method in the right place and get the revised
> specs to pass.  I should have a patch for you tomorrow. If not, then by
> Monday.

Cool. I may need to get a release out before the weekend due to other
pressures, so this might not make it until the next release, but that
won't be too far off.

Thanks James,
David
171ea139761951336b844e708d1547ab?d=identicon&s=25 James Byrne (byrnejb)
on 2009-04-23 22:20
David Chelimsky wrote:
> On Thu, Apr 23, 2009 at 3:16 PM, James Byrne <lists@ruby-forum.com>
> wrote:
>>>>
>> to stick the object_handle method in the right place and get the revised
>> specs to pass. �I should have a patch for you tomorrow. If not, then by
>> Monday.
>
> Cool. I may need to get a release out before the weekend due to other
> pressures, so this might not make it until the next release, but that
> won't be too far off.
>
> Thanks James,
> David

NP
5d38ab152e1e3e219512a9859fcd93af?d=identicon&s=25 David Chelimsky (Guest)
on 2009-04-23 22:20
(Received via mailing list)
On Thu, Apr 23, 2009 at 3:17 PM, David Chelimsky <dchelimsky@gmail.com>
wrote:
>>>> Instead of metaclass how about object_handle ?
>> OK.  I have made the changes to the code in a local branch.  I just need
>> to stick the object_handle method in the right place and get the revised
>> specs to pass.  I should have a patch for you tomorrow. If not, then by
>> Monday.
>
> Cool. I may need to get a release out before the weekend due to other
> pressures, so this might not make it until the next release, but that
> won't be too far off.

BTW - FWIW, this is a classic example of how OSS should work. User
gets frustrated. User solves problem through contribution. Thanks for
playing!
171ea139761951336b844e708d1547ab?d=identicon&s=25 James Byrne (byrnejb)
on 2009-04-24 09:54
David Chelimsky wrote:

> BTW - FWIW, this is a classic example of how OSS should work. User
> gets frustrated. User solves problem through contribution. Thanks for
> playing!

Patch is on Lighthouse.

https://rspec.lighthouseapp.com/projects/5645-rspe...

I did this on my laptop so some of the file modes are whacked (775 vice
664).  It seems that I am not the first to encounter this since I found
other library files in the repository that have mode 775.  Nonetheless,
you may wish to tidy this situation up.
39100495c9937c39b2e0c704444e1b4a?d=identicon&s=25 Pat Maddox (Guest)
on 2009-04-24 18:14
(Received via mailing list)
On Wed, Apr 22, 2009 at 12:18 PM, David Chelimsky <dchelimsky@gmail.com>
wrote:
>>>> '==')
>>        expected "<title>Bank of Canada: Noon Foreign Exchange
>>
>> WDYT?
>
> I like the idea, though I think it's helpful to also have the strings
> in the case of String objects. But having the class and object id
> would really help tell the story we're looking for.
>
> wdYt?

I like this idea.  Maybe you show the object id and a truncated string.
i.e.

expected "#<String:0x2b6950315300> (Four score and seven years...)"
            got "#<String:0x2b695026e898> (Four score and seven
years...)"
using equal?

So it's clear that they're different objects, and you get a bit of
context to figure out which string it's referring to.

Pat
171ea139761951336b844e708d1547ab?d=identicon&s=25 James Byrne (byrnejb)
on 2009-04-24 19:10
James Byrne wrote:

>
> Patch is on Lighthouse.
>
> https://rspec.lighthouseapp.com/projects/5645-rspe...
>

Besides Fixnum, are there any other Ruby Class Objects that do not have
a virtual class?
This topic is locked and can not be replied to.