"If you liked it then you should have put a test on it", Beyonce rule
Google.Test/Google.Mock/Cucumber on steroids
- 
Improve your productivity with GUnit, a library which extends/simplifies Google.Test/Google.Mock and adds support for Gherkin (Behaviour Driven Development) to it. - Why it's based on Google.Test/Google.Mock?
- (+) Google.Test is widely used (The most popular testing framework according to https://www.jetbrains.com/research/devecosystem-2017/cpp)
- (+) Google.Test is stable
- (+) Google.Test is powerful
- (+) Google.Test comes with Google.Mock
- (+) Google.Test is well documented
- (-) Google.Test doesn't have support for - gherkin style - tests
- (-) Google.Test and Google.Mock have a lot boilerplate macros
 
 
- Why it's based on Google.Test/Google.Mock?
No more base classes, labels as identifiers and special assertions - GUnit.GTest / GUnit.GTest-Lite
               Google.Test                     |               GUnit.GTest
-----------------------------------------------+-----------------------------------------
#include <gtest/gtest.h>                       | #include <GUnit.h>
                                               |
struct CalcTest : testing::Test {              | GTEST("Calc Test") {
 void SetUp() override {                       |   Calc calc{};
   calc = std::make_unique<Calc>();            |
 }                                             |   // SetUp
                                               |
 void TearDown() override { }                  |   SHOULD("return sum of 2 numbers") {
                                               |     EXPECT(5 == calc->add(4, 1));
 std::unique_ptr<Calc> calc;                   |   }
};                                             |
                                               |   SHOULD("throw if division by 0") {
TEST_F(CalcTest, ShouldReturnSumOf2Numbers) {  |     EXPECT_ANY_THROW(calc->div(42, 0));
  EXPECT_EQ(5, calc->add(4, 1));               |   }
}                                              |
                                               |   // TearDown
TEST_F(CalcTest, ShouldThrowIfDivisionBy0) {   | }
  EXPECT_ANY_THROW(calc->div(42, 0));          |
}                                              |Output
[----------] 2 tests from CalcTest             | [----------] 1 tests from Calc Test
[ RUN      ] CalcTest.ShouldReturnSumOf2Numbers| [ RUN      ] Calc Test
[       OK ] CalcTest.ShouldReturnSumOf2Numbers| [ SHOULD   ] return sum of 2 numbers
[ RUN      ] CalcTest.ShouldThrowIfDivisionBy0 | [ SHOULD   ] throw if division by 0
[       OK ] CalcTest.ShouldThrowIfDivisionBy0 | [       OK ] Calc Test (0 ms)
[----------] 2 tests from CalcTest (1 ms total)| [----------] 1 tests from ExampleNo more hand written mocks - GUnit.GMock
struct interface {
  virtual ~interface() = default;
  virtual int get() const = 0;
  virtual void foo(int) = 0;
  virtual void bar(int, const std::string&) = 0;
};               Google.Test                     |           GUnit.GMock
-----------------------------------------------+--------------------------------------
#include <gmock/gmock.h>                       | #include <GUnit.h>
                                               |
struct mock_interface : interface {            |
  MOCK_CONST_METHOD0(get, int(int));           |
  MOCK_METHOD1(foo, void(int));                |
  MOCK_METHOD2(bar, void(int, const string&)); |
};                                             |
                                               |
int main() {                                   | int main() {
  StrictMock<mock_interface> mock{};           |   StrictGMock<interface> mock{};
  EXPECT_CALL(mock, foo(42));                  |   EXPECT_CALL(mock, (foo)(42));
                                               |
  interface& i = mock;                         |   interface& i = mock.object();
  i.foo(42);                                   |   i.foo(42);
}                                              | }Simplified creation and injection of SUT (System Under Test) and mocks - GUnit.GMake
class coffee_maker {
 public:
   coffee_maker(iheater&, ipump&, igrinder&);
   ...
};               Google.Test              |                     GUnit.GMake
----------------------------------------+--------------------------------------------------
#include <gtest/gtest.h>                | #include <GUnit.h>
#include <gmock/gmock.h>                |
                                        |
TEST(CalcTest, ShouldMakeCoffee) {      | GTEST("Calc Test") {
  StrictMock<mock_heater> heater{};     |   auto [sut, mocks] =
  StrictMock<mock_pump> pump{};         |     make<coffee_maker, StrictGMock>();
  StrictMock<mock_grinder> grinder{};   |
  coffee_maker sut{heater,pump,grinder};|   EXPECT_CALL(mocks.mock<iheater>(), (on)());
                                        |   EXPECT_CALL(mocks.mock<ipump>(), (pump)());
  EXPECT_CALL(heater, on());            |   EXPECT_CALL(mocks.mock<igrinder>(), (grind)());
  EXPECT_CALL(pump, pump());            |   EXPECT_CALL(mocks.mock<iheater>(), (off)());
  EXPECT_CALL(grinder, grind());        |
  EXPECT_CALL(heater, off());           |   sut->brew();
                                        | }
  sut->brew();                          |
}Support for - Gherkin style - BDD (Behaviour Driven Development) scenarios - GUnit.GSteps
Feature specification
Test/Features/Calc/addition.feature
Feature: Calc Addition
  In order to avoid silly mistakes
  As a math idiot
  I want to be told the sum of two numbers
  Scenario: Add two numbers
    Given I created a calculator with value 0
      And I have entered 20 into the calculator
      And I have entered 30 into the calculator
     When I press add
     Then The result should be 50Steps Implementation
Test/Features/Calc/Steps/CalcSteps.cpp
#include <GUnit.h>
GSTEPS("Calc*") { // "Calc Addition.Add two numbers"
  auto result = 0;
  Given("I created a calculator with value {n}") = [&](int n) {
    Calculator calc{n};
    Given("I have entered {n} into the calculator") = [&](int n) {
      calc.push(n);
    };
    When("I press add") = [&] {
      result = calc.add();
    };
    Then("The result should be {expected}") = [&](int expected) {
       EXPECT_EQ(expected, result);
    };
  };
}Usage
SCENARIO="Test/Features/Calc/addition.feature" \
  ./test --gtest_filter="Calc Addition.Add two numbers"Output
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 tests from Calc Addition
[ RUN      ] Calc Addition.Add two numbers
[    Given ] I have created a calculator with value 0         # CalcSteps.cpp:10
[    Given ] I have entered 20 into the calculator            # CalcSteps.cpp:12
[    Given ] I have entered 30 into the calculator            # CalcSteps.cpp:14
[     When ] I press add                                      # CalcSteps.cpp:16
[     Then ] the result should be 50 on the screen            # CalcSteps.cpp:19
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (7 ms total)
[  PASSED  ] 1 tests.- GUnit.GTest- Google.Test with strings and more friendly macros- Test cases with string as names
- No more SetUp/TearDown (SHOULD clauses)
- One (GTEST) macro for all types of tests
- 100% Compatible with tests using GTest
 
- GUnit.GTest-Lite- lightweight, limited, no-macro way of defining simple tests
- GUnit.GMock- Google.Mock without hand written mocks- No more hand written mocks!
- Support for more than 10 parameters
- Quicker compilation times
- Support for unique_ptr without any tricks
- Support for overloaded operators
- Support for mocking classes with constructors
- 100% Compatible with Google Mocks
 
- GUnit.GMake- Makes creation of System Under Test (SUT) and Mocks easier- No need to instantiate SUT (System Under Test) and mocks
- Automatic mocks injection
 
 
- No need to instantiate SUT (System Under Test) and mocks
- GUnit.GSteps- Behaviour Driven Development- Support for - Gherkin style - BDD tests
 
- GUnit.GAssert- Google.Test assertions without postfixes- Simple/consised interface - EXPECT(true); EXPECT(.0 > 2.0); ASSERT(11 != 42), ...
- No more EXPECT_EQ/EXPECT_GT/...
- No more confusing error messages depending on expected, given parameters
- No more bugs due to using the wrong EXPECT for floating point numbers (EXPECT_DOUBLE_EQ) and/or strings
- No more implicit conversions between types!
 
- Simple/consised interface - 
- If your project is NOT using Google.Test/Google.Mock
- Follow instructions from https://github.com/google/googletest/tree/master/googletest
 
- Clone the repository
- git clone https://github.com/cpp-testing/GUnit.git
 
- Add GUnit/includedirectory to your include path- -I GUnit/include
 
- Write some tests...
- Compile and Run!
- Add to your CMakeLists.txt the following lines:
include(FetchContent) FetchContent_Declare( gunit GIT_REPOSITORY https://github.com/cpp-testing/GUnit.git GIT_TAG master ) FETCHCONTENT_MAKEAVAILABLE(gunit)
- Write some tests...
- Compile and Run
When using the installation method as described here you may fully skip this step.
- gherkin support using CMake
- gherkin-cppusing add_subdirectory- # using add_subdirectory from the top-level CMakeLists.txt file: add_subdirectory(gunit)- # src/CMakeLists.txt contains either this: add_executable(myprogram) target_link_libraries(myprogram gunit) ... # or you could have also been more explicit, then you would write this: target_link_libraries(myprogram gtest gtest_main) 
- gherkin-cppusing a ExternalProject_Add(gunit ...) Note: This sections needs updates, when writing the gherkin-cpp CMake integration I used add_subdirectory:- Add include paths
- -I GUnit_install_dir/include
 
- Link with libgherkin-cpp.{a, so}Note: I wasn't able to nest the fmem/gherkin into libghekin-cpp, so two more libs to add: fmem/gherkin!- -L gherkin-cpp
- -L fmem
- -L gherkin
 
- Write some feature tests...
- Compile and Run!
 
- Add include paths
 
- To run GUnit tests/benchmarks
$mkdir build && cd build && cmake .. $make && ctest 
- C++14
- GTest/GTest-Lite/GMock/GMake- libs/googletest - compatible with all versions
 
- GSteps
- Thanks to Google Open Source for Google.Test/Google.Mock libraries
- Thanks to Eran Pe'er for FakeIt library
- Thanks to Peter Bindels for HippoMocks library
- Thanks to Niels Lohmann for json library
- Thanks to Aslak Hellesøy for gherkin-c library
- Thanks to Cucumber Open Source for cucumber-cpp library