4

I used to name my test class as a friend in the class to be tested, in order to enable testing private fields. I noticed that the name of the class is not verified for existence. Is it by intention?

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
katang
  • 2,474
  • 5
  • 24
  • 48
  • 3
    *"I used to name my test class as a friend in the class to be tested in order to enable testing private fields."* - That's a horrible idea. Testing must not break encapsulation. – Christian Hackl Feb 02 '17 at 17:24
  • 3
    Declarations *create* names. They don't check for existence of names. – Kerrek SB Feb 02 '17 at 17:24
  • Can you show an example of what you have and what part of it you think should not work? – NathanOliver Feb 02 '17 at 17:24
  • @ChristianHackl related http://stackoverflow.com/questions/4171310/what-is-wrong-with-making-a-unit-test-a-friend-of-the-class-it-is-testing – UKMonkey Feb 02 '17 at 17:27
  • @ChristianHackl: There is black box testing, and then there is white box testing. White box testing does break encapsulation. – Ben Voigt Feb 02 '17 at 17:30
  • @ChristianHackl black-box testing: fly the aircraft and see if it crashes. White-box testing: take the aircraft apart, check critical components for hairline cracks, then put the aircraft back together. Aircraft undergo white-box testing regularly. – Klitos Kyriacou Feb 02 '17 at 17:44
  • 1
    @KlitosKyriacou: Then `friend` unit tests are like letting the testers fly in the aircraft every time alongside the passengers? There's only so much value in comparing computer programs with real-life things, you know... – Christian Hackl Feb 02 '17 at 17:53
  • @ Christian Hackl I am in the process of implementation, and after implementing some new detail, I test it, rather than stepping and debugging. Not making tests for a ready-made project. I do not find it horrible, but I wonder what your offered/preferred method is. – katang Feb 02 '17 at 19:09

3 Answers3

3

A friend class declaration that uses an elaborated type specifier with non-qualified name of the class is actually a declaration of that class. It introduces the class as a member of the enclosing namespace. It does not require it to be pre-declared

class C
{
  friend class X; // OK, introduces '::X'
};

But if you use a qualified name in a friend class declaration, it will be subjected to a regular qualified name lookup. And it must refer to a previously declared name

class X {};

class C
{
  friend ::X; // OK, refers to '::X'
  friend ::Y; // Error, no '::Y' in sight
};

So, if you want your class name to be "verified for existence", use qualified names in friend declarations.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
2

Is it by intention?

I think so. It's much like a forward declaration.

Usually the friend class needs a full declaration of the friended class, but not vice versa.


To force checking an existent (declared) type you can use

class MyClass {
    friend FriendClass;
};

as mentioned in @bogdan's comment.


As a side note:
How to refactor the mostly not appropriate friend pattern, I recommend you to read my Q&A post: How can I remove refactor a «friend» dependency declaration properly?

Community
  • 1
  • 1
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • 3
    You can say `friend X;` instead of `friend class X;` and then it will require a previous declaration. Maybe this will help the OP. – bogdan Feb 02 '17 at 17:31
  • @bogdan Interesting. I wasn't aware of that syntax subtlety. – πάντα ῥεῖ Feb 02 '17 at 17:33
  • If i'm reading the standard right (**[dcl.type.elab]**) it's because the declaring work is done by `class` and `friend` is just a modifier. There are a couple caveats a little later in **[class.friend]** note 11 about scope that I'm working through in my head. – user4581301 Feb 02 '17 at 17:51
1

Imagine if the friend class was required to exist. How would you structure your code? For testing you have that friend declaration in your code. When you build your shipping version you aren't going to ship the test code, so you have to remove the friend declarations and rebuild everything. Now you're shipping code that's different from the code that you tested.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
  • See reply from bogdan and AnT. Otherwise I am not sticking to a friend. During the development phase, something debug/release solution would also do. Like asserting. – katang Feb 02 '17 at 19:18