Test private members of a class using gtest

Source: Internet
Author: User

Write unit tests using frameworks such as gtest and cppunit.CodeOne of the most common problems is the test and verification of class private members. Ideally, we hope that all the data and methods in the class can be accessed during the test. In the product code, we only expose the implemented interface.

The gtest official document also mentions the handling of private members. There are two methods: one is to use the friend keyword to obtain trust, and the other is to use the pimpl mode for reconstruction, only interfaces are exposed in the public class, and all the details (public) are exposed in the implementation class. Only the implementation class is included in the test.

However, I tried both methods and thought it was inconvenient.

    • Use the friend keyword
      Gtest provides a friend_test macro to declare a test as a friend of the product class. Its disadvantage is obvious. One is to add pure test code to the product class; the other is to add a friend_test to the product class for each test.

    • Reconstruction adopts the pimpl Mode
      I agree with the pimpl mode, but I will not do this for all classes at the same time. So I may be reluctant to rebuild it just to support testing. Besides, manual refactoring is very troublesome, and I don't have such an automated tool at hand. (Of course, I believe this can be automated)

In fact, we want to achieve nothing more than: in the product code, the pubic is public, the private is private, and in the test code, all are public. So:

 
# Ifdef gtest # define private public # define protected public # endif

Put it before the declaration of each class, or put it in a separate header file such as forcepublic. h and include it. In this way, you can easily use any member of the tested class by adding the gtest pre-compiled macro to compile the test code without affecting the product code.

If you are pureSource codeBut if you use your product class through static library or dynamic library, if you use these libraries directly in the test code, the compilation is fine, because all files are disguised as public, but the private members are not exported from the library during the connection, A link error is inevitable. At this time, there are two solutions: one is to recompile the library using gtest; the other is to directly compile the product source code into your test project.

I used a dynamic library and chose to compile the code into the test project. To solve some compilation problems related to dllexport and dllimport, I also made the following definitions:

 
# Ifdef syntax # define txnmgr_api _ declspec (dllexport) # else # ifdef gtest # define txnmgr_api # else # define txnmgr_api _ declspec (dllimport) # endif

In this way, the txnmgr_api macro definition is empty in the test project and is ignored without affecting the product code.

I feel that the advantage of this method is that as long as you make some small changes at the beginning, you can solve the problem of accessing all the private members of the product class once and for all. Because we only change the access level of members, class behavior should have no effect.

 

Update:

In the Google group of gtest, we raised a discussion on this issue. We pointed out that the problem with this method is:

 

    • This makes it too easy to access private members, which increases the possibility of writing test files to access private members. Tests access private members, that is, they rely on implementation. This makes unit tests a burden of refactoring, not a guarantee.
    • Wan zhanyong also pointed out that this method is not a standard C ++ usage: first, the C ++ standard does not allow redefinition of keywords, therefore, even if this method is feasible in your current compiler at this time, you cannot guarantee the future or be able to operate on other compilers. The second is public, access modifiers such as protected private may affect the layout of object members, which may cause some problems when your test is directly linked to the product code.

 

Therefore, unless you are clear about and can accept the above 02:10, it is better to use the official friend_test.

 

    • Because every test that needs to access a private member requires adding a friend_test in the product code, this will let you think: Do I really need to access a private member? Is there any way to access private members? To help form a better design and test
    • Because each test dependent on the implementation is explicitly registered, so that when your implementation details change, you know which test will be affected

 

Update 2:

# A fatal problem with define private public is that if the class you are using is a pre-compiled DLL or Lib, if you change the access modifier to use this compiled class, there is a very likely Link error-because you are using another class at all. In reality, we use other libraries more or less, or directly or indirectly, so this should be disabled. This is actually an extension of the second point proposed by hichina.

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.