`ELSE` support for `Run Keyword If` and implicit user keyword return values

9,569 views
Skip to first unread message

Pekka Klärck

unread,
Sep 3, 2012, 7:36:08 AM9/3/12
to robotframework-users
Hi all,

Last week a client of mine asked could he simplify a user keyword that
looked more or less like this:

Do Something
[Arguments] ${arg}
${temp1} = Run Keyword If "${arg}" == "xxx"
... Some Keyword arg1 arg2
${temp2} = Run Keyword Unless "${arg}" == "xxx"
... Another Keyword another arg
${return} = Set Variable If "${arg}" == "xxx"
... ${temp1} ${temp2}
[Return] ${return}

Basically the above keyword executes either `Some Keyword` or `Another
Keyword`, depending on the value of `${arg}`, and returns the results
of the executed keyword. Pretty simple task but unfortunately complex
in Robot Framework test data.

My first reaction how to simplify this was moving the logic into a
custom test library. Although that is often the best solution,
especially if the needed logic grows more complex, it may not always
be that easy. The biggest problem is that if keywords to be executed
are themselves user keywords, executing them from Python isn't
possible directly. Moving from Robot test data to "real" programming
may also be a quite big jump for people without much "real"
programming experience.

Because of the explained drawbacks in moving the logic to a test
library, I started to think could we make it possible to simplify the
above keyword otherwise. After pondering this a little, I believe that
implementing following two enhancements would be a good idea. I'm very
interested to hear your opinions too, but please read this mail to the
end first.

1) `ELSE` support for `Run Keyword If`.

Creating if/else construct using `Run Keyword If/Run Keyword Unless`
works pretty well if you only want to execute certain keywords, but
gets pretty complicated if you are interested in the return values. As
the above example demonstrates, you need to add one more `Set Variable
If` into the equation to make that work. If, on the other hand, `Run
Keyword If` would support `ELSE`, you would only run one keyword get
one return value. I assume it's not only me who thinks that the below
example quite a bit simpler than the original.

Do Something
[Arguments] ${arg}
${return} = Run Keyword If "${arg}" == "xxx"
... Some Keyword arg1 arg2
... ELSE
... Another Keyword another arg
[Return] ${return}

Notice that the else "branch" is denoted with capital `ELSE`. I chose
that because I wanted it to stand out and also be less likely to clash
with arguments passed to `Some Keyword`. It is obviously still
possible that someone is nowadays passing `ELSE` as an argument to a
keyword used with `Run Keyword If`, but I think that is pretty
unlikely. It is also easy to escape this string like `\ELSE` if you
actually want to use the literal value. This change would,
nevertheless, be at least potentially backwards incompatible.

2) Implicit user keyword return values.

Returning a value from a keyword only to use it with `[Return]` is a
bit boring. Robot could easily behave like e.g. Ruby and return the
return value of the last executed keyword if no explicit return value
is specified. That would simplify our example still a little bit more:

Do Something
[Arguments] ${arg}
Run Keyword If "${arg}" == "xxx"
... Some Keyword arg1 arg2
... ELSE
... Another Keyword another arg

I can see someone arguing that the previous example was more explicit
than the last one, but they could keep using `[Return]`. A nice thing
about this enhancement is that it ought to be fully
backwards-compatible.

----------------

What do you think about these two enhancements? Should we implement
them? Should they be includes already to RF 2.7.4 that is otherwise
pretty much ready? I've already prototyped both of them and know that
implementing them is very easy.

Cheers,
.peke
--
Agile Tester/Developer/Consultant :: http://eliga.fi
Lead Developer of Robot Framework :: http://robotframework.org

Janne Kohvakka

unread,
Sep 3, 2012, 8:26:18 AM9/3/12
to pe...@iki.fi, robotframework-users
Hi,

Although we could get rid of the Run keyword if structure altogether in our particular case, I would like to get ELSE supported in the future to avoid extra hassle with setting the return value into a variable.

You can make the return value implicit if you like. I like the more explicit version =).

-janne

2012/9/3 Pekka Klärck <pe...@iki.fi>
--
You received this message because you are subscribed to the Google Groups "robotframework-users" group.
To post to this group, send email to robotframe...@googlegroups.com.
To unsubscribe from this group, send email to robotframework-u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/robotframework-users?hl=en.


Tatu aalto

unread,
Sep 3, 2012, 12:24:31 PM9/3/12
to jkoh...@gmail.com, robotframework-users, pe...@iki.fi

Ugh

Seems quite good and easy to understand. Also for me, would make some if/else statements easier to read and maintain. Thumbs-up also from me.

But now days I am python man and I have grown to like the explicit of the return statement. But if it is backward compatible, one should be able try new thongs.

-Tatu

Taylor, Martin

unread,
Sep 3, 2012, 2:41:28 PM9/3/12
to pe...@iki.fi, robotframework-users
I like the simplification of the logical structure and I MUCH PREFER the explicit return values. Robot Framework has always been "Pythonic" in its style and ancestry so I think this fits better than Ruby's cryptic "you just gotta know that magic happens" approach. Some of our testers who have become RF KW developers will really appreciate this new structure!

Thanks,
Martin

Kevin O.

unread,
Sep 5, 2012, 10:43:13 AM9/5/12
to robotframe...@googlegroups.com
I think the need is definitely there for the reasons you mentioned.
Rather than modifying Run Keyword If, I for one would prefer changing the syntax of test data to support IF/ELSE in a way that is consistent with the FOR loops already implemented. Using colons would also help these constructs standout as flow control statements. I would like something like this:

Do Something
    [Arguments]    ${arg} 
    :IF    "${arg}" == "xxx"
    \     Some Keyword    arg1    arg2
    :ELSE IF   "${arg}" == "yyy"
    \     Another Keyword    another arg
    :ELSE 
    \     Fail    Invalid arg value: "${arg}"

I'm sure it would be harder to implement, but better in the long run IMHO.
As for returning value(s) I have to agree with Martin.

Kevin

Taylor, Martin

unread,
Sep 6, 2012, 7:57:36 AM9/6/12
to korm...@gmail.com, robotframe...@googlegroups.com

I like this alternative syntax, if it is possible to implement this way.  I could also see a future :WHILE implemented in this way.

 

Thanks,

Martin

--

You received this message because you are subscribed to the Google Groups "robotframework-users" group.

Tatu aalto

unread,
Sep 6, 2012, 9:53:48 AM9/6/12
to cmta...@ti.com, korm...@gmail.com, robotframe...@googlegroups.com

Ugh

I like Kevins idea. At least for my eyes it looks cleaner and readable. Which usually is causes less maintenance hassle.

But really make an call which way is better (or are both needed) one should be able to try these things out, perhaps in the next release?

-Tatu

Thomas Jaspers

unread,
Sep 7, 2012, 4:28:53 AM9/7/12
to robotframe...@googlegroups.com
Hi,

even though I can understand the requirement and the need to conditional execution on one side I think the tests as such should not become too complicated. This will make it - in case of a test failures - even harder to decide whether the problem is in the System under Test or the tests.

Of course it is always possible to not use such a feature as I already try to avoid "Run Keyword If" besides for some conditional logging or doing screenshots. 

I would not say I would never use this feature ;-), but I really believe once it is available it must be used with care and I think I can remember having heard my argument mentioned above from some members of the core team in earlier days why there is no If/Then/Else construct in RF ;-).

Cheers
- Thomas

Pekka Klärck

unread,
Sep 14, 2012, 10:00:46 AM9/14/12
to korm...@gmail.com, robotframe...@googlegroups.com
2012/9/5 Kevin O. <korm...@gmail.com>:
When :FOR loop syntax with indentation was originally implemented, the
idea was to extend the same syntax for :IF blocks. We have, however,
noticed that there are two major problems with programming syntax like
this:

1) It makes test cases more complicated. It is, in general, better to
program using real programming languages in test libraries.

2) It makes the framework itself more complicated. There's quite a lot
of code in Robot Framework for parsing and running for loops as well
as showing them in log files. Parts of the parsing code could be
reused when creating :IF blocks, but execution and logging would need
a lot of new code, tests, and documentation.

3) It makes supporting tools, especially RIDE, more complicated. If
Mikko could have spent the time he has spent fighting with :FOR loops
in RIDE for something else, we probably would already have RIDE 1.0 in
our hands.


In practice I doubt we will ever add more programming logic to Robot's
test data syntax. I would actually rather remove the special :FOR loop
syntax and just add FOR keyword that could be used like this:

FOR ${i} IN v1 v2 v3 DO Keyword ${i}

Obviously :FOR loops are so widely used that they cannot be removed.
Except perhaps in possible Robot Framework 3...

Kevin O.

unread,
Sep 15, 2012, 12:32:57 AM9/15/12
to robotframe...@googlegroups.com, korm...@gmail.com
Wow - 3 days from your post to being in a new release!
I had a feeling the implementation would be difficult.  Thank you for the explanation.
Having some conditional logic in user keywords in a resource file simplifies test cases for me rather than making them more complicated. I agree that conditional logic does not belong in the test cases themselves, or even in user keywords that are local to a suite.
Sometimes there are several steps that execute conditionally and having the conditional logic repeated and no indentation present makes it harder to read.
Example:
Run Keyword If    ${foo} == 0    kw1    arg1
Run Keyword If    ${foo} == 0    kw2    arg2    arg3
Run Keyword Unless    ${foo} == 0    kw3    arg4
Run Keyword Unless    ${foo} == 0    kw4    arg5

In order to use the new feature for Run Keyword If, then these steps have to be collapsed into one keyword (presuming they take arguments which precludes using Run Keywords)..
If the series of steps in one "branch" do not make sense as a separate keywords, then I hesitate polluting the namespace with one-off keywords.
Does anyone prefix keywords that are "internal" to a resource file with a _ to indicate it is "private"? It would still pollute the namespace, but follow the heritage of Python and be visually separate.

One might be quick to say hey - just put the keyword in a library, but as you said you cannot call user keywords from Python. When following the page object model and using resources to hold the keywords the scenario you mentioned in the OP happens frequently.

Kevin

Pekka Klärck

unread,
Sep 20, 2012, 5:42:16 AM9/20/12
to korm...@gmail.com, robotframe...@googlegroups.com
2012/9/15 Kevin O. <korm...@gmail.com>:
> Wow - 3 days from your post to being in a new release!

We were already finalizing 2.7.4 release when this issue came into our
attention. I knew implementing it wasn't too complicated so it could
easily be included. The main reason I sent the original mail was to
find out do others see any obvious reasons adding such functionality
would not be a good idea.

> Sometimes there are several steps that execute conditionally and having the
> conditional logic repeated and no indentation present makes it harder to
> read.
> Example:
> Run Keyword If ${foo} == 0 kw1 arg1
> Run Keyword If ${foo} == 0 kw2 arg2 arg3
> Run Keyword Unless ${foo} == 0 kw3 arg4
> Run Keyword Unless ${foo} == 0 kw4 arg5

Agreed.

> In order to use the new feature for Run Keyword If, then these steps have to
> be collapsed into one keyword (presuming they take arguments which precludes
> using Run Keywords)..

I have actually been thinking that adding a support for running
multiple keywords with arguments to `Run Keywords` would probably be a
good idea. This could be implemented by using `AND` as separator
between keywords. I rejected the idea initially, but seeing how well
`ELSE` works with `Run Keyword If` I'm ready to change my mind. In
practice this would allow turning your example to this:

Run Keyword If ${foo} == 0 kw1 arg1 AND kw2 arg2 arg3
Run Keyword Unless ${foo} == 0 kw3 arg4 AND kw4 arg5

or even to this:

Run Keyword If ${foo} == 0
... kw1 arg1 AND kw2 arg2 arg3
... ELSE
... kw3 arg4 AND kw4 arg5

> If the series of steps in one "branch" do not make sense as a separate
> keywords, then I hesitate polluting the namespace with one-off keywords.

I agree that one-off keywords can pollute the namespace especially on
bigger projects.

> Does anyone prefix keywords that are "internal" to a resource file with a _
> to indicate it is "private"? It would still pollute the namespace, but
> follow the heritage of Python and be visually separate.

It would be great to have some kind of a support for "private"
keywords in the framework itself. There are several issues related to
this in the tracker:

Keyword visibility modifiers for resource files
http://code.google.com/p/robotframework/issues/detail?id=430

Keyword categorization support
http://code.google.com/p/robotframework/issues/detail?id=925

Limit visibility of imported resources
http://code.google.com/p/robotframework/issues/detail?id=1041

It might be a good idea to start a new thread here to discuss the
potential approaches. If we can come up with a good-enough and
not-too-hard-to-implement solution, I would really like to get
something into RF 2.8.

Pekka Klärck

unread,
Sep 20, 2012, 5:46:19 AM9/20/12
to korm...@gmail.com, robotframe...@googlegroups.com
2012/9/20 Pekka Klärck <pe...@iki.fi>:
> I have actually been thinking that adding a support for running
> multiple keywords with arguments to `Run Keywords` would probably be a
> good idea. This could be implemented by using `AND` as separator
> between keywords. I rejected the idea initially, but seeing how well
> `ELSE` works with `Run Keyword If` I'm ready to change my mind. In
> practice this would allow turning your example to this:
>
> Run Keyword If ${foo} == 0 kw1 arg1 AND kw2 arg2 arg3
> Run Keyword Unless ${foo} == 0 kw3 arg4 AND kw4 arg5
>
> or even to this:
>
> Run Keyword If ${foo} == 0
> ... kw1 arg1 AND kw2 arg2 arg3
> ... ELSE
> ... kw3 arg4 AND kw4 arg5

Ooops, examples above aren't exactly correct. These are what you could
use if `AND` support was added to `Run Keywords`:

Run Keyword If ${foo} == 0 Run Keywords kw1 arg1 AND
kw2 arg2 arg3
Run Keyword Unless ${foo} == 0 Run Keywords kw3 arg4
AND kw4 arg5

Or:

Run Keyword If ${foo} == 0
... Run Keywords kw1 arg1 AND kw2 arg2 arg3
... ELSE
... Run Keywords kw3 arg4 AND kw4 arg5

theheadofabroom

unread,
Sep 20, 2012, 6:32:02 AM9/20/12
to robotframe...@googlegroups.com, korm...@gmail.com
I think it would read better to me if it were AND THEN rather than just AND, but this would certainly appeal to me. Would another option not be to use indentation, i.e. which column - i.e.

Run Keywords If | ${foo} == 0 
…   |    | kw1    arg1
…   |    | kw2    arg2    arg3 
…   | ELSE 
…   |    | kw3    arg4
…   |    | kw4    arg5

this would seem a lot more clear and readable to me

Kevin O.

unread,
Sep 20, 2012, 11:18:57 PM9/20/12
to robotframe...@googlegroups.com, korm...@gmail.com
Thanks for the feedback and thoughts. Run Keywords with keywords taking arguments would be great.  I also see I'm not the only one who think private KWs would be handy.

Thanks,
Kevin

Bryan Oakley

unread,
Sep 21, 2012, 7:05:19 AM9/21/12
to robotframe...@googlegroups.com
On Thu, Sep 20, 2012 at 5:32 AM, theheadofabroom
<alistair....@mindcandy.com> wrote:
>
> I think it would read better to me if it were AND THEN rather than just AND, but this would certainly appeal to me. Would another option not be to use indentation, i.e. which column - i.e.
>
>> Run Keywords If | ${foo} == 0
>> … | | kw1 arg1
>> … | | kw2 arg2 arg3
>> … | ELSE
>> … | | kw3 arg4
>> … | | kw4 arg5
>
>
> this would seem a lot more clear and readable to me

That would be hard (impossible?) to do with space-separated format
since a completely blank column is indistinguishable from just extra
whitespace.

Another solution would be to introduce another special syntax similar
to "..." but with slightly different behavior. For example:

| | Run Keywords If | ${foo} == 0
| | ::: | kw1 | arg1
| | ::: | kw2 | arg 1 | arg 2
| | ::: | kw3 | arg 1 | arg 2
| | ... | arg 3 | arg 4 | arg 5
| | ::: | ELSE
| | ... | kw4 | arg1

The definition for ":::" would be something like "::: continues the
current command, but acts as a separator between two keywords. It can
be used in cases such as "run keyword" which takes one or more
keywords as arguments. Maybe something less visually similar might be
better?

| | Run Keywords If | ${foo} == 0
| | => | kw1 | arg1
| | => | kw2 | arg 1 | arg 2
| | => | kw3 | arg 1 | arg 2
| | ... | arg 3 | arg 4 | arg 5

That's at least arguably much easier to read.
Reply all
Reply to author
Forward
0 new messages