-
Notifications
You must be signed in to change notification settings - Fork 131
Primer
This guide is for the development branch.
To use Cucumber-Cpp, you have to write the standard Cucumber scenarios, set up the wire protocol connection and write the C++ step definitions.
Nothing strange here. The project structure is the same as with Cuke4Nuke:
MyProject/features/some_feature.feature
MyProject/features/another_feature.feature
MyProject/features/step_definitions/cucumber-cpp.wire
The .wire file tells Cucumber that it should use the wire protocol. The file has two lines:
host: localhost
port: 3902
The default port for Cucumber-Cpp server is 3902. If you need to change it, you should add the same port number as the first argument while running the steps executable.
Cucumber-Cpp includes a sample borrowed from Cuke4Nuke that uses the same feature definitions but tests a C++ implementation. Let’s analyze it.
The file CppSpecCalculatorSteps.cpp contains the C++ step definitions (written using CppSpec, but samples for Boost and GTest are provided as well). It starts by including the test framework to be used and the Cucumber connector (in this exact order):
#include <CppSpec/CppSpec.h>
#include <cucumber-cpp/defs.hpp>
Then it includes the code to be tested and defines common data to be used by every step in a scenario, that we call context:
struct CalcCtx {
Calculator calc;
double result;
};
The contexts with scenario scope will be automatically created before and cleared after every scenario (actually they are created only when needed by a step). The step code will be able to access a “context” pointer of the defined type, as we will see. In the sample application the steps are defined as:
using cucumber::ScenarioScope;
GIVEN("^I have entered (\\d+) into the calculator$") { REGEX_PARAM(double, n); ScenarioScope<CalcCtx> context;
context->calc.push(n); }
WHEN("^I press add") { ScenarioScope<CalcCtx> context;
context->result = context->calc.add(); }
WHEN("^I press divide") { ScenarioScope<CalcCtx> context;
context->result = context->calc.divide(); }
THEN("^the result should be (.*) on the screen$") { REGEX_PARAM(double, expected); ScenarioScope<CalcCtx> context;
specify(context->result, should.equal(expected)); }
Steps are defined by one of these macros:
GIVEN("regular expression") { ... }
WHEN("regular expression") { ... }
THEN("regular expression") { ... }
Regular expression parameters can be accessed in the step body using the REGEX_PARAM macro. It takes two parameters: the variable type and name. The type can be every C++ type that can be extracted by a std::istringstream (so you can even define your own types implementing the extraction operator).
So executing the following scenario…
Scenario: Regular numbers
Given I have entered 3 into the calculator
And I have entered 2 into the calculator
When I press divide
Then the result should be 1.5 on the screen
…would correspond to something like…
void theCalculatorCanComputeBasicDivisions() {
context->calc.push(3);
context->calc.push(2);
context->result = context->calc.divide();
specify(context->result, should.equal(1.5));
}
The current library relies on a few libraries:
- Boost 1.40+ (headers for smart_ptr and spirit, as well as compiled libraries for thread, system, regex, and date_time) – Should work with some previous versions too, but it wasn’t tested
- GTest 1.4+ – Optional for the software test suite and the GTest driver. It wasn’t tested with GTest 1.3
- CppSpec development branch – Optional for the CppSpec driver
- GMock 1.6+ – Optional for the internal test suite
This header-only library is included in the source code:
- JSON Spirit – Needed by the Wire Protocol connector
Cucumber-Cpp uses the CMake build system, so you also need CMake 2.8 to run the tests and the example project. This is how to complile them:
cmake -E make_directory build
cmake -E chdir build cmake ..
cmake --build build
cmake --build build --target test
If CMake can’t find the required libraries, you can define variables to specify the path where to look. For GTest, set GTEST_ROOT to the location of the GTest install prefix. If the GTest libraries were installed in /usr/local/lib and the includes are in /usr/local/include/gtest, then you should add -DGTEST_ROOT=/usr/local to the cmake command line. Similarly you can define BOOST_ROOT and CPPSPEC_ROOT for Boost and CppSpec respectively.
This is more complex example of CMake command line specifying both a Visual Studio Project generator and paths for the libraries:
cmake -E make_directory vs_project
cmake -E chdir vs_project cmake -G"Visual Studio 9 2008" -DGTEST_ROOT=X:\gtest-1.4.0 -DBOOST_ROOT=X:\boost_1_40_0 ..
This is an example of how to create an Eclipse Project:
cmake -E make_directory eclipse_project
cmake -E chdir eclipse_project cmake -G"Eclipse CDT4 - Unix Makefiles" -DGTEST_ROOT=/usr/local ..
To run the example on Unix:
build/examples/Calc/CppSpecCalculatorSteps >/dev/null &
cucumber examples/Calc/CalcFeatures
To run the example on Windows (NMake):
start build\examples\Calc\CppSpecCalculatorSteps.exe
cucumber examples\Calc\CalcFeatures
You should see Cucumber scenarios passing:
# language: en Feature: Addition In order to avoid silly mistakes As a math idiot I want to be told the sum of two numbers
Scenario Outline: Add two numbers # examples/Calc/CalcFeatures/features/addition.feature:7 Given I have entered <input_1> into the calculator # CppSpecCalculatorSteps.cpp:11 And I have entered <input_2> into the calculator # CppSpecCalculatorSteps.cpp:11 When I press <button> # CppSpecCalculatorSteps.cpp:17 Then the result should be <output> on the screen # CppSpecCalculatorSteps.cpp:27
Examples: | input_1 | input_2 | button | output | | 20 | 30 | add | 50 | | 2 | 5 | add | 7 | | 0 | 40 | add | 40 |
# language: en Feature: Division In order to avoid silly mistakes Cashiers must be able to calculate a fraction
Scenario: Regular numbers # examples/Calc/CalcFeatures/features/division.feature:6 Given I have entered 3 into the calculator # CppSpecCalculatorSteps.cpp:11 And I have entered 2 into the calculator # CppSpecCalculatorSteps.cpp:11 When I press divide # CppSpecCalculatorSteps.cpp:22 Then the result should be 1.5 on the screen # CppSpecCalculatorSteps.cpp:27
4 scenarios (4 passed) 16 steps (16 passed) 0m0.045s