Forum: RSpec Cucumber - step negating another expecting step

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.
8a2de74362a8ee5f9c5e86b1ba0b1640?d=identicon&s=25 Joaquin Rivera Padron (Guest)
on 2009-04-16 12:14
(Received via mailing list)
hey there,
this here may be a little too general, and maybe is only a though
sharing,
but would be nice to hear what you think.

What is your opinion about expectation steps that negates another
expectation step?

for example: let's say I have a step that specs something:

Then /^I should see the people search form$/ do
    response.should have_tag('form#search')
    # this of course could get more complex, like several expectations
in a
row or so
end

then I would like to reuse the step but negating it, like:

Then /^I should not see the people search form$/ do
  !(Then "I should see the people search form")
end

this wont work because spectations (or some of them) of the first step
will
fail.  A low level implementation of this could be something like:

Then /^I should (.*) see the people search form$/ do |bool|
    post_fix = "_#{bool}" if bool
    # allow the incompleteness of this line, but you get the idea :-)
    # it'll send should or should_not
    response.send("should#{postfix}", have_tag('form#search') )
end

but here there are considerations regarding unreadability of the step,
but
anyway the question again:

would this be too bad? too problematic? what do you think about
expectation
steps negating another expectation steps?

cheers
joaquin
8a2de74362a8ee5f9c5e86b1ba0b1640?d=identicon&s=25 Joaquin Rivera Padron (Guest)
on 2009-04-16 12:26
(Received via mailing list)
at the moment I do it this way, hiding the complexity out of the steps:

Then /^I should see the people search form$/ do
  people_search_form_exists
end

Then /^I should not see the people search form$/ do
  people_search_form_exists "not"
end

and then the method:

def people_search_form_exists negation = ""
  neg = "_not" unless negation.blank?
  response.send "should#{neg}".to_sym, have_tag('form#frmSearch')
end

this is a simple case, but what do you think about this? any blog post
or so

cheers
joaquin
Cdf378de2284d8acf137122e541caa28?d=identicon&s=25 Matt Wynne (mattwynne)
on 2009-04-16 14:03
(Received via mailing list)
On 16 Apr 2009, at 11:22, Joaquin Rivera Padron wrote:

>
> and then the method:
>
> def people_search_form_exists negation = ""
>   neg = "_not" unless negation.blank?
>   response.send "should#{neg}".to_sym, have_tag('form#frmSearch')
> end
>
> this is a simple case, but what do you think about this? any blog
> post or so

Yeah this is an annoying one isn't it. I sometimes get around it by
going old-skool and pulling out the Test::Unit assertion methods
instead:

     Then /^I (should|should not) see the people search form$/ do |
maybe|
       has_matching_tags = current_dom.css('form#frmSearch').length > 0
       assert has_matching_tags == (maybe == "should")
     end

I think that would work. It's shorter, but is it much easier to
understand?

Matt Wynne
http://blog.mattwynne.net
http://www.songkick.com
8a2de74362a8ee5f9c5e86b1ba0b1640?d=identicon&s=25 Joaquin Rivera Padron (Guest)
on 2009-04-16 15:14
(Received via mailing list)
thanks matt,
yes, the regexp in the step matcher is a good one to dry it up

So I end up with this one:

Then /^I (should|should not) see the people search form$/ do |maybe|
  people_search_form_should_exist maybe == "should"
end

and the method:

def people_search_form_should_exist it_should_exist
  _not = "_not" unless it_should_exist

  response.send "should#{_not}".to_sym, have_tag('form#frmSearch')
end

only because I find it easier to read (when I don't need to jump to the
method), but yours maybe faster (shorter it is), I could come back to it
later and benchmark both

thanks again,
joaquin
Cdf378de2284d8acf137122e541caa28?d=identicon&s=25 Matt Wynne (mattwynne)
on 2009-04-16 17:49
(Received via mailing list)
On 16 Apr 2009, at 14:06, Joaquin Rivera Padron wrote:

>
> def people_search_form_should_exist it_should_exist
>   _not = "_not" unless it_should_exist
>
>   response.send "should#{_not}".to_sym, have_tag('form#frmSearch')
> end
>
> only because I find it easier to read (when I don't need to jump to
> the method), but yours maybe faster (shorter it is), I could come
> back to it later and benchmark both

If you don't mind using the #send (I was trying to help you get rid of
it) then just do this:

Then /^I (should|should not) see the people search form$/ do |maybe|
   response.send maybe.underscore.to_sym, have_tag('form#frmSearch')
end


> thanks again,
> joaquin
> _______________________________________________
> rspec-users mailing list
> rspec-users@rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users

Matt Wynne
http://blog.mattwynne.net
http://www.songkick.com
8a2de74362a8ee5f9c5e86b1ba0b1640?d=identicon&s=25 Joaquin Rivera Padron (Guest)
on 2009-04-16 18:15
(Received via mailing list)
wow! even shorter :-)

2009/4/16 Matt Wynne <matt@mattwynne.net>
54568ee7ba0c78a836e84c8756a3d681?d=identicon&s=25 Lenny Marks (Guest)
on 2009-04-17 16:27
(Received via mailing list)
I've been doing something similar. I think the benefit of having half
the steps(each can be negated) wins over the small impact it has on
step readability. Personally I started adding stuff like this(perhaps
not as DRY but simple enough):

Then /^the correspondence should (not )?have inclusions$/ do |negate|
   if negate
     @outcorr.inclusions.should be_empty
   else
     @outcorr.inclusions.should_not be_empty
   end
end

-lenny
C6ce9a98479a04c47d143d444ae317c6?d=identicon&s=25 Kero van Gelder (Guest)
on 2009-04-18 11:28
(Received via mailing list)
>   end
> end

What's the advantage of having half the steps?
They should be grouped in a nice way in files anyway.

This one's quite readable, though.

>> yes, the regexp in the step matcher is a good one to dry it up
>>
>> So I end up with this one:
>>
>> Then /^I (should|should not) see the people search form$/ do |maybe|
>>  people_search_form_should_exist maybe == "should"
>> end

should ... exist ...  maybe... should

Unreadable?

>> and the method:
>>
>> def people_search_form_should_exist it_should_exist
>>  _not = "_not" unless it_should_exist
>>
>>  response.send "should#{_not}".to_sym, have_tag('form#frmSearch')
>> end

Convoluted.

>> end
If you go with this kind of abstraction, this solution and the topmost
in this mail at least do not introduce extra methods to deal with the
should/should not. more methods to have fewer steps can not be an
advantage,
I think.

But the readbility of

  Then /^I should see the people search form$/ do
    response.should have_tag('form#peopleSearch')
  end

  Then /^I should not see the people search form$/ do
    response.should_not have_tag('form#peopleSearch')
  end

is higher for me, as I only need to think what the have_tag means,
but do not have to parse the should/not, send, underscore and to_sym.

The difference in readability is from about 2 seconds to at least
10 seconds. That's a disadvantage that I'm not willing to pay for
any advantage of having "fewer steps".

Bye,
Kero.
___
How can I change the world if I can't even change myself?
  -- Faithless, Salva Mea
59581f5e40f8e5ffeb75dbd7a68e2419?d=identicon&s=25 Mark Anderson (Guest)
on 2009-04-22 07:47
(Received via mailing list)
> >   end
> > end
>
> What's the advantage of having half the steps?
> They should be grouped in a nice way in files anyway.
>
> This one's quite readable, though.

[snip]

>   end
> any advantage of having "fewer steps".
I use the first method for negating steps - when I need it.  The
advantage
is DRY ("Don't Repeat Yourself").  While your method - having two
separate
step matchers - may be a little easier to comprehend, my worry would be
maintainability.  If another user (perhaps just future-me) comes along
and
adds another step matcher between those two without noticing that they
negate each other, and then a third user (perhaps future-future-me)
comes
along and changes one step matcher but not the other, we no longer truly
have negation.

There is definitely a balancing act.  Hopefully future-me is less likely
to
change one branch of my negating step matcher without mirroring the
change
in the other half, it is even less likely in some of the one-line
solutions
that are more difficult to quickly comprehend.

If you value comprehension and are confident that you'll remember to
update
both cases together, then your solution is ideal.  If you value
idiot-proofing and don't mind slower comprehension, then a one-line
solution
may be ideal.  I worry about everything and therefore take the middle of
the
road solution.

          /\/\ark


__________ Information from ESET NOD32 Antivirus, version of virus
signature
database 4022 (20090420) __________

The message was checked by ESET NOD32 Antivirus.

http://www.eset.com
0be0e4aa42aacd9a8a95c792de273ca7?d=identicon&s=25 Aslak Hellesøy (aslakhellesoy)
on 2009-04-22 08:19
(Received via mailing list)
2009/4/17 Lenny Marks <lenny@aps.org>

> end
>

Thanks Lenny. You get it. Readability trumps obsessive DRYness.
Corollary: The value of DRYness diminishes with distance.
5dade05c7d95ee88f2d6d8970bb2071e?d=identicon&s=25 Jeff Talbot (Guest)
on 2009-04-22 16:06
(Received via mailing list)
On Wed, Apr 22, 2009 at 1:17 AM, aslak hellesoy
<aslak.hellesoy@gmail.com>wrote:

>>     @outcorr.inclusions.should be_empty
>>   else
>>     @outcorr.inclusions.should_not be_empty
>>   end
>> end
>>
>
> Thanks Lenny. You get it. Readability trumps obsessive DRYness.
> Corollary: The value of DRYness diminishes with distance.
>
>>

This is just a thought, but every solution on this thread, including
this
one, indicates to me that something is amiss.

I don't recall ever seeing a "Then" step without a "should" or "should
not"
(I've only come across steps in English so far). To me, this means
there's
something special about "Then" steps, and quite possibly the "should" /
"should not" aspect of it should be built into the cucumber grammar.

I'll be the first one to agree that cucumber steps are not the place to
get
cute, and that readability is paramount, but seriously, shouldn't you be
able to negate the core expectation of a step without having to write
extra
code?

Jeff
8a2de74362a8ee5f9c5e86b1ba0b1640?d=identicon&s=25 Joaquin Rivera Padron (Guest)
on 2009-04-22 16:18
(Received via mailing list)
well, that was the vague idea I had when asking at first, but I don't
think
every multi-should or should_not step can be in general negated,

by the way, Lenny's one have come to be my preferred solution

joaquin
0be0e4aa42aacd9a8a95c792de273ca7?d=identicon&s=25 Aslak Hellesøy (aslakhellesoy)
on 2009-04-22 17:38
(Received via mailing list)
On Wed, Apr 22, 2009 at 3:51 PM, Jeff Talbot
<jeff.a.talbot@gmail.com>wrote:

>>> but simple enough):
>> Corollary: The value of DRYness diminishes with distance.
>
> I'll be the first one to agree that cucumber steps are not the place to get
> cute, and that readability is paramount, but seriously, shouldn't you be
> able to negate the core expectation of a step without having to write extra
> code?
>

It's an interesting idea. Could you give an example of how you'd like it
to
look? How would you like to use this? A step definition example would be
great.

Aslak
8a2de74362a8ee5f9c5e86b1ba0b1640?d=identicon&s=25 Joaquin Rivera Padron (Guest)
on 2009-04-23 00:51
(Received via mailing list)
ok, let's say:

Then /should see "(.+)"/ do |text|
   # a binary step, easily negable
end

Then /I deny some steps/ do
  # really not so readable
  Not Then "should see \"your are not log in\""

  Then "some other step that holds"

  # another way of saying it bad
  But Not Then "should receive info for non users"

  # or maybe this bad
  And Not Then "should receive info for non users"
end

now comes the mars attack part, I haven't dig into cucumber or rspec
code
that much, only guessing here.
and Not could do something like receiving the step that comes behind the
keyword

def Not(step)
    # we tell the step to assert (I mean the rspec synonym) itself
    # so that it raises some RSpec exception
    step.assert!
    # the step really passed, we should raise an Exception not
rescueable
for the next rescue
    raise Spec::UncatchableException
    rescue Spec::Expectations # or something like that
        # green, nothing, this is what we expected
    end
end

is this doable? I have to say I have not come to need this that bad to
ask
the cucumber to provide it

is really late and this cross my mind :-)

joaquin
0be0e4aa42aacd9a8a95c792de273ca7?d=identicon&s=25 Aslak Hellesøy (aslakhellesoy)
on 2009-04-23 08:04
(Received via mailing list)
On Thu, Apr 23, 2009 at 12:34 AM, Joaquin Rivera Padron
<joahking@gmail.com>wrote:

>   Then "some other step that holds"
> and Not could do something like receiving the step that comes behind the
>         # green, nothing, this is what we expected
>     end
> end
>
> is this doable? I have to say I have not come to need this that bad to ask
> the cucumber to provide it
>

Only if you have exactly one thing that can be negated. If you have
several
things, this won't work.

Frankly, I don't think I'll ever implement a cute feature in Cucumber
that
allows you to have out of the box negation. It would be ugly no matter
how
it's done, and it would only save you a line or 2 of code.

Aslak
3f37c31a4f7c9ae3743b4464dbbd4652?d=identicon&s=25 John Goodsen (Guest)
on 2009-04-23 11:04
(Received via mailing list)
On Thu, Apr 23, 2009 at 1:53 AM, aslak hellesoy
<aslak.hellesoy@gmail.com>wrote:

>
>
> Frankly, I don't think I'll ever implement a cute feature in Cucumber that
> allows you to have out of the box negation. It would be ugly no matter how
> it's done, and it would only save you a line or 2 of code.
>

fwiw, +1 on that.  refactor to a descriptive method and get used to
refactoring cucumber implementations to keep the cukes dry.  moist cukes
get
moldy - my grams taught me that.
8a2de74362a8ee5f9c5e86b1ba0b1640?d=identicon&s=25 Joaquin Rivera Padron (Guest)
on 2009-04-23 12:27
(Received via mailing list)
>
> Frankly, I don't think I'll ever implement a cute feature in Cucumber that
>> allows you to have out of the box negation. It would be ugly no matter how
>> it's done, and it would only save you a line or 2 of code.
>>
>
> fwiw, +1 on that.  refactor to a descriptive method and get used to
> refactoring cucumber implementations to keep the cukes dry.  moist cukes get
> moldy - my grams taught me that.
>

totally agree
5d38ab152e1e3e219512a9859fcd93af?d=identicon&s=25 David Chelimsky (Guest)
on 2009-04-23 15:58
(Received via mailing list)
On Thu, Apr 16, 2009 at 10:35 AM, Matt Wynne <matt@mattwynne.net> wrote:
>> end
>> method), but yours maybe faster (shorter it is), I could come back to it
>> later and benchmark both
>
> If you don't mind using the #send (I was trying to help you get rid of it)
> then just do this:
>
> Then /^I (should|should not) see the people search form$/ do |maybe|
>  response.send maybe.underscore.to_sym, have_tag('form#frmSearch')
> end

I'm definitely on the "clarity trumps DRY" side of the fence here. But
that doesn't deny that there is a problem to solve. This solution gets
close but is still takes me some extra time to grok. What extracting
that to a method like this:

Then /^I (should|should not) see the people search form$/ do
|should_or_should_not|
  expect_that(response, should_or_should_not,
have_tag('form#frmSearch'))
end

def expect_that(target, should_or_should_not, matcher)
  target.send should_or_should_not.underscore.to_sym, matcher
end

I definitely don't see this in Cucumber, BTW as "should" and "should
not" are not the only way to express positive and negative
expectations even in English, let alone other languages that might not
deal w/ negation in such clean and consistent ways.

And it's not the least number of characters you can type. But it's
grok-able IMO. And DRY. And cute, to boot.

Of course, if anybody can come up with one word other than "maybe"
(damn you Ben Mabey for f'ing up my ability to type that word) to
express should_or_should_not more succinctly, that might help reduce
the typing. "Maybe" doesn't work for me because it implies lack of
precision rather than choice (to me).

Don't know how helpful this is, but it's fun to explore.

David
5dade05c7d95ee88f2d6d8970bb2071e?d=identicon&s=25 Jeff Talbot (Guest)
on 2009-04-23 17:37
(Received via mailing list)
> I definitely don't see this in Cucumber, BTW as "should" and "should
> not" are not the only way to express positive and negative
> expectations even in English, let alone other languages that might not
> deal w/ negation in such clean and consistent ways.
>


Yeah, I went down a similar line of thinking that went as far as
splitting
Then's into 2 steps like so:

Then /^I/ do...
Should /^see the people search form/ do

Where the former returns the target object and the latter returns the
matcher.

An interesting concept, but it definitely doesn't fit with Cucumber as
we
know it today.

Jeff
C694a032be7518a0d704318895f8fe1d?d=identicon&s=25 Ben Mabey (mabes)
on 2009-04-23 18:37
(Received via mailing list)
David Chelimsky wrote:
>>> Then /^I (should|should not) see the people search form$/ do |maybe|
>>>
>>
>
> grok-able IMO. And DRY. And cute, to boot.
>
> Of course, if anybody can come up with one word other than "maybe"
> (damn you Ben Mabey for f'ing up my ability to type that word) to
>

LOL... I seem to have that effect on people. :)  But, think how I feel.
Do you know how many "witty" people I have met who tell some "maybe"
joke and think they are the first person to ever make it?  Well, I can
tell you that it does, in fact, get very old. :)
> express should_or_should_not more succinctly, that might help reduce
> the typing. "Maybe" doesn't work for me because it implies lack of
> precision rather than choice (to me).
>

Back on topic...  I like this proposal the best.  Having the
"should_or_should_not" makes it very clear what is happening.  To reduce
typing I suppose you could call it "expectation" in the step
definition... and you could possibly even abbrevaite that more.  But I
wold probably stick with the more verbose "should_or_should_not".  I
also agree that this is something that shouldn't be part of Cucumber
itself but I'll probably play around with it in my own projects.

-Ben *Mabey*
5d38ab152e1e3e219512a9859fcd93af?d=identicon&s=25 David Chelimsky (Guest)
on 2009-04-23 18:41
(Received via mailing list)
On Thu, Apr 23, 2009 at 9:39 AM, Ben Mabey <ben@benmabey.com> wrote:
>>>> yes, the regexp in the step matcher is a good one to dry it up
>>>>  _not = "_not" unless it_should_exist
>>> it)
>> that to a method like this:
>> I definitely don't see this in Cucumber, BTW as "should" and "should
>
> Back on topic...  I like this proposal the best.  Having the
>  "should_or_should_not" makes it very clear what is happening.  To reduce
> typing I suppose you could call it "expectation" in the step definition...
> and you could possibly even abbrevaite that more.

e9n ???
s18t ???
This topic is locked and can not be replied to.