0

I want to check that other classes meet the same specifications as my base class but, I don't want to repeat the same code. A solution that I am thinking of is passing a class as an argument to a test case and I'd be able to invoke the same methods but it doesn't seem possible.

Here is an example of what I have. It repeats the same code.

#include <iostream>
#include <catch2/catch_test_macros.hpp>

using namespace std;

class Base 
{

public:
  Base() = default;
  virtual ~Base() = default;
  
  virtual string do_something() {
    return "Base";
  }

};

class A : Base
{
public:
  A() = default;
  string do_something() override {
    return "A";
  }


};

class B : Base
{
public:
  B() = default;
  string do_something() override {
    return "B";
  }


};

TEST_CASE("some test")
{
/* THIS IS THE SPEC THAT DERIVED CLASSES SHOULD MEET.
  SECTION("Base class"){
    Base base_obj;
    auto result = base_obj.do_something();
    REQUIRE(result != "");
  }
*/
  SECTION("Dervied class A"){
    A a_obj;
    auto result = a_obj.do_something();
    REQUIRE(result != "");
  }
  SECTION("Dervied class B"){
    B b_obj;
    auto result = b_obj.do_something();
    REQUIRE(result != "");
  }
}


Brandon
  • 1
  • 3

2 Answers2

0

Yes as said you can do it with templates (and lambdas). Like this :

#include <cassert> // replacement for your test framework
#include <iostream>
#include <type_traits>
//#include <catch2/catch_test_macros.hpp>

//using namespace std; <-- don't do this

struct Base
{
    virtual std::string do_something() { return "Base";}
};

struct A : Base
{
    std::string do_something() override { return "A"s; }
};

struct B : Base
{
    std::string do_something() override { return "B"s;}
};

template<typename base_t, typename... types_t>
void test_lsp()
{
    // check that all classes are correctly derived from base
    static_assert((std::is_base_of_v<base_t, types_t>, ...));

    // a lambda to test instances of your derived classes
    auto test = [](auto&& object)
    {
        auto value = object.do_something();
        std::cout << value << "\n";
        assert(value != ""s);
    };

    // if you want baseclass to have functionality test that 
    test(base_t{});

    // use fold expression to test all derived types
    (test(types_t{}), ...);
}

int main()
{
    // and now you can just supply the list of classes to test
    test_lsp<Base, A, B>();
    return 0;
}
Pepijn Kramer
  • 9,356
  • 2
  • 8
  • 19
0

REQUIRE and SECTION live in any function. This allows for a much cleaner solution using catch2 built in functionality.

void test_lsp(Base &obj)
{
  SECTION("...") {}
  SECTION("...") {}
}
TEST_CASE("some test")
{
  Derived obj;
  test_lsp(obj);
}
Brandon
  • 1
  • 3