长亭百川云 - 文章详情

聊聊Google的工程实践(三):软件测试篇

技艺丛谈

63

2024-07-13

在《聊聊Google的工程实践(一)》,《聊聊Google的工程实践(二)》中,我们分享了代码仓库管理、构建系统、代码审查三个话题,有关Google的几本书,以及谷歌工程师的几个公众号。

这篇我们来继续分享软件测试这个话题。

Google的软件测试在业界是非常出名的,在上篇文章中,我们也介绍了Gtest的作者是华人。Gtest和GMock 在谷歌内部被广泛使用,

先说为什么软件需要测试?我认为有几个原因:

1,代码和bug几乎是伴生关系,再好的代码,也难免出问题。测试可以预防出现bug.

2,写实现代码,和写测试代码,有时候考虑事情的视角不同。这就和有了开发工程师的同时,也存在测试工程师一个道理。当我们编写测试代码时,我们更多地考虑边界条件,极端条件等,因此,在我们编写实现代码的时候,也有助于我们更好地处理边界问题。

3,测试代码一定程度上可以看成是教程,可以让使用者快速熟悉代码的接口,各种主要的接口和使用场景,使用方式。

4,在代码重构的时候,如果有足够多的测试代码,我们进行重构就比较大胆,敢于放手去做。我曾经重构过一个非常大的项目,好几万行的代码,但是几乎没有测试用例,代码的风格不说,代码的质量还比较糟糕,这时候就非常痛苦了,绝大部分人这时候会有心无力,无从下手,有一些还不错的人,会选择重写而不是重构。当时我的选择是,先引入Gtest,编写了一些单元测试用例,然后再进行大刀阔斧的重构。

5,用来保障依赖的代码不会引入新的问题,或者是行为的不同。比如,我们结合Jenkins等工具,定期编译主要的target,并且执行单元测试,就可以检测到一些依赖的库变更了,引入的新bug。这时候如果执行测试泄露检测,还可以预防一些内存泄露问题。因为这个原因,所以基础库的编写者,一般需要去编写更多的测试用例,并且在编译工具中,引入类似bazel这样的编译工具,以在提交基础代码的时候,能够编译所有依赖它的build target会不会被break。

那么,在那么多的单元测试框架中,我们为什么要选择Gtest呢?我们来看看谷歌官方对Gtest功能的介绍。

  • An xUnit test framework.(xUnit is the collective name for several unit testing frameworks that derive their structure and functionality from Smalltalk's SUnit)

  • Test discovery.

  • A rich set of assertions.(断言丰富)

  • User-defined assertions.(支持用户自定义断言)

  • Death tests.(死亡测试)

  • Fatal and non-fatal failures.(区分严重和不严重的测试失败)

  • Value-parameterized tests.

  • Type-parameterized tests.

  • Various options for running the tests.(提供了不同的参数以运行测试)

  • XML test report generation.(可生成XML格式的测试报告)

解释下几个概念:

Death tests.(死亡测试):In many applications, there are assertions that can cause application failure if a condition is not met. These sanity checks, which ensure that the program is in a known good state, are there to fail at the earliest possible time after some program state is corrupted. If the assertion checks the wrong condition, then the program may proceed in an erroneous state, which could lead to memory corruption, security holes, or worse. Hence it is vitally important to test that such assertion statements work as expected.

Value-parameterized testsValue-parameterized tests allow you to test your code with different parameters without writing multiple copies of the same test. This is useful in a number of situations, for example:

  • You have a piece of code whose behavior is affected by one or more command-line flags. You want to make sure your code performs correctly for various values of those flags.

  • You want to test different implementations of an OO interface.

  • You want to test your code over various inputs (a.k.a. data-driven testing). This feature is easy to abuse, so please exercise your good sense when doing it!

Type-parameterized tests:Sometimes, however, you don't yet know all the types that you want to test when you write the tests.  For example, if you are the author of an interface and expect other people to implement it, you might want to write a set of tests to make sure each implementation conforms to some basic requirements, but you don't know what mplementations will be written in the future.

How can you write the tests without committing to the type parameters?  That's what "type-parameterized tests" can do for you.

以下是最新的Gtest高级用法的介绍,

https://github.com/google/googletest/blob/master/googletest/docs/advanced.md

大概看了下,发现我自己掌握的也只是其中一部分,可见Gtest的功能是多么强大。

那么Gmock又是干什么的呢?还是来看一下官方的解释吧:

Google's framework for writing and using C++ mock classes. It can help you derive better designs of your system and write better tests.

It is inspired by:

  • jMock

  • EasyMock

  • Hamcrest

It is designed with C++'s specifics in mind.

gMock:

  • Provides a declarative syntax for defining mocks.

  • Can define partial (hybrid) mocks, which are a cross of real and mock objects.

  • Handles functions of arbitrary types and overloaded functions.

  • Comes with a rich set of matchers for validating function arguments.

  • Uses an intuitive syntax for controlling the behavior of a mock.

  • Does automatic verification of expectations (no record-and-replay needed).

  • Allows arbitrary (partial) ordering constraints on function calls to be expressed.

  • Lets a user extend it by defining new matchers and actions.

  • Does not use exceptions.

  • Is easy to learn and use.

不过Gmock的使用没有Gtest广泛,写起来也比较专业。在我过往的实际开发中,使用的频率也不算高。

几个总结:

1,软件测试是非常有价值的,不仅对测试工程师是必备技能,对开发工程师亦然。

2,测试驱动开发的理论和书籍,值得开发工程师去研究下。推荐下《测试驱动开发》这本书。有测试工程师的思维模式,对编写高质量的代码有帮助。当然,有产品经理的思维模式,对编写高质量可维护的代码也有帮助。

3,Gtest和Gmock值得广大C++工程师学习和使用。

4,很多工程师还没写过测试代码。

5,大部分工程师还不太会写测试代码。我面试过大量的工程师,工作中有过编写单元测试经验的不算多。而在我接触过的工程师里,能把单元测试写得比较好的,更是少见。

6,测试和重构有较大相关性。推荐看一些重构的书籍,这里推荐下《重构》这本书。

7,写测试框架也是很有含金量的。比如编写Gtest的作者,也就是上篇文章里介绍的老万,听说很早就是Google Staff工程师了,薪资不会低。

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2