Google Test(GTest)使用方法和源码解析——断言的使用方法和解析
在之前博文的基础上,我们将介绍部分断言的使用,同时穿插一些源码。(转载请指明出于breaksoftware的csdn博客)
断言(Assertions)
断言是GTest局部测试中最简单的使用方法,我们之前博文中举得例子都是使用断言去做判断的。
基础断言
我们先看一个基础的断言
Fatal assertion | Nonfatal assertion | Verifies |
ASSERT_TRUE(condition); | EXPECT_TRUE(condition); | condition is true |
ASSERT_FALSE(condition); | EXPECT_FALSE(condition); | condition is false |
GTest中断言都是成对出现的。即分为两个系列:
- ASSERT_*系列;
- EXPECT_*系列;
EXPECT_*系列是比较常用的。在一个测试特例中,如果局部测试使用了EXPECT_*系列函数,它将保证本次局部测试结果不会影响之后的流程。但是ASSERT_*系列在出错的情况下,当前测试特例中剩下的流程就不走了。
TEST(BaseCheck, Assert) {ASSERT_TRUE(1==1);ASSERT_TRUE(2==3);ASSERT_TRUE(3==3);
}
TEST(BaseCheck, Expect) {EXPECT_TRUE(1==1);EXPECT_TRUE(2==3);EXPECT_TRUE(3==3);
}
上面两个测试特例中,第二个局部测试都是不成立的。由于EXPECT_*不会影响执行流程,所以即使第8行出错,之后的流程(第9行)也执行了。但是ASSERT_*会影响,所以第3行出错后,第4行没有执行。那么GTest是如何做到的呢?我们对比下EXPECT_TRUE和ASSERT_TRUE的实现
#define EXPECT_TRUE(condition) \GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \GTEST_NONFATAL_FAILURE_)
#define ASSERT_TRUE(condition) \GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \GTEST_FATAL_FAILURE_)
可以见得,他们的区别就是在是出错时调用了GTEST_NONFATAL_FAILURE_还是GTEST_FATAL_FAILURE_
#define GTEST_FATAL_FAILURE_(message) \return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure)#define GTEST_NONFATAL_FAILURE_(message) \GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure)
这儿调用到《Google Test(GTest)使用方法和源码解析——结果统计机制分析》中介绍保存局部测试结果的宏——GTEST_MESSAGE_。但是这个不是重点,重点是GTEST_FATAL_FAILURE_宏调用了return——函数返回了。我们再看下GTEST_TEST_BOOLEAN_的实现
#define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \GTEST_AMBIGUOUS_ELSE_BLOCKER_ \if (const ::testing::AssertionResult gtest_ar_ = \::testing::AssertionResult(expression)) \; \else \fail(::testing::internal::GetBoolAssertionFailureMessage(\gtest_ar_, text, #actual, #expected).c_str())
在出错的情况下,ASSERT_*的else里return了。而EXPECT_*的else没有return。
二进制比较断言
GTest还提供了二进制对比宏
Fatal assertion | Nonfatal assertion | Verifies | 全称 |
ASSERT_EQ(val1,val2); | EXPECT_EQ(val1,val2); | val1 == val2 | equal |
ASSERT_NE(val1,val2); | EXPECT_NE(val1,val2); | val1 != val2 | not equal |
ASSERT_LT(val1,val2); | EXPECT_LT(val1,val2); | val1 < val2 | less than |
ASSERT_LE(val1,val2); | EXPECT_LE(val1,val2); | val1 <= val2 | less equal |
ASSERT_GT(val1,val2); | EXPECT_GT(val1,val2); | val1 > val2 | big than |
ASSERT_GE(val1,val2); | EXPECT_GE(val1,val2); | val1 >= val2 | big equal |
虽然宏很多,但是还是很好记,大家只要记住全称那列,就知道怎么对应关系了。我们再查看下二进制对比系列宏的ASSERT_*和EXPECT_*的区别(以EQ为例)
#define ASSERT_EQ(val1, val2) GTEST_ASSERT_EQ(val1, val2)
#define GTEST_ASSERT_EQ(val1, val2) \ASSERT_PRED_FORMAT2(::testing::internal:: \EqHelper<GTEST_IS_NULL_LITERAL_(val1)>::Compare, \val1, val2)
#define EXPECT_EQ(val1, val2) \EXPECT_PRED_FORMAT2(::testing::internal:: \EqHelper<GTEST_IS_NULL_LITERAL_(val1)>::Compare, \val1, val2)
// Binary predicate assertion macros.
#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_)
#define EXPECT_PRED2(pred, v1, v2) \GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_)
#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_)
#define ASSERT_PRED2(pred, v1, v2) \GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_)
可以见得它们和基本断言一样——EXPECT在失败的情况下没有return(失败时调用了GTEST_NONFATAL_FAILURE_),而ASSERT在失败的情况下return掉了(失败时调用了GTEST_FATAL_FAILURE_)。
一般来说二进制比较,都是对比其结构体所在内存的内容。C++大部分原生类型都是可以使用二进制对比的。但是对于自定义类型,我们就要定义一些操作符的行为,比如=、<等,我这儿就不举例了。
字符串对比断言
对于string类型,可以使用如下宏
Fatal assertion | Nonfatal assertion | Verifies | 全称 |
ASSERT_STREQ(str1,str2); | EXPECT_STREQ(str1,_str_2); | the two C strings have the same content | string equal |
ASSERT_STRNE(str1,str2); | EXPECT_STRNE(str1,str2); | the two C strings have different content | string not equal |
ASSERT_STRCASEEQ(str1,str2); | EXPECT_STRCASEEQ(str1,str2); | the two C strings have the same content, ignoring case | string (ignoring) case equal |
ASSERT_STRCASENE(str1,str2); | EXPECT_STRCASENE(str1,str2); | the two C strings have different content, ignoring case | string (ignoring) case not euqal |
在源码上,string对比宏和二进制对比只是在对比函数的选择上有差异,以Equal为例
#define EXPECT_EQ(val1, val2) \EXPECT_PRED_FORMAT2(::testing::internal:: \EqHelper<GTEST_IS_NULL_LITERAL_(val1)>::Compare, \val1, val2)
#define EXPECT_STREQ(s1, s2) \EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, s1, s2)
浮点对比断言
在对比数据方面,我们往往会讨论到浮点数的对比。因为在一些情况下,浮点数的计算精度将影响对比结果,所以这块都会单独拿出来说。GTest对于浮点数的对比也是单独的
Fatal assertion | Nonfatal assertion | Verifies |
ASSERT_FLOAT_EQ(val1, val2); | EXPECT_FLOAT_EQ(val1, val2); | the two float values are almost equal |
ASSERT_DOUBLE_EQ(val1, val2); | EXPECT_DOUBLE_EQ(val1, val2); | the two double values are almost equal |
almost euqal表示两个数只是近似相似,默认的是是指两者的差值在4ULP之内(Units in the Last Place)。我们还可以自己制定精度
Fatal assertion | Nonfatal assertion | Verifies |
ASSERT_NEAR(val1, val2, abs_error); | EXPECT_NEAR(val1, val2, abs_error); | the difference between val1 and val2 doesn't exceed the given absolute error |
使用方法是
ASSERT_NEAR(-1.0f, -1.1f, 0.2f);ASSERT_NEAR(2.0f, 3.0f, 1.0f);
对于浮点数的比较,感兴趣的同学可以查看下GTest的源码,还是有点意思的。
成功失败断言
该类断言用于直接标记是否成功或者失败。可以使用SUCCEED()宏标记成功,使用FAIL()宏标记致命错误(同ASSERT_*),ADD_FAILURE()宏标记非致命错误(同EXPECT_*)。举个例子
if (Check) {SUCCEED();
}
else {FAIL();
}
我们直接在自己的判断下设置断言。这儿有个地方需要说一下,SUCCEED()宏会调用GTEST_MESSAGE_AT_宏,从而会影响TestResult的test_part_results结构体,这也是唯一的成功情况下影响该结构体的地方。详细的分析可以见《Google Test(GTest)使用方法和源码解析——结果统计机制分析》。
类型对比断言
该类断言只有一个::testing::StaticAssertTypeEq<T, T>()。当类型相同时,它不会执行任何内容。如果不同则会引起编译错误。但是需要注意的是,要使代码触发编译器推导类型,否则也会发生编译错误。如
template <typename T> class Foo {public:void Bar() { ::testing::StaticAssertTypeEq<int, T>(); }
};
如下的代码就不会引起编译冲突
void Test1() { Foo<bool> foo; }
但是下面的代码由于引发了编译器的类型推导,所以会触发编译错误
void Test2() { Foo<bool> foo; foo.Bar(); }
异常断言
异常断言是在断言中接收一定类型的异常,并转换成断言形式。它有如下几种
Fatal assertion | Nonfatal assertion | Verifies |
ASSERT_THROW(statement, exception_type); | EXPECT_THROW(statement, exception_type); | statement throws an exception of the given type |
ASSERT_ANY_THROW(statement); | EXPECT_ANY_THROW(statement); | statement throws an exception of any type |
ASSERT_NO_THROW(statement); | EXPECT_NO_THROW(statement); | statement doesn't throw any exception |
我们举一个例子
void ThrowException(int n) {switch (n) {case 0:throw 0;case 1:throw "const char*";case 2:throw 1.1f;case 3:return;}
}TEST(ThrowException, Check) {EXPECT_THROW(ThrowException(0), int);EXPECT_THROW(ThrowException(1), const char*);ASSERT_ANY_THROW(ThrowException(2)); ASSERT_NO_THROW(ThrowException(3));
}
这组测试特例中,我们预期ThrowException在传入0时,会返回int型异常;传入1时,会返回const char*异常。传入2时,会返回异常,但是异常类型我们并不关心。传入3时,不返回任何异常。当然ThrowExeception的实现也是按以上预期设计的。
我们看下源码,我们只看ASSERT_型的,EXPECT_型和ASSERT_型的区别在前文很多次讲到,所以不再罗列代码了。
#define ASSERT_THROW(statement, expected_exception) \GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_)
#define ASSERT_NO_THROW(statement) \GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_)
#define ASSERT_ANY_THROW(statement) \GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_)
我们先看最简单的GTEST_TEST_NO_THROW_的实现
#define GTEST_TEST_NO_THROW_(statement, fail) \GTEST_AMBIGUOUS_ELSE_BLOCKER_ \if (::testing::internal::AlwaysTrue()) { \try { \GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \} \catch (...) { \goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \} \} else \GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \fail("Expected: " #statement " doesn't throw an exception.\n" \" Actual: it throws.")
只要表达式抛出异常,就会goto到else中进行错误处理。
再看下GTEST_TEST_ANY_THROW_的实现
#define GTEST_TEST_ANY_THROW_(statement, fail) \GTEST_AMBIGUOUS_ELSE_BLOCKER_ \if (::testing::internal::AlwaysTrue()) { \bool gtest_caught_any = false; \try { \GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \} \catch (...) { \gtest_caught_any = true; \} \if (!gtest_caught_any) { \goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \} \} else \GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \fail("Expected: " #statement " throws an exception.\n" \" Actual: it doesn't.")
只要抛出异常,就认为是正确的。否则goto到else代码中进行错误处理。
再看下稍微复杂点的GTEST_TEST_THROW_
#define GTEST_TEST_THROW_(statement, expected_exception, fail) \GTEST_AMBIGUOUS_ELSE_BLOCKER_ \if (::testing::internal::ConstCharPtr gtest_msg = "") { \bool gtest_caught_expected = false; \try { \GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \} \catch (expected_exception const&) { \gtest_caught_expected = true; \} \catch (...) { \gtest_msg.value = \"Expected: " #statement " throws an exception of type " \#expected_exception ".\n Actual: it throws a different type."; \goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \} \if (!gtest_caught_expected) { \gtest_msg.value = \"Expected: " #statement " throws an exception of type " \#expected_exception ".\n Actual: it throws nothing."; \goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \} \} else \GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \fail(gtest_msg.value)
只有接收到了传入的特定类型的异常,否则都会goto到else代码中进行错误处理。
参数名输出断言
在之前的介绍的断言中,如果在出错的情况下,我们会对局部测试相关信息进行输出,但是并不涉及其可能传入的参数。参数名输出断言,可以把参数名和对应的值给输出出来。
Fatal assertion | Nonfatal assertion | Verifies |
ASSERT_PRED1(pred1, val1); | EXPECT_PRED1(pred1, val1); | pred1(val1) returns true |
ASSERT_PRED2(pred2, val1, val2); | EXPECT_PRED2(pred2, val1, val2); | pred2(val1, val2) returns true |
... | ... | ... |
目前版本的GTest支持5个参数的版本ASSERT/EXPECT_PRED5宏。其使用方法是
template <typename T1, typename T2>
bool GreaterThan(T1 x1, T2 x2) {return x1 > x2;
}
TEST(PredicateAssertionTest, AcceptsTemplateFunction) {int a = 5;int b = 6;ASSERT_PRED2((GreaterThan<int, int>), a, b);
}
其输出是
error: (GreaterThan<int, int>)(a, b) evaluates to false, where
a evaluates to 5
b evaluates to 6
其源码也没什么太多奥秘,只是简单的把结果输出
template <typename Pred,typename T1,typename T2>
AssertionResult AssertPred2Helper(const char* pred_text,const char* e1,const char* e2,Pred pred,const T1& v1,const T2& v2) {if (pred(v1, v2)) return AssertionSuccess();return AssertionFailure() << pred_text << "("<< e1 << ", "<< e2 << ") evaluates to false, where"<< "\n" << e1 << " evaluates to " << v1<< "\n" << e2 << " evaluates to " << v2;
}
这儿需要注意的是,判断的表达式可以使用if语句判断返回结果,所以最好是bool类型。
子过程中使用断言
经过之前的分析,我们可以想到,如果子过程中使用了断言,则结果输出只会指向子过程,而不会指向父过程中的某个调用。为了便于阅读我们可以使用SCOPED_TRACE宏去标记下位置
void Sub(int n) {ASSERT_EQ(1, n);
}TEST(SubTest, Test1) {{SCOPED_TRACE("A");Sub(2);}Sub(3);
}
其结果输出时标记了下A这行位置,可见如果没有这个标记,是很难区分出是哪个Sub失败的。
..\test\gtest_unittest.cc(87): error: Expected: 1
To be equal to: nWhich is: 2
Google Test trace:
..\test\gtest_unittest.cc(92): A
..\test\gtest_unittest.cc(87): error: Expected: 1
To be equal to: nWhich is: 3
我们再注意下Sub的实现,其使用了ASSERT_EQ断言,该断言并不会影响Test1测试特例的运行,其原因我们在之前做过分析了。为了消除这种可能存在的误解,GTest推荐使用在子过程中使用ASSERT/EXPECT_NO_FATAL_FAILURE(statement);
如果父过程一定要在子过程发生错误时退出怎么办?我们可以使用::testing::Test::HasFatalFailure()去判断当前线程中是否产生过错误。
TEST(SubTest, Test1) {{SCOPED_TRACE("A");Sub(2);}if (::testing::Test::HasFatalFailure())return;Sub(3);
}
相关文章:

精品软件 推荐 硬盘物理序列号修改专家
硬盘物理序列号修改专家不是市面上那些简单修改硬盘驱动器的序列号的东西,而是修改硬盘厂商在烧制时刻录在硬盘盒上的,即(硬盘物理序列号),大约20位字母数字的组合1、可以解决部分软件封用户电脑,导致这台电…
知识图谱实体链接是什么?一份“由浅入深”的综述
作者 | 尼古拉瓦砾来源 | Paperweekly(ID:paperweekly)【导读】这个世界充斥着无数的结构化数据(wiki)和非结构化数据(web),然而,如何将两者有效地集成仍然是个非常困难的问题。本文…

Google Test(GTest)使用方法和源码解析——预处理技术分析和应用
预处理 在《Google Test(GTest)使用方法和源码解析——概况》最后一部分,我们介绍了GTest的预处理特性。现在我们就详细介绍该特性的使用和相关源码。(转载请指明出于breaksoftware的csdn博客) 测试特例级别预处理 Test Fixtures是建立一个固…

出色管理者的时间管理
出色管理者的时间管理不少管理者都有这样的感慨:“忙了一天,也不知道忙了什么,时间还不够用。”其实,只要有效地运用时间,就可以提高工作效率,在相同的时间里做更多的事,而且做得更好࿰…

精品软件 推荐 瑞星 杀毒软件 安全软件
一句话评价一下这软件: 功能好,速度一般。功能:设置中心:最后, 下载地址请到官方下载吧。转载于:https://blog.51cto.com/hangtc/1690981

Google Test(GTest)使用方法和源码解析——自定义输出技术的分析和应用
在介绍自定义输出机制之前,我们先了解下AssertResult类型函数。(转载请指明出于breaksoftware的csdn博客) 在函数中使用AssertionResult AssertionResult只有两种类型: AssertionSuccess()AssertionFailure()要么成功࿰…
五年循环期限已到,我们又要步入“AI寒冬”了吗?
作者 | Sam Shead译者 | Kolen编辑 | 夕颜出品 | AI科技大本营(ID: rgznai100) 【导读】过去的十年对人工智能来说是一个重要的十年,但该领域的研究人员认为该行业即将进入一个新的阶段。 过去几年里,人工智能这项技术的…

相知用心.相爱用情
人如花 一生匆匆而过 不要等到你凋落的时候才去眷恋天空,眷恋蝴蝶爱情是短暂的,但却是美丽的该追求的就去追求吧不要留给自己遗憾,不要让自己美丽的花朵枯萎 人生就象一列急驰的火车 机遇和缘分会让许多素昧平生的乘客在旅途中相遇、相识、相…

Android:problem opening wizard the selected wizard could not be started
直接将Eclipse关掉,重新打开后也许就好了。 如还没好,就执行如下步骤: 1.如果还没有添加ADT,则:Help -> Add New Software -> Add 在“Name”中填入ADT。 2.如果已经安装了ADT,就直接将ADT的地址填写…

Google Test(GTest)使用方法和源码解析——私有属性代码测试技术分析
有些时候,我们不仅要测试类暴露出来的公有方法,还要测试其受保护的或者私有方法。GTest测试框架提供了一种方法,让我们可以测试类的私有方法。但是这是一种侵入式的,会破坏原来代码的结构,所以我觉得还是谨慎使用。&am…
170个新项目,579个活跃代码仓库,Facebook开源年度回顾
作者 | Dmitry Vinnik译者 | 泓礼编辑 | 夕颜出品 | AI科技大本营(ID:rgznai100) 【导读】过去一年对于Facebook的开源工程师来说是繁忙的一年。在2019年,Facebook发布了170个新的开源项目,活跃代码仓库产品达到了579…

“怀才不遇”与“怀才不孕”怎么办?
今天在飞机上闲来无事,翻阅深航的随机杂志。一直以来,我乘的比较多的是南航和深航的杂志。南航的杂志基本上都是广告,没有一点可读性的内容。相反,不知道是不是深航的规模较小的原因,找不到合适的广告主吧,…

《评人工智能如何走向新阶段》后记(再续15)
由AI科技大本营下载自视觉中国170. 清华大学全球产业研究院和百度大学Alpha学院于2020年1月5日发表(人工智能)产业智能化白皮书讨论AI发展情况,应用TUMC模型,从技术和综合应用场景的角度,考察热点技术和场景的AI产业化…

Google Test(GTest)使用方法和源码解析——参数自动填充技术分析和应用
在我们设计测试用例时,我们需要考虑很多场景。每个场景都可能要细致地考虑到到各个参数的选择。比如我们希望使用函数IsPrime检测10000以内字的数字,难道我们要写一万行代码么?(转载请指明出于breaksoftware的csdn博客)…

Linux 指令篇:文件系统--fstab
Linux 指令篇:文件系统-----FSTAB指令:FSTAB使用权限 : 超级使用者 使用方式 : 使用编辑器来修改 /etc/fstab (eg. vi /etc/fstab) 说明 : 存放档案系统与目录结构对应资料的档案 fstab 栏位说明: 第一栏(fs_spec): 实际的 device…

跨平台抓包软件,可以替代Fiddler
2019独角兽企业重金招聘Python工程师标准>>> Zed Attack Proxy (ZAP) 是个强大的跨平台的抓包工具,可以用来替代windows下的Fiddler https://www.owasp.org/index.php/OWASP_Zed_Attack_Proxy_Project https://github.com/zaproxy/zaproxy/wiki/Download…
集五福,我用Python
所有参与投票的 CSDN 用户都参加抽奖活动群内公布奖项,还有更多福利赠送作者 | Crossin先生编辑 | Jane来源 | Crossin的编程教室(ID:crossincode)【导读】你的五福集齐了吗?作为一名技术人,我们是不是可以…

Google Test(GTest)使用方法和源码解析——模板类测试技术分析和应用
写C难免会遇到模板问题,如果要针对一个模板类进行测试,似乎之前博文中介绍的方式只能傻乎乎的一个一个特化类型后再进行测试。其实GTest提供了两种测试模板类的方法,本文我们将介绍方法的使用,并分析其实现原理。(转载…

IT人才职场受宠
面对就业压力的日益增大,就业难,工资水平低等问题困扰着所有的大学生。然而,IT业的迅猛发展却造成了数以万计的网络设计、运行、维护的网络工程师需求的空缺,巨大的人才缺口使得IT业“全线告急”,这也促使更多的研究人…

引用头文件#include queue出错
为什么80%的码农都做不了架构师?>>> 在工程头文件中引用头文件 #include <queue> 莫名奇妙出错,其原因很可能是由于头文件引用问题。 include/c/4.7.1/bits/stl_vector.h:1308:40: error: expected unqualified-id before ‘(’ token…

ZOJ1002 Fire Net(非递归版)
以前用递归的回溯搜索思路做过一次,参见ZOJ1002 Fire Net(递归版),今天想着用非递归的方法试试看,呵呵,比我想象中要难啊,主要还是堆栈里究竟放什么,这一点上思路一直没理清。因此用了整整一天的时间&#…
“数学不行,干啥也不行”骨灰级程序员:其实你们都是瞎努力
编程圈一直都流传着一个段子:一流程序员靠数学,二流程序员靠算法,末端程序员靠百度,低端看高端就是黑魔法。懂的人其实都知道,这不是段子,其实就是程序员的真实写照。想一想,我们日常学习、求职…

Google Test(GTest)使用方法和源码解析——死亡测试技术分析和应用
死亡测试是为了判断一段逻辑是否会导致进程退出而设计的。这种场景并不常见,但是GTest依然为我们设计了这个功能。我们先看下其应用实例。(转载请指明出于breaksoftware的csdn博客) 死亡测试技术应用 我们可以使用TEST声明并注册一个简单的测…
java学习笔记11--Annotation
java学习笔记11--Annotation Annotation:在JDK1.5之后增加的一个新特性,这种特性被称为元数据特性,在JDK1.5之后称为注释,即:使用注释的方式加入一些程序的信息。 java.lang.annotation Annotation接口是所有的Annotat…

GoogleLog(GLog)源码分析
GLog是Google开发的一套日志输出框架。由于其具有功能强大、方便使用等特性,它被众多开源项目使用。本文将通过分析其源码,解析Glog实现的过程。 该框架的源码在https://github.com/google/glog上可以获取到。本文将以目前最新的0.3.3版本源码为范例进行…

Ajax Toolkit 控件学习系列(13) ——FilteredTextBoxExtender 控制输入
这个控件的作用是对TextBox所要输入的内容进行过滤控制。按照自己需要过滤,可以自定义,再或者使用定义好的方式。看效果。效果不是很突出,说明下,就是只能输入大写字母和数字。因为加了限制,但是具体有什么高深的应用呢…
Uber最新开源Manifold,助力机器学习开发者的可视化与调试需求
所有参与投票的 CSDN 用户都参加抽奖活动群内公布奖项,还有更多福利赠送作者 | Lezhi Li译者 | 凯隐编辑 | Jane出品 | AI科技大本营(ID:rgznai100)【导语】2019 年 1 月,Uber 推出了 Manifold,一款与模型无…

jQuery对象和DOM对象使用说明
1.jQuery对象和DOM对象第一次学习jQuery,经常分辨不清哪些是jQuery对象,哪些是 DOM对象,因此需要重点了解jQuery对象和DOM对象以及它们之间的关系.DOM对象,即是我们用传统的方法(javascript)获得的对象,jQuery对象即是用jQuery类库…

[WPF疑难]避免窗口最大化时遮盖任务栏
[WPF疑难]避免窗口最大化时遮盖任务栏 周银辉 WPF窗口最大化时有个很不好的现象是:如果窗口的WindowStyle被直接或间接地设置为None后(比如很多情况下你会覆盖默认的窗体样式,即不采用Windows默认的边框和最大化最等按钮,来打造个…

Google Mock(Gmock)简单使用和源码分析——简单使用
初识Gmock是之前分析GTest源码时,它的源码和GTest源码在同一个代码仓库中(https://github.com/google/googletest)。本文我将以目前最新的Gmock1.7版本为范例,分析其实现原理。(转载请指明出于breaksoftware的csdn博客…