Can I do foo.should (be_nil || be_empty) in rspec


#1

Is there any way to do

foo.should (be_nil || be_empty)

in rspec.

Thanks in advance


#2

On 4 Nov 2008, at 11:10, Andrew P. wrote:

Is there any way to do
foo.should (be_nil || be_empty)
in rspec.

“foo.should be_blank” would work if you’re using Rails (i.e.
ActiveSupport is loaded).

Cheers,
-Tom


#3

On 4 Nov 2008, at 11:10, Andrew P. wrote:

Is there any way to do

foo.should (be_nil || be_empty)

in rspec.

That won’t do what you want it to, at first glance it will always
match with be_nil. You could write a custom matcher
(be_nil_or_empty), but I suspect that’s not the real answer here.

Why do you want to do this? What is the distinction between nil and
empty in your app? I suspect this is a data modelling issue rather
than a spec issue. (Be very wary as soon as you see conditionals in
your code.)

Ashley


http://www.patchspace.co.uk/


#4

Sweet I’m using rails so will give it a go. Any ideas about the general
case, is making a custom matcher the (only) way to go?
All best

Andrew

2008/11/4 Tom S. removed_email_address@domain.invalid


#5

On 4 Nov 2008, at 11:26, Andrew P. wrote:

Any ideas about the general case, is making a custom matcher the
(only) way to go?

Can you give an example of what you’re doing, or think you might do?
Until I saw Tom’s reply it never occurred to me that you might be
dealing with strings (I thought you were doing something with an array
or other collection.)

Ashley


http://www.patchspace.co.uk/


#6

General case I’m thinking about is just testing that something should be
one
thing or another
e.g x.should be(foo || bar)

Haven’t got a specific example at the moment apart from the blank one.
What
I’m thinking about is the syntax to say this in a spec, as I think there
must be lots of times when having this sort of syntax would be useful.

All best

Andrew

2008/11/4 Ashley M. removed_email_address@domain.invalid


#7

On 4 Nov 2008, at 12:45, Andrew P. wrote:

General case I’m thinking about is just testing that something
should be one thing or another

e.g x.should be(foo || bar)

Haven’t got a specific example at the moment apart from the blank
one. What I’m thinking about is the syntax to say this in a spec,
as I think there must be lots of times when having this sort of
syntax would be useful.

Hi Andrew

I suspect that in general the concept of an object O being (foo ||
bar) actually means there’s a rule that makes your object baz
instead. The reason is that if you spec foo and bar independently,
you double the number of contexts for objects that depend on O.

So this might not look to bad:

describe MyObject do
before(:each) do
@o = MyObject.new
end

 it "should be foo or bar" do
   @o.should be_foo_or_bar
 end

end

but it means everywhere else you’re forced to duplicate that logic, eg:

describe MyOtherObject do
describe “when its MyObject is foo” do
before(:each) do
o = mock(MyObject, :foo => true, :bar => false)
@oo = MyOtherObject.new(o)
end
it “should be faz” do
@oo.should be_faz
end
end

 describe "when its MyObject is bar" do
   before(:each) do
     o = mock(MyObject, :foo => false, :bar => true)
     @oo = MyOtherObject.new(o)
   end
   it "should be faz" do
     @oo.should be_faz
   end
 end

 describe "when its MyObject is neither foo nor bar" do
   before(:each) do
     o = mock(MyObject, :foo => false, :bar => false)
     @oo = MyOtherObject.new(o)
   end
   it "should not be faz" do
     @oo.should_not be_faz
   end
 end

end

instead of just:

describe MyOtherObject do
describe “when its MyObject is baz” do
before(:each) do
o = mock(MyObject, :baz => true)
@oo = MyOtherObject.new(o)
end
it “should be faz” do
@oo.should be_faz
end
end

 describe "when its MyObject is not baz" do
   before(:each) do
     o = mock(MyObject, :baz => false)
     @oo = MyOtherObject.new(o)
   end
   it "should not be faz" do
     @oo.should_not be_faz
   end
 end

end

s/foo/nil/
s/bar/empty/
s/baz/blank/

This make sense? Sorry if it’s a bit abstract, or has typos. I
didn’t actually run that code, of course…

I think in summary, two branches in your specs => you are violating
Tell Don’t Ask (somewhere else) in your code.

Ashley


http://www.patchspace.co.uk/


#8

Ashley,
Thanks for your time on this, the reply does make sense, and I can see
from
an OO point of view that any particular object being (foo||bar) is
equivalent to that object being baz. However with the dynamic nature of
ruby
we often don’t know what object we are going to be dealing with in our
tests/specs. Whilst a unit test will generally (always?) be aimed at a
particular type, when implementing a plain text feature/story we are
often
working at a much higher level. In these cases the (foo || bar)
construct
could mean different types and a baz might not exist or be particularly
easy
to represent or formulate.

I can see that wanting this construct, could indicate a smell maybe a
badly
worded story - i.e. a conjunction step.

All best

Andrew

2008/11/4 Ashley M. removed_email_address@domain.invalid


#9

“Andrew P.” removed_email_address@domain.invalid writes:

General case I’m thinking about is just testing that something should be one thing or another

e.g x.should be(foo || bar)

Haven’t got a specific example at the moment apart from the blank one. What I’m thinking about is the syntax to say this in a spec, as I
think there must be lots of times when having this sort of syntax would be useful.

Hi,

This is a case where a custom matcher would be hiding a concept that
belongs directly in your code. If you really don’t care about the
difference between empty and nil, you should create a method - such as
#blank? - that handles that for you.

Pat


#10

On Tue, Nov 4, 2008 at 11:36 AM, Andrew P. removed_email_address@domain.invalid
wrote:

Ok I see. I was approaching this more from the syntax that my stories can
express rather than what my code does. However from these replies and a
re-read of the cucumber wiki I can see that any step that requires the
(foo||bar) construct is by definition a conjunction and can be broken into
smaller steps.
However we only have ‘And’ available in stories, do we need ‘Or’?

What is your scenario that you are thinking of using an “or” ? This
may be helpful, otherwise we’re going to speculating about the
theoretical use cases. I’d rather focus on your specific use case. :slight_smile:


Zach D.
http://www.continuousthinking.com
http://www.mutuallyhuman.com


#11

Ok I see. I was approaching this more from the syntax that my stories
can
express rather than what my code does. However from these replies and a
re-read of the cucumber wiki I can see that any step that requires the
(foo||bar) construct is by definition a conjunction and can be broken
into
smaller steps.
However we only have ‘And’ available in stories, do we need ‘Or’?

All best

Andrew

2008/11/4 Pat M. removed_email_address@domain.invalid


#12

Oh I was definitely into theoretical speculation here :slight_smile: - haven’t got a
particular case at the moment

2008/11/4 Zach D. removed_email_address@domain.invalid


#13

On Tue, Nov 4, 2008 at 9:29 AM, Pat M. removed_email_address@domain.invalid wrote:

This is a case where a custom matcher would be hiding a concept that
belongs directly in your code. If you really don’t care about the
difference between empty and nil, you should create a method - such as
#blank? - that handles that for you.

In which case you would get be_blank for free, in case you weren’t
aware.

FYI - if you REALLY want to match against either, it’s pretty easy to
do w/ simple matcher:

def be_nil_or_empty
simple_matcher “nil? or empty? to return true” do |actual|
actual.nil? || actual.empty?
end
end

Cheers,
David


#14

On Nov 04, 2008, at 5:07 pm, David C. wrote:

FYI - if you REALLY want to match against either, it’s pretty easy to
do w/ simple matcher:

def be_nil_or_empty
simple_matcher “nil? or empty? to return true” do |actual|
actual.nil? || actual.empty?
end
end

Wow, I completely forgot about simple_matcher. That REALLY deserves a
more prominent place in the docs! It’s a great feature.

Would be really cool if you could do it like this though:

simple_matcher :be_nil_or_empty, “nil? or empty? to return true” do |
actual|
actual.nil? || actual.empty?
end

and have it call define_method for you.

That’s one I could hopefully do myself in time, after I’ve got a few
Merb/DataMapper jobs out of the way.

WYDAT? Worth filing a ticket for?

Ashley


http://www.patchspace.co.uk/


#15

On Tue, Nov 4, 2008 at 1:14 PM, Ashley M.
removed_email_address@domain.invalid wrote:

end
end

and have it call define_method for you.

That’s one I could hopefully do myself in time, after I’ve got a few
Merb/DataMapper jobs out of the way.

WYDAT? Worth filing a ticket for?

If you can do it w/o breaking existing behaviour, sure.

Alternatively, you could add a new method:

def_matcher

or something like that.

Either way, it would be totally worth it.


#16

On Tue, Nov 4, 2008 at 2:14 PM, Ashley M.
removed_email_address@domain.invalid wrote:

end
end

and have it call define_method for you.

That’s one I could hopefully do myself in time, after I’ve got a few
Merb/DataMapper jobs out of the way.

WYDAT? Worth filing a ticket for?

There are a few obstacles that it would have to overcome. As-is I
don’t think that will work. If you file a ticket I’ll comment there as
to why I think that. :slight_smile:


Zach D.
http://www.continuousthinking.com
http://www.mutuallyhuman.com


#17

“David C.” removed_email_address@domain.invalid writes:

Alternatively, you could add a new method:

def_matcher

I dig this.

Pat


#18

On Tue, Nov 4, 2008 at 1:47 PM, Pat M. removed_email_address@domain.invalid wrote:

“David C.” removed_email_address@domain.invalid writes:

Alternatively, you could add a new method:

def_matcher

I dig this.

FYI - I was talking off-line (on line, really, but outside this list)
to wycats and he’s got some matcher stuff in merb that I, shamefully,
have yet to check out in detail. It’d be good to peak at that and see
if it makes sense to bring it into rspec, or maybe release it as a
plugin/extension.


#19

On Nov 04, 2008, at 7:24 pm, Zach D. wrote:

There are a few obstacles that it would have to overcome. As-is I
don’t think that will work. If you file a ticket I’ll comment there as
to why I think that. :slight_smile:

I’ve filed a ticket[1]. Unleash your scepticism, Zach! :slight_smile:

Ashley

[1]
http://rspec.lighthouseapp.com/projects/5645-rspec/tickets/592-improve-simple_matcher


http://www.patchspace.co.uk/