assert的用法简析
1 软件验证、测试宏assert
C/C++本身仅提供了有限的软件验证、测试宏assert,而Boost.assert库增强了assert库,包含如下的组件
- assert —>运行时检查
- static_assert —>编译时检查 已被C++17收录
- lightweight_test —>提供最基本的单元测试功能
- test —>既提供最基本的单元测试功能,又提供测试用例、测试套件等整个体系
2 assert运行时断言
BOOST_ASSERT等同于assert宏,断言为假发生异常。它还有一个特点
1. BOOST_ASSERT只会在Debug模式生效,在Release下不会进行编译。
# define BOOST_ASSERT(expr) assert(expr)
# define BOOST_ASSERT_MSG(expr, msg) assert((expr)&&(msg))
案例:
double fun(int x)
{
BOOST_ASSERT_MSG(x != 0, "divided by zero");
std::cout << "boost_assert: " << std::endl;
return 1.0 / x;
}
断言失败时候的输出:
double fun(int): Assertion `(x != 0)&&("divided by zero")' failed.
2.1 禁用BOOST_ASSERT
如果引入了boost的assert,但是任然想用C++的assert,在头文件前增加如下代码
#define BOOST_DISABLE_ASSERTS
通过查看代码可知,其实是让BOOST_ASSERT
和BOOST_ASSERT_MSG
失效,即((void)0)
,将激活如下代码
# define BOOST_ASSERT(expr) ((void)0)
# define BOOST_ASSERT_MSG(expr, msg) ((void)0)
案例,这时候BOOST_ASSERT_MSG
已经失效了哈。
double fun(int x)
{
// 使用宏失效
BOOST_ASSERT_MSG(x != 0, "divided by zero");
std::cout << "boost_assert: " << std::endl;
// 有效
assert(x != 0 && "divided by zero");
std::cout << "asssert: " << std::endl;
return 1.0 / x;
}
2.2 自定义assert?
Boost.asssert提供很大的灵活性,程序员可以在出错的时候给出出错原因、文件名、行号、函数名
。只需要在文件开始处提供如下代码,不过它带来一个缺点
- 断言表达式无论在Debug,还是release下都要求值!!!
#define BOOST_ENABLE_ASSERT_HANDLER
进而,会自动激活assertion_failed()
和assertion_failed_msg()
这两个函数,因此,下面是一个Demo
#define BOOST_ENABLE_ASSERT_HANDLER
#include <iostream>
#include <boost/assert.hpp>
#include <boost/format.hpp>
namespace boost{
void assertion_failed(char const * expr, char const * function, char const * file, long line) // user defined
{
boost::format fmt("Assertion failed!\nExpression: %s\n"
"Function: %s\nFile: %s\nLine: %ld\n\n");
fmt % expr % function % file % line;
std::cout << fmt;
}
void assertion_failed_msg(char const * expr, char const * msg, char const * function, char const * file, long line) // user defined
{
boost::format fmt("Assertion failed!\nExpression: %s\n"
"Function: %s\nFile: %s\nLine: %ld\n"
"Msg: %s\n\n");
fmt % expr % function % file % line % msg;
std::cout << fmt;
}
}
注意:
- 上面两个函数都应该写在boost库下
- expr是错误表达式、function是函数名、msg是错误信息、file是文件名、line是行号
- 这里使用的是format库,有机会在介绍,其实它很像printf(),尤其是%的使用,也是一摸一样的
如何调用呢?和上面两个是对应的
1. BOOST_ASSERT() 自动调用assertion_failed()
2. BOOST_ASSERT_MSG() 自动调用assertion_failed_msg()
一个案例输出
Assertion failed!
Expression: x != 0
Function: double fun(int)
File: /home/topeet/myBoost/chap6_assert/_6_1_3.cpp
Line: 27
3 static_assert编译时检查
static_assert表示在编译时就会进行断言,因此运行时不存在这个问题,这个对Debug和Release都不会有任何影响。
头文件是:
#include <boost/static_assert.hpp>
同理,也有两个宏,其中一个支持输出错误信息
BOOST_STATIC_ASSERT(expr)
BOOST_STATIC_ASSERT_MSG(expr, msg)
下面是一个案例
template <typename T>
T my_min(T a, T b)
{
BOOST_STATIC_ASSERT_MSG(sizeof(T) < sizeof(int), "only short or char");
return a < b ? a : b;
}
测试代码
// 主函数,一个测试代码
std::cout << my_min((short)1, (short)3) << std::endl;
std::cout << my_min((long)1, (long)3) << std::endl; // error 不管是什么编译器,long>=int,这是硬性规定
输出代码,编译直接报错
In instantiation of ‘T my_min(T, T) [with T = long int]’:
required from here
static assertion failed: only short or char
BOOST_STATIC_ASSERT_MSG(sizeof(T) < sizeof(int), "only short or char");
4 总结static_assert和assert
逐步运行和比较输出,你会很清楚的发现,如下规律
- static_assert是编译就会发现错误,assert是在运行时才会发现。
- 同时提供了两个函数,一个不带MSG,一个带有MSG。
- 提供一个自定义的assert,方便给出给出
出错原因、文件名、行号、函数名
5 lightweight_test提供最基本的单元测试功能
你是否希望有如下的宏
BOOST_TEST(e) 断言是否成立
BOOST_TEST_NOT(e) 断言是否不成立
BOOST_ERROR(e) 断言失败输出错误信息s
BOOST_TEST_EQ(e1, e2) 断言e1==e2?
BOOST_TEST_NE(e1, e2) 断言e1!=e2?
BOOST_TEST_THROWS(e, eX) 断言失败,抛出异常
同时提供两个C-style语法的断言
BOOST_TEST_CSTR_EQ(e1, e2) 断言e1==e2?
BOOST_TEST_CSTR_NE(e1, e2) 断言e1!=e2?
无疑,lightweight_test组件给我们提供了完整的测试方案,你只需要包含头文件
#include <boost/core/lightweight_test.hpp>
注意的,必须用boost::report_errors()
作为返回值,不然会发生异常
下面用shared_ptr做了一个简单的测试,
{
// 一个简单的测试用例
boost::shared_ptr<int> p = boost::make_shared<int>(10);
BOOST_TEST(*p == 10);
BOOST_TEST(p.unique());
BOOST_TEST_NOT(!p);
BOOST_TEST_EQ(p.use_count(), 1);
BOOST_TEST_NE(*p, 20);
BOOST_ERROR("ERROR ACCURED!!!"); // error
}
return boost::report_errors();
输出如下
ERROR ACCURED!!! in function 'int main(int, char**)'
2 errors detected.
boost::report_errors()?
答:总结和报告错误,必须加上。至于是否加在返回值,其实无所谓,只要在返回值前即可。否则编译错误!!!
6 test组件
其实前面的组件丰富了C++的assert的功能,从测试角度将,这并不完整,因此test库填充了这个缺口,也像其他语言支持大型的测试工作。
Boost C++测试组件test库
https://blog.csdn.net/weixin_39956356/article/details/111385774