How to lose friends and alienate coworkers.

Started by
12 comments, last by matt77hias 7 years ago

@[member='l0calh05t']

If one wants to write unit tests (whether to achieve full code coverage or not), one should include private methods as well. Except for their access modifier, they do not differ from any other methods! They have preconditions, postconditions, should be documented and ideally should be tested separetely (private methods are in fact more "unit" than public methods).

Lots of Java (or C#) codebases use reflection for this purpose:


Method method = targetClass.getDeclaredMethod(methodName, argClasses);
method.setAccessible(true);
return method.invoke(targetObject, argObjects);

🧙

Advertisement

Why make it so predictable?

Random chaos is much more fun...


std::thread([]{
    while( true){
    //cause problems randomly, but only once every 15 minutes on average
    sleep(1000);
    if(0==rand()%(15*60)) {
        char *x=(void*)rand();
        //seg fault? just corrupt some data? who knows? let's make it a surprise...
        *x=rand();
    }
    }}

My Oculus Rift Game: RaiderV

My Android VR games: Time-Rider& Dozer Driver

My browser game: Vitrage - A game of stained glass

My android games : Enemies of the Crown & Killer Bees

@[member='l0calh05t']

If one wants to write unit tests (whether to achieve full code coverage or not), one should include private methods as well. Except for their access modifier, they do not differ from any other methods! They have preconditions, postconditions, should be documented and ideally should be tested separetely (private methods are in fact more "unit" than public methods).

Lots of Java (or C#) codebases use reflection for this purpose:


Method method = targetClass.getDeclaredMethod(methodName, argClasses);
method.setAccessible(true);
return method.invoke(targetObject, argObjects);

Nonsense. Private methods are not at all like other methods. They are implementation details! So those "pre and post conditions" are liable to change at any time, making your tests utterly worthless. A private method can even leave an object in an inconsistent state. DO NOT do this. And doing this to achieve better "code coverage" is even worse, because if any paths in private methods cannot be exercised via public methods, they are dead code and should be removed.

Or if you prefer a quote from a book, Dave Thomas and Andy Hunt write the following in Pragmatic Unit Testing:

In general, you don't want to break any encapsulation for the sake of testing (or as Mom used to say, "don't expose your privates!"). Most of the time, you should be able to test a class by exercising its public methods. If there is significant functionality that is hidden behind private or protected access, that might be a warning sign that there's another class in there struggling to get out.
Nonsense. Private methods are not at all like other methods. They are implementation details! So those "pre and post conditions" are liable to change at any time, making your tests utterly worthless. A private method can even leave an object in an inconsistent state. DO NOT do this. And doing this to achieve better "code coverage" is even worse, because if any paths in private methods cannot be exercised via public methods, they are dead code and should be removed.

Your arguments make no sense. The way private methods are implemented are implementation deals like any other method. That is you encapsulate the how or the imperative nature of your code. Thus treating them as black boxes like any other method both when using them and when testing them via unit tests. Both the use and the testing make no sense without pre- and postconditions which only expose the what or the declarative nature of your code. Without having those conditions, your methods should be treated as dead code since no one would have a clue what (not how) the methods do. Saying that the conditions change can mean several things:

  1. You refactored your code. In this case, documentation, pre- and postconditions need to be updated accordingly since you modified the declarative behaviour of some methods or added some new methods.
  2. You do not understand the difference between declarative and imperative, making you leak implementation details via the documentation, pre- and/or postcondtions. In this case you should do some research on how formal documentation works.

Leaving objects in an inconsistent state is not a problem, whether this occurs in a public or private method, as long as it is documented. Therefore one uses code annotations (at class, methode, parameter level, etc.) for instance in Java or just enforce immutability at the language level like Haskell.

Of course not all languages (C++, etc.) provide support for testing private methods. That is a design decision of the laguage itself and irrelevant for the general discussion. (As a sidenote: in software design research one uses languages like Haskell, First and Second Order Logic languages like IDP, since one can enforce certain pre- and/or postcondtions in the code itself (at all levels independent of some access modifier). In practice for nuclear reactors for instance, one uses different languages in their toolset as well, since one wants to control all aspects of the code.)

Finally, it is important to realize that one library of a software project has multiple APIs. You have the API you expose to the end user who is only concerned with using the code (not testing the code). The API is also exposed to API programmers which have access to all code independent of their access modifiers. The access modifier only restricts the usage range. So different API programmers may use the same private method inside the same class. If they, however, have no guarantees that the method works as intended, they could not build upon the functionality. They could detect inconsistencies by testing public methods using those private methods, but could not deduce whether the public method or private method works not as intended via the typical black box testing.

🧙

This topic is closed to new replies.

Advertisement