On Thu, Dec 22, 2011 at 8:59 AM, Chris Cleeland <chris.cleeland@gmail.com> wrote:
Thanks to all for the suggestions!  You are correct that I'm testing
"legacy" code, though in this particular case the legacy code is
completely open for change.  But, I need unit tests before I go
mucking about so I know that I haven't made things any worse than they
are.

On Wed, Dec 21, 2011 at 7:04 PM, Ahmed Badran <ahmed.badran@gmail.com> wrote:
> That is what I've come to accept as probably the cleanest possible solution
> without hacking/redefining "private"/"protected" in production vs. test code
> (even though it's far from what I would call elegant).
> For a class I essentially create a friend in a completely different "test"
> namespace, the unit tests go in that namespace and are linked against the
> object files to test them and validate class internals/invariants. The
> shipping code (headers) always have the 'missing' friend declarations, but
> as I said it's a 1 line that I've gotten to accept as the least ugly
> solution until I come across something that's more elegant.

For some reason I'm having difficulties implementing this suggestion.

The "legacy" code lives in a namespace, e.g.,

// ClassToBeTested.hh
namespace mycompany {
namespace internal {
class ClassToBeTested { ... };
} // namespace internal
} // namespace mycompany


If I understand the suggestion, I think I want to put the testing in a
different namespace, e.g.,

// test_ClassToBeTested.cxx
namespace mycompany {
namespace internal {
namespace test {
 // here lies the boost unit test stuff that I create
 struct ClassToBeTested_suite_fixture { ... };
 BOOST_FIXTURE_TEST_SUITE( ClassToBeTested_suite,
ClassToBeTested_suite_fixture )
 ... here lie unit tests...
 BOOST_AUTO_TEST_SUITE_END()
} } }


So, in the declaration for ClassToBeTested, I should have something like

class ClassToBeTested {
public:
 // public interface
protected:
 // protected members/methods
 friend class mycompany::internal::test::ClassToBeTested_suite_fixture;
};



When I compile, the compiler complains that it does not know about
namespace 'test'

]$ clang++ namespace_test.cxx
namespace_test.cxx:4:46: error: no member named 'test' in namespace
'mycompany::internal'
        friend class
::mycompany::internal::test::ClassToBeTested_suite_fixture;
                     ~~~~~~~~~~~~~~~~~~~~~~~^
namespace_test.cxx:6:8: error: expected external declaration
  } } }
      ^
2 errors generated.

In your header (the class to be tested, you need to forward declare the test namespace and the tester class, e.g.

// ClassToBeTested.h

// You may be able to generate the forward declaration using a script and put it in an include file that you
// include here.
namespace test
{
    class TesterOfClassToBeTested;
}

namespace myOtherNamespace { // optional
    class ClassToBeTested
    {
        friend class test::TesterOfClassToBeTested;   // here's the one line :)
        public:
        private:
    };
}

 
// TesterOfClassToBeTested.cpp

#include "ClassToBeTested.h"

#define foreach BOOST_FOREACH

using namespace std;
using namespace boost;
using namespace stage;

namespace test
{
    class TesterOfClassToBeTested
    {
        public:
        TesterOfClassToBeTested()
        {
        }
        void copy_constructor()
        {
            ClassToBeTested loc2;
            ClassToBeTested loc(loc2);
            BOOST_REQUIRE(loc.locIdStruct == loc2.locIdStruct);
        }
        ~TesterOfClassToBeTested()
        {
        }
        private:
    };
}

BOOST_AUTO_TEST_SUITE(TesterOfClassToBeTested)

struct fixture
{
    test::TesterOfClassToBeTested t;
};


BOOST_FIXTURE_TEST_CASE(copy_constructor, fixture)
{
    t.copy_constructor();
}

BOOST_AUTO_TEST_SUITE_END()



The only way I've found around this is to forward declare
ClassToBeTested_suite_fixture in the ClassToBeTested header, e.g.,

// ClassToBeTested.hh
namespace mycompany {
namespace internal {
namespace test { class ClassToBeTested_suite_fixture; }
class ClassToBeTested { ... };
} // namespace internal
} // namespace mycompany


Is this the technique that you use?  I wonder, because it's more than
one lane and still intrusive, and I'm wondering if I'm missing
something.


--
Chris Cleeland
_______________________________________________
Boost-users mailing list
Boost-users@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users