对于单元测试,是否有一种骇人听闻的方法来更改 const 变量的值?
For unit tests, is there a hackish way to change the value of a const variable?
我有一个 C++ 11 头文件,它有一个声明为 my_const_value
的常量值。还有一个名为 GetValue
的函数,它使用 const 值和 returns 预期值运行复杂的逻辑。
我想用 my_const_value
的不同值对 GetValue
进行单元测试。
我知道这是不可取的,但是为了为 GetValue
编写单元测试,我希望用 my_const_value
的不同值测试 GetValue
。 C++ 中是否有一些 hack-ish 方法来更改 const 的值,即使它是 const?
//MyHeader.hpp
namespace myheader {
const int my_const_value = 5;
int GetValue() {
// In real-world, lets say below line of code is a complex logic that needs to be tested by a unit test
return /my_const_value * 5) / 25;
}
}
#include "MyHeader.hpp"
#include <gtest/gtest.h>
TEST(MyHeaderTest, Testing_Something) {
EXPECT_EQ(1, myheader::GetValue()); // This is okay
// I want to test that in the future is the value of my_const_value changes to something else then
// myheader::GetValue returns the expected result. But of course, I cannot change my_const_value because it is a const.
// Is there a way to hack around this for a unit test? Is there a way that I could still hack and change the value of my_const_value?
myheader::my_const_value = 25;
EXPECT_EQ(5, myheader::GetValue());
}
我知道我可以 const_cast
my_const_value
到 non_const 变量。但这在这里无济于事。如果有一些 hack 可以通过使用指针或其他东西来更改 my_const_value
的值,那将回答我的问题。
没有
更改声明为 const
的内容的值会调用未定义的行为。为了说明,请考虑此代码
const int x = 4;
modify_const_somehow(x,42); // "magically" assigns 42 to x
std::cout << x;
可以打印任何东西。您可以在控制台上看到 4
或 42
,但 "Hey you broke the rules, const cannot be modified"
也是有效输出。无论您如何修改 x
,代码都有未定义的行为。编译器不需要发出错误或警告,代码只是无效的,编译器不需要对它做任何有意义的事情。
唯一允许删除常量的情况是对象实际上不是常量。听起来很奇怪不是吗?看这个例子:
const int x = 42;
int y = 100;
void foo(const int& a) {
const_cast<int&>(a) = 4;
}
foo(x); // undefined behavior !!
foo(y); // OK !!
您的问题的解决方案是编写可测试的代码。例如:
int GetValue(int value = my_const_value) {
// In real world, lets say below line of code is a complex logic that needs to be tested by a unit test
return (value * 5) / 25;
}
如果您想保留原始签名,您也可以将其包装(如评论中所建议):
int GetValue_impl(int value) {
return (value * 5) / 25;
}
int GetValue() {
return GetValue_impl(my_const_value);
}
现在您可以测试 GetValue_impl
而 GetValue
使用常量。但是,我真的很奇怪你为什么要测试一个不可能发生的案例。
你问的是 hackish,这里是 :
// define the string const to be replaced by empty string
#define const
#include "header.hh"
#undefine const
...tests...
我看到的唯一问题是 1.all const 修饰符脱落,这可能是问题,也可能不是问题。 2. 它有点侵入性,正如其他人提到的那样,编译器以特定方式处理常量,因此您的测试并没有完全测试将 运行 在您的实际用例中使用的相同代码。
有一个类似的技巧,从 #define private public
开始,然后包括 header,用于从库中访问另一个 class 的私有字段。好消息是当你 link 在图书馆时它甚至不会中断。
请注意 none 这些东西是推荐的,它们是 hackish,但是利用预处理器来偏置包含的文件是可以的。它将清除 all const 修饰符,并在其他包含的 header 中传递,因此非常具有侵入性。
更简单的做法是拥有一个宏 TEST
并放入您的 header #ifdef TEST /*non const decl*/ #else /*const decl*/
。那么你显然在包含 header 之前执行 #define TEST
这比重新定义关键字更干净。
我知道您正在寻找一种方法来摆脱 const,但我可能会采用不同的方法。
您在评论中说:
Well. I have given my reason. I am testing the logic in GetValue
. I have declared my_const_value
as a const
but that can be changed from 5
to something else in future when someone changes the value in future.
如果一个变量是 const
并且在没有传递给它的情况下参与函数内的表达式,那么这些更改通常不应该定期发生,也不应该被期望。如果您认为 myheader::my_const_value
是一个配置值,并且可能随时更改,那么它应该传递给在表达式中使用它的函数。
因此,从测试的角度来看,我同意 在答案中提出的建议,将函数分为两部分,一个可测试部分带有参数,另一部分使用常量。
一个测试代码当前应该如何表现的测试(它应该有什么常量)
TEST(MyHeaderTest, Testing_Something1) {
EXPECT_EQ(5, myheader::my_const_value)
EXPECT_EQ(1, myheader::GetValue());
}
还有一个用于通用测试:
TEST(MyHeaderTest, Testing_Something2) {
EXPECT_EQ(1, myheader::GetValue_impl(5));
EXPECT_EQ(5, myheader::GetValue_impl(25));
// …
}
如果 GetValue
使用的计算有效,那么您就可以进行通用测试。还有一个,如果对于您当前版本的代码,myheader::GetValue()
的值是预期值。
嗨希望你做得很好。
只需在存根函数上方尝试#define const /* myComment */
我有一个 C++ 11 头文件,它有一个声明为 my_const_value
的常量值。还有一个名为 GetValue
的函数,它使用 const 值和 returns 预期值运行复杂的逻辑。
我想用 my_const_value
的不同值对 GetValue
进行单元测试。
我知道这是不可取的,但是为了为 GetValue
编写单元测试,我希望用 my_const_value
的不同值测试 GetValue
。 C++ 中是否有一些 hack-ish 方法来更改 const 的值,即使它是 const?
//MyHeader.hpp
namespace myheader {
const int my_const_value = 5;
int GetValue() {
// In real-world, lets say below line of code is a complex logic that needs to be tested by a unit test
return /my_const_value * 5) / 25;
}
}
#include "MyHeader.hpp"
#include <gtest/gtest.h>
TEST(MyHeaderTest, Testing_Something) {
EXPECT_EQ(1, myheader::GetValue()); // This is okay
// I want to test that in the future is the value of my_const_value changes to something else then
// myheader::GetValue returns the expected result. But of course, I cannot change my_const_value because it is a const.
// Is there a way to hack around this for a unit test? Is there a way that I could still hack and change the value of my_const_value?
myheader::my_const_value = 25;
EXPECT_EQ(5, myheader::GetValue());
}
我知道我可以 const_cast
my_const_value
到 non_const 变量。但这在这里无济于事。如果有一些 hack 可以通过使用指针或其他东西来更改 my_const_value
的值,那将回答我的问题。
没有
更改声明为 const
的内容的值会调用未定义的行为。为了说明,请考虑此代码
const int x = 4;
modify_const_somehow(x,42); // "magically" assigns 42 to x
std::cout << x;
可以打印任何东西。您可以在控制台上看到 4
或 42
,但 "Hey you broke the rules, const cannot be modified"
也是有效输出。无论您如何修改 x
,代码都有未定义的行为。编译器不需要发出错误或警告,代码只是无效的,编译器不需要对它做任何有意义的事情。
唯一允许删除常量的情况是对象实际上不是常量。听起来很奇怪不是吗?看这个例子:
const int x = 42;
int y = 100;
void foo(const int& a) {
const_cast<int&>(a) = 4;
}
foo(x); // undefined behavior !!
foo(y); // OK !!
您的问题的解决方案是编写可测试的代码。例如:
int GetValue(int value = my_const_value) {
// In real world, lets say below line of code is a complex logic that needs to be tested by a unit test
return (value * 5) / 25;
}
如果您想保留原始签名,您也可以将其包装(如评论中所建议):
int GetValue_impl(int value) {
return (value * 5) / 25;
}
int GetValue() {
return GetValue_impl(my_const_value);
}
现在您可以测试 GetValue_impl
而 GetValue
使用常量。但是,我真的很奇怪你为什么要测试一个不可能发生的案例。
你问的是 hackish,这里是 :
// define the string const to be replaced by empty string
#define const
#include "header.hh"
#undefine const
...tests...
我看到的唯一问题是 1.all const 修饰符脱落,这可能是问题,也可能不是问题。 2. 它有点侵入性,正如其他人提到的那样,编译器以特定方式处理常量,因此您的测试并没有完全测试将 运行 在您的实际用例中使用的相同代码。
有一个类似的技巧,从 #define private public
开始,然后包括 header,用于从库中访问另一个 class 的私有字段。好消息是当你 link 在图书馆时它甚至不会中断。
请注意 none 这些东西是推荐的,它们是 hackish,但是利用预处理器来偏置包含的文件是可以的。它将清除 all const 修饰符,并在其他包含的 header 中传递,因此非常具有侵入性。
更简单的做法是拥有一个宏 TEST
并放入您的 header #ifdef TEST /*non const decl*/ #else /*const decl*/
。那么你显然在包含 header 之前执行 #define TEST
这比重新定义关键字更干净。
我知道您正在寻找一种方法来摆脱 const,但我可能会采用不同的方法。
您在评论中说:
Well. I have given my reason. I am testing the logic in
GetValue
. I have declaredmy_const_value
as aconst
but that can be changed from5
to something else in future when someone changes the value in future.
如果一个变量是 const
并且在没有传递给它的情况下参与函数内的表达式,那么这些更改通常不应该定期发生,也不应该被期望。如果您认为 myheader::my_const_value
是一个配置值,并且可能随时更改,那么它应该传递给在表达式中使用它的函数。
因此,从测试的角度来看,我同意
一个测试代码当前应该如何表现的测试(它应该有什么常量)
TEST(MyHeaderTest, Testing_Something1) {
EXPECT_EQ(5, myheader::my_const_value)
EXPECT_EQ(1, myheader::GetValue());
}
还有一个用于通用测试:
TEST(MyHeaderTest, Testing_Something2) {
EXPECT_EQ(1, myheader::GetValue_impl(5));
EXPECT_EQ(5, myheader::GetValue_impl(25));
// …
}
如果 GetValue
使用的计算有效,那么您就可以进行通用测试。还有一个,如果对于您当前版本的代码,myheader::GetValue()
的值是预期值。
嗨希望你做得很好。
只需在存根函数上方尝试#define const /* myComment */