如何解决对于单元测试,有没有办法改变const变量的值?
我有一个C ++ 11标头,它的const值声明为my_const_value
。还有一个名为GetValue
的函数,该函数使用const值运行复杂的逻辑并返回期望值。
我想使用不同的GetValue
值对my_const_value
进行单元测试。
我知道这是不可取的,但是对于编写GetValue
的单元测试,我希望使用不同的GetValue
值来测试my_const_value
。在C ++中,即使它是一个const,它也有某种改变形式的hack方式吗?
//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变量。但这对这里没有帮助。如果有人通过使用指针或其他方法来更改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时,才允许删除constness。听起来很奇怪吗?参见以下示例:
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
。但是,我真的很想知道为什么要测试不可能发生的情况。
我知道您正在寻找一种将const抛弃的方法,但我可能会采用另一种方法。
您在评论中说:
好吧。我已经给出了我的理由。我正在测试
srid
中的逻辑。我已经将GetValue
声明为my_const_value
,但是当将来有人更改值时,可以将其从const
更改为其他内容。
如果变量为5
,并且在不传递给函数的情况下参与了表达式,则通常不应定期进行这些更改,并且不应期望这些更改。如果您认为const
是一个配置值,并且该值可能随时更改,则应将其传递给用于表达式的函数。
因此,从测试的角度来看,我同意idclev 463035818的建议,将函数分为两部分,一个是可测试的部分,一个参数,另一个是使用常数。
一个测试,测试当前代码的行为(应该具有什么常数)
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
,则为期望值。
您要求破解,这里是:
// define the string const to be replaced by empty string
#define const
#include "header.hh"
#undefine const
...tests...
我看到的唯一问题是1.所有const修饰符都掉了,这可能不是问题。 2.它是一种侵入式的编译器,就像其他人提到的那样,编译器以特定的方式处理常量,因此您的测试不是完全测试将在实际用例中运行的相同代码。
有一个类似的技巧,它以#define private public
开头,然后包含标题,用于从库访问另一个类的私有字段。很好的是,当您链接到库时,它甚至不会中断。
请注意,不建议使用这些工具,它们都是 hackish ,但是利用预处理程序对包含的文件进行偏向是很好的。它将清除所有 const修饰符,并在其他包含的标头中传递,因此非常具有侵入性。
较少的骇客行为是拥有一个宏TEST
并将其放置在标题#ifdef TEST /*non const decl*/ #else /*const decl*/
中。然后,您显然会在添加包含比重新定义关键字更干净的标题之前进行#define TEST
。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。