Skip to content

Method of visiting private members in unit test #2666

@kirk0830

Description

@kirk0830

Meet trouble when adding unit test on module_io/bessel_basis. Relevant issue #2614 .

Discussed in #2659

Originally posted by kirk0830 June 21, 2023
The writing and debugging unit test of module_io/bessel_basis are still in progress, while thanks to Zuxin we will have a brand new module (module_nao) later, therefore the unit test of bessel_basis may be not quite important if the new module is fully implemented. However, presently, during adding unit tests on private members, the use of #define private public will iteratively cause errors like:
error: ‘struct std::__cxx11::basic_stringbuf<_CharT, _Traits, _Alloc>::__xfer_bufptr ’ redeclared with different access
446 | struct __xfer_bufptrs
| ^~~~~~
which is, obviously caused by imposing #define private public onto <sstream> (for analysis with more details posted by other coder, see why cannot use #define private public anymore?). Got advice from Tianqi that removing unnecessary dependence of header files on other header files may finally solve this error, but this error pops again and again, from global_function.h to global_variable.h, then realarray.h, unitcell.h, vector3.h and matrix3.h.

Actually there are also other methods for visiting private variables and functions, but will be more or less invasive, such as gtest/gtest_prod.h::FRIEND_TEST, or the following way:

  1. first create a variable when setting BUILD_TESTING option in CMakeLists.txt is true, say __UNITTEST
  2. In header file, use
    #ifdef __UNITTEST
    #define PRIVATE_SWTICH public
    #else
    #define PRIVATE_SWTICH private
    #endif
    and substitute private with PRIVATE_SWTICH.

The use of FRIEND_TEST also requires declaration in private scope of class to test. So these two methods are more or less invasive but has pros that makes the range of variables which will be set as public during unit test controllable. Suggestions provided by ChatGPT4 are pasted here:

It looks like the error is caused due to an access level conflict for struct __xfer_bufptrs within the basic_stringbuf class, which is part of the std namespace (typically declared in the <sstream> header file). The most likely reason for this error is the #define private public directive.
While this directive can help you access private members of a class for testing purposes, it also changes the access level of everything in every file that is included after the directive, not just your own classes. This can cause conflicts with library classes, such as std::basic_stringbuf, that rely on the proper access levels for their members.
This situation is a perfect example of the risks associated with using #define private public. As I suggested earlier, safer alternatives for testing private methods are refactoring your code to make it more testable, making the test a friend of the class, or using the Google Test FRIEND_TEST macro.
As a final note, the use of #define private public is generally considered a bad practice because it breaks the encapsulation principle of object-oriented programming. Moreover, it can lead to issues like the one you're experiencing, especially in complex projects that involve multiple libraries or large codebases.
It's always better to architect your classes and methods in such a way that you can test them without needing to access private members. This typically involves designing your classes with testability in mind, for example by providing public methods that can be used to check the state of the object, or by using interfaces and dependency injection so you can provide mock implementations for testing.

Therefore comments and opinions are of need and will be appreciated about method visiting private variables and functions during unit test.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions