4.7. Step - 05 : Make tests fail¶
Now, let’s add a very basic libMath
library, and make tests fail.
The updated directory structure would be like this. (Bear with me, this is no Python. It’s C/C++. Just to add an empty file with missing implementation, we will need to create 3 files, and update at-least 1-3 more file):
.
|-- features
| |-- step_definitions
| | |-- cucumber.wire
| | `-- steps_addition.cpp
| |-- CMakeLists.txt
| `-- simple-addition.feature
|-- lib
| |-- CMakeLists.txt
| |-- libMath.c
| `-- libMath.h
`-- CMakeLists.txt
lib/libMath.h
This new header file has the interface for the libMath APIs.
#ifdef __cplusplus extern "C" { #endif // __cplusplus int libMath_add(int param1, int param2); #ifdef __cplusplus } // extern "C" #endif // __cplusplus
lib/libMath.c
As of now, the file
lib/libMath.c
will not have any implementation. (Remember we still want to fail tests.)#include <libMath.h> int libMath_add(int param1, int param2) { return -1; // FIXME }
lib/CMakeLists.txt
A minimal CMakeLists.txt file is needed to make this as a library.
PROJECT(libMath) ADD_LIBRARY( ${PROJECT_NAME} libMath.c libMath.h ) TARGET_INCLUDE_DIRECTORIES(${PROJECT_NAME} PUBLIC .)
features/CMakeLists.txt
Update the Feature executable CMake File so that it can link to the new
libMath
.PROJECT(features) FILE( GLOB all_files step_definitions/*.cpp step_definitions/*.hpp *.feature ) ADD_EXECUTABLE(${PROJECT_NAME} ${all_files}) TARGET_LINK_LIBRARIES( ${PROJECT_NAME} CucumberCpp::cucumber-cpp libMath )
<TOP>CMakeLists.txt
Update the top level
<TOP>CMakeLists.txt
to also .CMAKE_MINIMUM_REQUIRED(VERSION 3.1) PROJECT(DemoBDD) INCLUDE(/usr/local/lib/cmake/CucumberCppConfig.cmake) SET(BOOST_MIN_VERSION "1.51") SET(CUKE_CORE_BOOST_LIBS thread system regex date_time program_options filesystem ) FIND_PACKAGE( Boost ${BOOST_MIN_VERSION} COMPONENTS ${CUKE_CORE_BOOST_LIBS} REQUIRED ) FIND_PACKAGE( GMock REQUIRED ) FIND_PACKAGE( GTest REQUIRED ) ADD_SUBDIRECTORY(features) ADD_SUBDIRECTORY(lib)
4.7.1. Changes¶
As compared to previous step (Step - 04 : Add Dummy Steps), the change is long, and hence listed at the end of this section at Changes - full diff.
4.7.2. Use CMake¶
Using CMake, we configure/create a work space, because we have added a new library libMath
:
cmake -S . -B ../_05-failing-tests
If everything is setup perfectly, the output would be similar to Step - 01 : Setup of C/C++ Code. (Not shown here)
4.7.3. Compile the math library and feature executable¶
Let’s compile the workspace:
make all
If everything is setup perfectly, the output looks like this:
[ 8%] Creating directories for 'GMock'
[ 16%] No download step for 'GMock'
[ 25%] No update step for 'GMock'
[ 33%] No patch step for 'GMock'
[ 41%] Performing configure step for 'GMock'
-- The CXX compiler identification is GNU 11.4.0
-- The C compiler identification is GNU 11.4.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Found Python: /home/c6h6/.virtualenvs/ratu7env/bin/python3.10 (found version "3.10.12") found components: Interpreter
-- Looking for pthread.h
-- Looking for pthread.h - found
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Success
-- Found Threads: TRUE
-- Configuring done
-- Generating done
-- Build files have been written to: /home/c6h6/data/p/book-tests/pgh_tech-bdd/book/csrc/_05-failing-tests/gmock
[ 50%] Performing build step for 'GMock'
[ 12%] Building CXX object /home/c6h6/data/p/book-tests/pgh_tech-bdd/book/csrc/_05-failing-tests/googletest/CMakeFiles/gtest.dir/src/gtest-all.cc.o
[ 25%] Linking CXX static library /home/c6h6/data/p/book-tests/pgh_tech-bdd/book/csrc/_05-failing-tests/gmock/lib/libgtest.a
[ 25%] Built target gtest
[ 37%] Building CXX object CMakeFiles/gmock.dir/src/gmock-all.cc.o
[ 50%] Linking CXX static library lib/libgmock.a
[ 50%] Built target gmock
[ 62%] Building CXX object CMakeFiles/gmock_main.dir/src/gmock_main.cc.o
[ 75%] Linking CXX static library lib/libgmock_main.a
[ 75%] Built target gmock_main
[ 87%] Building CXX object /home/c6h6/data/p/book-tests/pgh_tech-bdd/book/csrc/_05-failing-tests/googletest/CMakeFiles/gtest_main.dir/src/gtest_main.cc.o
[100%] Linking CXX static library /home/c6h6/data/p/book-tests/pgh_tech-bdd/book/csrc/_05-failing-tests/gmock/lib/libgtest_main.a
[100%] Built target gtest_main
[ 58%] No install step for 'GMock'
[ 66%] Completed 'GMock'
[ 66%] Built target GMock
[ 75%] Building C object lib/CMakeFiles/libMath.dir/libMath.c.o
[ 83%] Linking C static library liblibMath.a
[ 83%] Built target libMath
[ 91%] Building CXX object features/CMakeFiles/features.dir/step_definitions/steps_addition.cpp.o
[100%] Linking CXX executable features
[100%] Built target features
And, we must have a feature
executable generated, as well as libMath
4.7.4. Running feature executable¶
As a first step, we need to run the feature executable in background.
./features/features -v &
If everything is setup perfectly, this process will wait for Cucumber. And once we run Cucumber, the full output would be like this:
Listening on 127.0.0.1:3902
/home/c6h6/data/p/book-tests/pgh_tech-bdd/book/csrc/05-failing-tests/features/step_definitions/steps_addition.cpp:39: Failure
Expected equality of these values:
4
context->result
Which is: -1
/home/c6h6/data/p/book-tests/pgh_tech-bdd/book/csrc/05-failing-tests/features/step_definitions/steps_addition.cpp:44: Failure
Expected equality of these values:
99
context->result
Which is: -1
4.7.5. Running cucumber¶
Now let’s run Cucumber.
cucumber
The output is as follows.
*** THIS RUBY IMPLEMENTATION DOESN'T REPORT FILE AND LINE FOR PROCS ***
# features/sample-addition.feature
Feature: Simple Addition
Showcase simple addition for the BDD Book.
Scenario: Addition of single digit numbers # features/simple-addition.feature:7
Given I have '1' and '3' # steps_addition.cpp:20
When I add them # steps_addition.cpp:32
Then The result must be '4' # steps_addition.cpp:37
/home/c6h6/data/p/book-tests/pgh_tech-bdd/book/csrc/05-failing-tests/features/step_definitions/steps_addition.cpp:39: Failure
Expected equality of these values:
4
context->result
Which is: -1 (Cucumber::WireSupport::WireException)
features/simple-addition.feature:10:in `Then The result must be '4''
Scenario: Addition of double digit numbers # features/simple-addition.feature:12
Given I have '70' and '29' # steps_addition.cpp:26
When I add them # steps_addition.cpp:32
Then The result must be '99' # steps_addition.cpp:42
/home/c6h6/data/p/book-tests/pgh_tech-bdd/book/csrc/05-failing-tests/features/step_definitions/steps_addition.cpp:44: Failure
Expected equality of these values:
99
context->result
Which is: -1 (Cucumber::WireSupport::WireException)
features/simple-addition.feature:15:in `Then The result must be '99''
Failing Scenarios:
cucumber features/simple-addition.feature:7 # Scenario: Addition of single digit numbers
cucumber features/simple-addition.feature:12 # Scenario: Addition of double digit numbers
2 scenarios (2 failed)
6 steps (2 failed, 4 passed)
0m0.017s
As you can see, the output is different from Step - 04 : Add Dummy Steps. We now see failing tests.
4.7.6. Changes - full diff¶
As compared to previous step (Step - 04 : Add Dummy Steps), the diff is:
diff '--unified=3' --new-file --ignore-all-space --text --recursive --show-c-function --report-identical-files old/CMakeLists.txt new/CMakeLists.txt
--- old/CMakeLists.txt 2022-12-11 00:00:00.000000000 +0530
+++ new/CMakeLists.txt 2022-12-11 00:00:00.000000000 +0530
@@ -31,3 +31,4 @@ FIND_PACKAGE(
)
ADD_SUBDIRECTORY(features)
+ADD_SUBDIRECTORY(lib)
diff '--unified=3' --new-file --ignore-all-space --text --recursive --show-c-function --report-identical-files old/features/CMakeLists.txt new/features/CMakeLists.txt
--- old/features/CMakeLists.txt 2022-12-11 00:00:00.000000000 +0530
+++ new/features/CMakeLists.txt 2022-12-11 00:00:00.000000000 +0530
@@ -13,4 +13,5 @@ ADD_EXECUTABLE(${PROJECT_NAME} ${all_fil
TARGET_LINK_LIBRARIES(
${PROJECT_NAME}
CucumberCpp::cucumber-cpp
+ libMath
)
Files old/features/simple-addition.feature and new/features/simple-addition.feature are identical
Files old/features/step_definitions/cucumber.wire and new/features/step_definitions/cucumber.wire are identical
diff '--unified=3' --new-file --ignore-all-space --text --recursive --show-c-function --report-identical-files old/features/step_definitions/steps_addition.cpp new/features/step_definitions/steps_addition.cpp
--- old/features/step_definitions/steps_addition.cpp 2022-12-11 00:00:00.000000000 +0530
+++ new/features/step_definitions/steps_addition.cpp 2022-12-11 00:00:00.000000000 +0530
@@ -2,26 +2,44 @@
#include <gtest/gtest.h>
#include <cucumber-cpp/autodetect.hpp>
+#include <libMath.h>
+
+using cucumber::ScenarioScope;
+
+struct libMathCtx {
+ int param1;
+ int param2;
+ int result;
+};
+
+
// We could have used Regular Expressions here
// to reduce the duplicated steps.
// but we will introduce that concept later.
GIVEN("^I have '1' and '3'$") {
- pending();
+ ScenarioScope<libMathCtx> context;
+ context->param1 = 1;
+ context->param2 = 3;
}
GIVEN("^I have '70' and '29'$") {
- pending();
+ ScenarioScope<libMathCtx> context;
+ context->param1 = 70;
+ context->param2 = 29;
}
WHEN("^I add them$") {
- pending();
+ ScenarioScope<libMathCtx> context;
+ context->result = libMath_add(context->param1, context->param2);
}
THEN("^The result must be '4'$") {
- pending();
+ ScenarioScope<libMathCtx> context;
+ EXPECT_EQ(4, context->result);
}
THEN("^The result must be '99'$") {
- pending();
+ ScenarioScope<libMathCtx> context;
+ EXPECT_EQ(99, context->result);
}
diff '--unified=3' --new-file --ignore-all-space --text --recursive --show-c-function --report-identical-files old/lib/CMakeLists.txt new/lib/CMakeLists.txt
--- old/lib/CMakeLists.txt 1970-01-01 05:30:00.000000000 +0530
+++ new/lib/CMakeLists.txt 2022-12-11 00:00:00.000000000 +0530
@@ -0,0 +1,9 @@
+PROJECT(libMath)
+
+ADD_LIBRARY(
+ ${PROJECT_NAME}
+ libMath.c
+ libMath.h
+)
+
+TARGET_INCLUDE_DIRECTORIES(${PROJECT_NAME} PUBLIC .)
diff '--unified=3' --new-file --ignore-all-space --text --recursive --show-c-function --report-identical-files old/lib/libMath.c new/lib/libMath.c
--- old/lib/libMath.c 1970-01-01 05:30:00.000000000 +0530
+++ new/lib/libMath.c 2022-12-11 00:00:00.000000000 +0530
@@ -0,0 +1,6 @@
+
+#include <libMath.h>
+
+int libMath_add(int param1, int param2) {
+ return -1; // FIXME
+}
diff '--unified=3' --new-file --ignore-all-space --text --recursive --show-c-function --report-identical-files old/lib/libMath.h new/lib/libMath.h
--- old/lib/libMath.h 1970-01-01 05:30:00.000000000 +0530
+++ new/lib/libMath.h 2022-12-11 00:00:00.000000000 +0530
@@ -0,0 +1,10 @@
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+int libMath_add(int param1, int param2);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif // __cplusplus