-
Notifications
You must be signed in to change notification settings - Fork 132
Primer 0.1
NOTE: Release 0.1 was named CukeBins
To use CukeBins, 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/
MyProject/features/some_feature.feature
MyProject/features/another_feature.feature
MyProject/features/step_definitions/
MyProject/features/step_definitions/cukebins.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 CukeBins 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.
CukeBins includes a sample borrowed from Cuke4Nuke that uses the same feature definitions but tests a C++ implementation. Let’s analyze it.
The file CalculatorSteps.cpp contains the C++ step definitions. It starts by including the test framework to be used and the Cucumber connector (in this exact order):
#include <gtest/gtest.h>
#include <cukebins/wireserver.hpp>
Then it includes the code to be tested and defines an common area to be used by every step in a scenario, that we call Context:
CUKE_CONTEXT(CalcCtx) {
Calculator calc;
double result;
};
The contexts 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:
GIVEN(CalcCtx, EnterNumber, "^I have entered (\\d+) into the calculator$") { CUKE_PARAM(1, double, n); context->calc.push(n); }
WHEN(CalcCtx, Add, "^I press add") { context->result = context->calc.add(); }
WHEN(CalcCtx, Divide, "^I press divide") { context->result = context->calc.divide(); }
THEN(CalcCtx, CheckResult, "^the result should be (.*) on the screen$") { CUKE_PARAM(1, double, expected); EXPECT_EQ(expected, context->result); }
Steps are defined by one of these macros:
GIVEN(ContextName, StepName, "regular expression") { ... }
WHEN(ContextName, StepName, "regular expression") { ... }
THEN(ContextName, StepName, "regular expression") { ... }
Regular expression parameters can be accessed in the step body using the CUKE_PARAM macro. It takes three parameters: the parameter position in the regex (counting from 1!), the variable type and name to be created. 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…
TEST(SomeTestName, SomeTestCaseName) {
context->calc.push(3);
context->calc.push(2);
context->result = context->calc.divide();
EXPECT_EQ(1.5, context->result);
}
A fixture for a step, can be defined with the macro CUKE_FIXTURE. Apart from that, the definition should be that of a normal GTest Fixture.
CUKE_FIXTURE(FixtureName, ContextName) {
...
void SetUp() { ... }
void TearDown() { ... }
}
To associate that fixture to a step you should then add the _F suffix to the step definition macros:
GIVEN_F(FixtureName, StepName, "regular expression") { ... }
WHEN_F(FixtureName, StepName, "regular expression") { ... }
THEN_F(FixtureName, StepName, "regular expression") { ... }
The current library is header-only, so it doesn’t need to be compiled separately, but it needs the following libraries when compiling the step definitions:
- Boost 1.40 (thread, system, regex, and date_time libraries) – Should work with some previous versions too, but it wasn’t tested
- GTest 1.4 – Needed by the test suite and the GTest implementation. Works with GTest 1.4 and 1.5 (not tested with 1.3)
This header-only library is included in the source code:
- JSON Spirit – Needed by the Wire Protocol connector
CukeBins 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
- For Boost, set BOOST_ROOT to the location of the Boost install prefix if CMake has troubles finding it
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/CalculatorSteps >/dev/null &
cucumber examples/Calc/CalcFeatures
To run the example on Windows (NMake):
start build\examples\Calc\CalculatorSteps.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 # Unknown And I have entered <input_2> into the calculator # Unknown When I press <button> # Unknown Then the result should be <output> on the screen # Unknown
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 # Unknown And I have entered 2 into the calculator # Unknown When I press divide # Unknown Then the result should be 1.5 on the screen # Unknown
4 scenarios (4 passed) 16 steps (16 passed)