Is there a cucumber hook to run before and after each feature

北城余情 提交于 2019-11-27 03:21:10

问题


Is there a way to run specific code block before and after each cucumber feature with certain tag?

Since setup process is very expensive I don't want to run it before each scenario.


回答1:


LukasMac's answer didn't work with @ variable. Ande based on official cucumber wiki page, my example below worked and tested ok, the before hook below only execute once per feature:

Before('@my_feature_tag') do
  unless $dts_test_preparation_done
    # expensive setup in my case setup lots of database tables for test
    $dts_test_preparation_done = true
  end
end



回答2:


Few days ago I've spoke with Matt Wynne (one of the core team member of cucumber gem) and he told me that there is no such feature in cucumber (at the time of writing this).

As a workaround he suggested to tag whole feature and use before each hook with a flag like so:

Before('@feature_with_expensive_setup') do
  unless @setup_is_done
    # perform expensive setup code here ..
    @setup_is_done = true
  end
end



回答3:


The hooks for cucumber are described in this wiki page which show the before and after hooks you can have.

Taken from that page is this example:

The following example will cause scenarios tagged with @fast to fail if the execution takes longer than 0.5 seconds:

Around('@fast') do |scenario, block|
  Timeout.timeout(0.5) do
    block.call
  end
end



回答4:


Cucumber before and after feature hooks

Usage info

As ruby cucumber does not come supplied with the option to create hooks for before and after a feature, an ad hoc solution has been put forward.

In order to specify a hook relating to a feature, the method name must be in the following format:

before_feature_[formatted feature name] after_feature_[formatted feature name]

Where the formatted feature name is the text from the 'Feature:' line in the feature file formatted with:

(i) all characters lowercased; (ii) all spaces replaced with underscores; and, (iii) all special characters deleted

Within methods matching this convention code can be specified as with scenario hooks.

Technical info

Building on the solutions by LukasMac and Gob00st I have implemented the following workarounds for my current client.

The methods go in a hooks subdirectory called AAA_special_hooks, in a special_hooks.rb file in that directory (the sole file), this is because all other things being equal the hooks will be run in the order they appear in the project structure and this way the hooks created here are run before any scenario hooks specified in other subdirectories or in the hooks base directory.

The code in the below appendix is vanilla, so far as I can see it would work for anyone.

The before hook runs on the principle of setting a global flag to ensure the hook is only run once for a feature (as per LukasMac and Gob00st). That principle has been extended to the abstract hook for two reasons, firstly to simplify the specification of hooks in general and also to have consistency with the after hook implementation.

The after hook is designed to determine whether the feature has changed since the last scenario was executed. If so the after hook will be run for the previous feature before anything happens in the current one. Clearly the vulnerability could be that the new feature has in fact been started before the after hook runs for the previous one, but I can't see how this might cause any issues. The final feature however cannot have an after hook run in this way and that is the reason for the reimplementation of that code in the at_exit method.

Appendix - special_hooks.rb code

def get_formatted_name(feature_name)
  formatted_name = feature_name.downcase.gsub(' ', '_')
  %w[@ ' , . / ! " £ $ % ^ & * ( ) { } [ ] ; : # ~ ? < > \] + = - ` ¬ |].each { |char| formatted_name.gsub! char, '' }
  formatted_name
end

Before do |scenario|
  $completed_before_hooks ||= []
  $feature_name ||= scenario.feature.name
  unless $feature_name == scenario.feature.name
    # run after hook for previous feature
    begin
      send "after_feature_#{get_formatted_name $feature_name}"
    rescue NoMethodError
    end
  end

  #run before hook for current feature if not already done
  begin
    formatted_name = get_formatted_name scenario.feature.name
    unless $completed_before_hooks.include? formatted_name
      $completed_before_hooks << formatted_name
      send "before_feature_#{formatted_name}"
    end
  rescue NoMethodError
  end

  $feature_name = scenario.feature.name
end

at_exit do
  # don't run final hook if error raised that was not handled
  unless $! && $!.status > 1
    puts 'EXECUTING FINAL AFTER HOOK... PLEASE WAIT'
    begin
      send "after_feature_#{get_formatted_name $feature_name}"
    rescue NoMethodError
    end
    puts 'FINAL AFTER HOOK COMPLETED'
  end
end



回答5:


Mocking of BeforeFeature/ AfterFeature hooks is achievable by tagging the first scenario of the feature with a tag say @ExecuteBeforeFeature and last scenario with tag say @ExecuteAfterFeature and then writing the tagged Before and After hooks as following:

Before('@ExecuteBeforeFeature') do
  #code in this method will be executed only before the first scenario or before the feature if only the first scenario is tagged for this hook.
end

After('@ExecuteAfterFeature') do
  #code in this method will be executed only after the last scenario or after the feature if only the last scenario is tagged for this hook.
end



回答6:


a modification of the first answer works for me with single quotes

    Before('@feature_with_expensive_setup') do
      unless '@setup_is_done'
        # perform expensive setup code here ..
        @setup_is_done = true
      end
    end


来源:https://stackoverflow.com/questions/23113370/is-there-a-cucumber-hook-to-run-before-and-after-each-feature

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!