Unit test accessing private variables

前端 未结 6 1475
无人及你
无人及你 2021-01-05 04:55

I have a unit test class Tester; I want it to access private fields of a Working class.

class Working {
    // ...
    private:
            


        
相关标签:
6条回答
  • 2021-01-05 05:27

    I did this by using a copy of my class header file in my test that is missing the "private" access specifier. The copy is generate by the makefile in the test directory so that the copy is regenerated if the original changes:

     perl -ne 'print unless m/private:/;' < ../include/class_header.h > mock_class_header.h
    

    and the 'test' make target depends on mock_class_header.h.

    This grants access to all the private member variables in the test, even though the real library was compiled with these member variables being private.

    0 讨论(0)
  • 2021-01-05 05:28

    Generally, your unit tests should not evaluate private variables. Write your tests to the interface, not the implementation.

    If you really need to check that a private variable has a particular characteristic, consider using assert() rather than trying to write a unit test for it.

    A longer answer (written for C# rather than C++, but the same principles apply) is at https://stackoverflow.com/a/1093481/436641.

    0 讨论(0)
  • 2021-01-05 05:29

    If you absolutely must do this, you could conditionally compile your code so that TestBase is a friend only when unit testing:

    class Working {
        // ...
        private:
        int m_variable;
    
    #ifdef UNIT_TESTING
        friend class TestBase;
    #endif
    };
    
    0 讨论(0)
  • 2021-01-05 05:41

    -fno-access-control

    If you're only using GCC, you can use the compiler option -fno-access-control while compiling your unit tests. This will cause GCC to skip all access checks, but still keep the class layout the same. I don't know if there is a similar option for other compilers, so this isn't a general solution.

    0 讨论(0)
  • 2021-01-05 05:45

    Try very hard to test all your private code using your public interface. Not only is it less work initially, but when you change the implementation there is much higher chance that the unit tests will still work.

    That said, sometime you just need to poke at the innards to get good test coverage. In that case I use an idiom I call expose. There is a joke in there if you think about it.

    Foo class that needs to be tested

    class Foo
    {
    public:
       // everyone is on their honor to only use Test for unit testing.
       // Technically someone could use this for other purposes, but if you have
       // coders purposely doing bad thing you have bigger problems.
       class Test;
    
       void baz( void );
    
    private:
       int m_int;
       void bar( void );
    };
    

    foo_exposed.h is only available to unit test code.

    class Foo::Test : public Foo
    {
    public:
       // NOTE baz isn't listed
    
       // also note that I don't need to duplicate the
       // types / signatures of the private data.  I just
       // need to use the name which is fairly minimal.
    
       // When i do this I don't list every private variable here.
       // I only add them as I need them in an actual unit test, YAGNI.
    
       using Foo::m_int;
       using Foo::bar;
    };
    
    
    // yes I'm purposely const smashing here.
    // The truth is sometimes you need to get around const
    // just like you need to get around private
    
    inline Foo::Test& expose( const Foo& foo )
    {
       return * reinterpret_cast<Foo::Test*>(
             &const_cast<Foo::Test&>( foo )
          );
    }
    

    How it would be used in unit test code

    #include "foo_exposed.hpp"
    
    void test_case()
    {
       const Foo foo;
    
       // dangerous as hell, but this is a unit test, we do crazy things
       expose(foo).m_int = 20;
       expose(foo).baz();
    }
    
    0 讨论(0)
  • 2021-01-05 05:51

    I agree with Trott's answer, but sometimes you're adding unit tests to legacy code that wasn't designed for it. In those cases, I reach for #define private public. It's just in unit tests, and it's just for when refactoring is too expensive to bother. It's ugly, technically illegal, and very effective.

    0 讨论(0)
提交回复
热议问题