cucumber-core
Cucumber Core is the inner hexagon for the Ruby flavour of Cucumber.
It contains the core domain logic to execute Cucumber features. It has no user interface, just a Ruby API. If you're interested in how Cucumber works, or in building other tools that work with Gherkin documents, you've come to the right place.
An overview
The entry-point is a single method on the module Cucumber::Core
called #execute
. Here's what it does:
- Parses the plain-text Gherkin documents into an AST
- Compiles the AST down to test cases
- Passes the activated test cases through any filters
- Executes the test cases, calling back to the report
We've introduced a number of concepts here, so let's go through them in detail.
The AST
The Abstract Syntax Tree or AST is an object graph that represents the Gherkin documents you've passed into the core. Things like Feature, Scenario and ExamplesTable.
These are immutable value objects.
Test cases
Your gherkin might contain scenarios, as well as examples from tables beneath a scenario outline.
Test cases represent the general case of both of these. We compile the AST down to instances of Cucumber::Core::Test::Case
, each containing a number of instances of Cucumber::Core::Test::Step
. It's these that are then filtered and executed.
Test cases and their test steps are also immutable value objects.
Filters
Once we have the test cases, and they've been activated by the mappings, you may want to pass them through a filter or two. Filters can be used to do things like activate, sort, replace or remove some of the test cases or their steps before they're executed.
Report
A report is how you find out what is happening during your test run. As the test cases and steps are executed, messages are sent to the report.
A report needs to respond to the following methods:
before_test_case(test_case)
after_test_case(test_case, result)
before_test_step(test_step)
after_test_step(test_test, result)
done
That's probably best illustrated with an example.
Example
Here's an example of how you might use Cucumber::Core#execute
require 'cucumber/core'
require 'cucumber/core/filter'
class MyRunner
include Cucumber::Core
end
class ActivateSteps < Cucumber::Core::Filter.new
def test_case(test_case)
test_steps = test_case.test_steps.map do |step|
activate(step)
end
test_case.with_steps(test_steps).describe_to(receiver)
end
private
def activate(step)
case step.name
when /fail/
step.with_action { raise Failure }
when /pass/
step.with_action {}
else
step
end
end
end
class Report
def before_test_step(test_step)
end
def after_test_step(test_step, result)
puts "#{test_step.name} #{result}"
end
def before_test_case(test_case)
end
def after_test_case(test_case, result)
end
def done
end
end
feature = Cucumber::Core::Gherkin::Document.new(__FILE__, <<-GHERKIN)
Feature:
Scenario:
Given passing
And failing
And undefined
GHERKIN
MyRunner.new.execute([feature], Report.new, [ActivateSteps.new])
If you run this little Ruby script, you should see the following output:
passing ✓
failing ✗
undefined ?
Copyright
Copyright (c) 2013-2014 Cucumber Limited.