The try / except method you suggest is really right, because it shows how you really use the code in real life. However, there is a reason why you do not quite like it. This leads to ugly problems with things like:
Scenario: correct password accepted Given that I have a correct password When I attempt to log in Then I should get a prompt Scenario: correct password accepted Given that I have a correct password When I attempt to log in Then I should get an exception
If I write the definition of the step without try / in addition, the second scenario will fail. If I write it using try / except, then in the first scenario, the risk will hide the exception, especially if the exception occurs after the invitation has already been printed.
Instead, these scripts should, IMHO, be written as something like
Scenario: correct password accepted Given that I have a correct password When I log in Then I should get a prompt Scenario: correct password accepted Given that I have a correct password When I try to log in Then I should get an exception
In step "I log in" you should not use try; โI'm trying to get inโ comes up neatly to try to give away the fact that there may not be success.
Then the question arises of reusing code between two almost, but not exactly identical steps. We probably do not want to have two functions that are both inputs. Besides the simple general function that you call, you can also do something like this at the end of your steps file.
@when(u'{who} try to {what}') def step_impl(context): try: context.exception=None except Exception as e: context.exception=e
This will automatically convert all the steps containing the word "try" into steps with the same name, but with an attempt to delete, and then protect them with try / except.
There are a few questions about when you really need to deal with exceptions in BDD, as they are not visible to the user. This is not part of the answer to this question, although I have put them in a separate publication .