当前位置:网站首页>Tips of this week 135: test the contract instead of implementation

Tips of this week 135: test the contract instead of implementation

2022-07-07 17:54:00 -Flying crane-

As TotW#135 Originally published in 2017 year 6 month 5 Japan

from James Dennett A literary creation

“ If you have a true friend , Then you have more than what you have ”—— Thomas · Fuller

C++ One uses public , The protection of , Private and friend detailed access control mechanisms . The test code has its own rules for using these devices ,GoogleTest Use it FRIEND_TEST Macros to expand them . Use FRIEND_TEST It should be the last resort , Not a priority .

Test Convention

We write tests to find errors in the implementation of component conventions , Or let us have enough confidence to believe that there is no such mistake . Using test driven development (TDD) when , We also write tests to help us design conventions . Tests that rely on unspecified content of components are fragile , Even if the production code works properly , It is also easy to report failure .

Give priority to testing through the public interface of components . More generally speaking , Tests should verify the conventions of components , And like any other client , No assumptions should be made that exceed the guarantee .

Provide technology from test access

Many techniques can be used to allow test code the necessary access to complete its work . Here are some , Roughly from good to bad .

Add public API

When testing through the smallest interface , Sometimes it's hard to get enough coverage . If your component is implementing a very narrow interface specified by the base class ( for example , only one ProcessItem Interface of virtual function ) And it is unrealistic to gain enough confidence from tests that only use this interface , Please consider creating a new 、 Testable components , Including implementation details . Then classes containing virtual functions can be very simple , Only minimal testing is required . BUILD Visibility can be used to limit the use of your implementation classes ( If necessary and your build system supports it ).

If the test depends only on oneortwo private functions , Consider these functions as part of the public interface . It's not bad : in any case , You all need them to have clearly documented interfaces , And other clients ( It's not just testing ) You may find them very useful . If after considering , You decide that a function is really only used for testing , Then it should be recorded , And may be ForTesting Suffix naming .

Use peers to avoid exposing implementations

If the test still needs access to private implementation details , Please create a test peer ( Sometimes called test pairing ). The test peer is a friend class of the tested class , Usually in _test.cc The document defines ( Although some people prefer to define it in the same file as the friend class ), And the test code used to provide controlled access to the class to be tested . Test peers will not exist in anonymous namespaces , Because its exact name needs to match the friend declaration , But the rest of the test code can be in anonymous namespaces as usual . The name of the test peer class is usually Peer ending .

The last resort : Use FRIEND_TEST

Although it is very common in old code , however FRIEND_TEST Should not be used in new code . It introduces reverse coupling , Make the production code header file dependent on the details of the relevant unit tests . It forces tests to move out of anonymous namespaces . Every FRIEND_TEST Both grant a test function unrestricted access to the class under test ; In long test functions , It is difficult to find out where the test modifies the state of the class under test . It requires the use of GoogleTest Provide an unusual header file to include in the production code , But almost all GoogleTest For testing only . Finally, its scalability is very poor , When adding new tests, you need to add new FRIEND_TEST Add to the header file of production . In practice , This usually leads to long header files FRINED_TEST block .

Don't let the whole testing device become friends

It is strongly recommended not to make the entire test device a class to be tested ( With friend class MyClassTest) Friends . Compare with the above options , It allows the entire test setup ( But not the test itself , They are subclasses of test devices ) Unrestricted and uncommented access to each member of the class under test , This means that the reader testing the code has no visible clues about when to break the package . It also forces the test device to be outside the anonymous namespace . Compared with friend devices , Testing peers makes the code more self explanatory , And the code author only needs to spend a little extra work .

Summary of recommendations

  • Test the client interface of components first , And ensure that the test is independent of the details of the private implementation .
  • If the client interface does not meet the requirements of completely running the unit to be tested , Will be testable , The sub components that may only be used for testing are decomposed .
  • Sometimes it makes sense to add to public interfaces to make components testable .
  • If necessary, , Please use the test peer instead of FRIEND_TEST Access private members from tests .
  • Don't pretend to be friends with the whole test . Use one of the more targeted methods mentioned above .
原网站

版权声明
本文为[-Flying crane-]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/188/202207071522592237.html