SpecFlow hooks (or events) are extension points where you can insert custom automation logic into the scenario execution before or after different sections, for example before any scenario execution. These can be used to perform custom preparation or cleanup logic, e.g. resetting the database. In bigger projects, you might need to have multiple hooks of the same kind. These run in an arbitrary order by default, which can be problematic in some cases. Hook ordering is a new feature in SpecFlow v2 that can help you in this situation. In the current “SpecFlow Tips” post, I am showing you how.
So let’s imagine that you have two [BeforeScenario]
hooks, ie. two methods that run before each scenario: one resets the database and another logs in an arbitrary user to the application. (The list of possible hooks can be found in the SpecFlow documentation.) As the database reset affects the Users table as well, we need it to be executed before the login hook.
Actually this is not quite right, because we don’t really want to login a user for every scenario, just for the ones that require an authorized user. These scenarios are marked with the @login
tag, and the hook is scoped to this tag (more about scoping in the documentation page). As the scoped hooks have no priority over the global ones, the ordering problem is still there.
So this is how our hooks look like currently:
In SpecFlow v2, we have introduced a new Order
parameter for the hook attributes, which as the name suggests can be used to control the execution order. The rules are very simple. The hook with a lower order value runs earlier than the one with a higher order value. If the order values are the same, then the order is arbitrary.
So here is a proper definition of the hooks for our situation:
What order number shall I choose?
In your project, you probably don’t think in order numbers, but you have a defined sequence of phases that has to be done before the scenario is executed. Eg. there is a database initialization phase that has to precede any other phases. Maybe you need to start some background services too, this should be the second phase and once these are all done, you can perform the authentication. Maybe there are phases even later that require an authenticated user.
You have to map these to numbers. You can use the BASIC style numbering, like 10, 20, etc. that leaves some room for introducing phases between the already defined ones. Will this be clear and understandable if you have more than two hooks? I don’t think so.
Another option is – if you have defined and named your initialization and finalization phases – to create a simple class with constants in it and use it in the hook attributes!
Feel free to use the BASIC numbering scheme for the consts – but only because of nostalgia.
Order vs Priority
When we were discussing this feature in the SpecFlow forum, we considered the related Cucumber Java implementation as well. The most interesting part of the discussion was about how the execution order should be for the “After” hooks, like[AfterScenario]
. Cucumber runs them in a reverse order, so the after-hook with the higher order number runs first.
Finally, we realized that this question is more about whether this number is a priority (higher priority features have to be initialized first and finalized last) or an order of execution (lower order number runs first regardless of before/after hook).
We concluded that interpreting “priority” for before/after extension points is more ambiguous, especially because it is very often that you don’t have an “after” pair of the “before” hook. So finally we decided to implement the feature as an “order”: In SpecFlow, the hooks with lower order value are always executed earlier. It is a slight inconsistency with Cucumber, but felt more proper.