Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
/ GUnit Public
forked from cpp-testing/GUnit

GUnit - Google.Test/Google.Mock/Cucumber on steroids

Notifications You must be signed in to change notification settings

elbeno/GUnit

Open more actions menu
 
 

Repository files navigation

Boost Licence Version Build Status Coveralls Github Issues


Testing

"If you liked it then you should have put a test on it", Beyonce rule

GUnit

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

Motivation Examples

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 Example (0 ms total)

No 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 50

Steps 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.

Overview

  • 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
  • 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!

Quick Start

Quick Start (CMake)

  • 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-cpp using 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-cpp using 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!

  • To run GUnit tests/benchmarks
    $mkdir build && cd build && cmake ..
    $make && ctest

Requirements

Tested compilers

User Guide

Acknowledgements

About

GUnit - Google.Test/Google.Mock/Cucumber on steroids

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C++ 93.9%
  • C 2.2%
  • CMake 2.0%
  • Gherkin 1.9%
Morty Proxy This is a proxified and sanitized view of the page, visit original site.