下面的代码使用#define
宏。我想避免这种情况,但是我看不到使用C++功能并且可读性更好的方法。该代码用于测试将ClassUnderTest
的两个实例合并为一个的PoorLegacyClass
类。此PoorLegacyClass
具有许多getter和setter,并且出于测试目的,我需要调用很多setter(或者,是吗?)。
简而言之,不是写作
a.setValueX(20);
b.setValueX(30);
我想写点东西
set(a, b, ValueX, 20, 30);
// or
set<ValueX>(a, 20, b, 30);
// or even
set(a, b, &PoorLegacyClass::setValueX, 20, 30);
这是类似于我目前使用的代码的代码:
#include <boost/test/unit_test.hpp>
#include "ClassUnderTest.h"
BOOST_AUTO_TEST_SUITE(Test_ClassUnderTest);
#define SETTER_A_B(fieldname, valueA, valueB)\
a.set##fieldname(valueA);\
b.set##fieldname(valueB);
struct TestContext
{
PoorLegacyClass a, b;
};
BOOST_FIXTURE_TEST_CASE(ClassUnderTest_meaningful_description1, TestContext)
{
SETTER_A_B(ValueX, 20, 30);
auto result = ClassUnderTest().merge(a, b);
BOOST_TEST(20 == result.getValueX());
}
BOOST_FIXTURE_TEST_CASE(ClassUnderTest_meaningful_description2, TestContext)
{
SETTER_A_B(ValueY, 21, 37);
auto result = ClassUnderTest().merge(a, b);
BOOST_TEST(21 + 37 == result.getValueY());
}
BOOST_FIXTURE_TEST_CASE(ClassUnderTest_meaningful_description3, TestContext)
{
SETTER_A_B(ValueZ, 12, 83);
auto result = ClassUnderTest().merge(a, b);
BOOST_TEST(12 + 83 == result.getValueZ());
}
BOOST_FIXTURE_TEST_CASE(ClassUnderTest_meaningful_description4, TestContext)
{
SETTER_A_B(ValueY, 212, 37);
SETTER_A_B(ValueX, 20, 30);
auto result = ClassUnderTest().merge(a, b);
BOOST_TEST(a.getValueY() == result.getValueY());
}
// more test cases that are similar to those above
BOOST_AUTO_TEST_SUITE_END();
虽然我将来会重构
PoorLegacyClass
,但这不是这个问题的主题。不过,我想知道的是如何避免使用#define
宏。 最佳答案
由于您愿意接受语法set(a, b, &PoorLegacyClass::setValueX, 20, 30);
,因此实现这样的set
应该很容易:
template <class T>
void set(PoorLegacyClass &a, PoorLegacyClass &b, void (PoorLegacyClass::*setter)(T), T valForA, T valForB)
{
(a.*setter)(valForA);
(b.*setter)(valForB);
}
您也可以这样做,以便
valFor
参数在非推导上下文中使用T
,以便只能从setter推导T
,并对值进行隐式转换:template <class T>
struct NonDeduced { using type = T; }
template <class T>
void set(PoorLegacyClass &a, PoorLegacyClass &b, void (PoorLegacyClass::*setter)(T), typename NonDeduced<T>::type valForA, typename NonDeduced<T>::type valForB)