Friday, August 10, 2012

Should private data and methods be unit tested?


A central part in OOP (Object Oriented Programming) model is encapsulation which hinders the external usage of some of the object’s components, such as its methods and data. Some OOP languages do not have real encapsulation, Python is an example of this but there is a loose agreement that internal data that begins with two underscores should not be accessed directly.

When it comes to unit testing such objects it can be quite tempting to check that the accessible methods modify the private data in a manner that is according to how the class should work. There are usually ways to achieve this in the programming language without breaking the encapsulation principle totally.

In C# it is possible to mark components as public, protected, private, and internal. protected components of an object are only available for inheritance while private components are only available to the object which they have been declared in. Components of an object that are declared as internal are only available within the software module, however it is possible to allow other modules access to them by adding an attribute to the AssemblyInfo.cs file.

For example if we have a class named AClass that has internal members and we want to have access to them in the unit test project called AClassUnitTest the following line should be added to the AssemblyInfo.cs file which houses the AClass file:

[assembly: InternalsVisibleTo("AClassUnitTest")]

Declaring an internal constructor which allows for injecting mocks into the class that should be tested is good usage of this functionality. The private and protected components can also be accessed through what is called Accessors. There is an article on MSDN on using Accessors on MSDN 

In C++ there is the friend keyword that can be used to access private components of another object.

1:  #include <iostream>  
2:  using namespace std;  
3:  // Predeclaration for AClass so the BClass is aware of it existance.  
4:  class AClass;   
5:  class BClass {  
6:  private:  
7:       int data;  
8:       void printData() { cout << data << endl; }  
9:  public:  
10:       BClass (int insertData) : data(insertData) {}  
11:       friend AClass;  
12:  };  
13:  class AClass {  
14:  private:  
15:       BClass* dataClass;  
16:  public:  
17:       AClass (BClass *insertDataClass) : dataClass(insertDataClass) {}  
18:       virtual ~AClass() { delete dataClass; }  
19:       void fireDataClass() {   
20:            if (dataClass)  
21:                 dataClass->printData(); // Calling the private method on BClass  
22:       }  
23:  };  
24:  int main(int argc, char* argv[]) {  
25:       AClass friendClass(new BClass(10));  
26:       friendClass.fireDataClass();  
27:       return 0;  
28:  }  

In the example above the AClass can access both the private function and data of the BClass  which is due to that the BClass friends AClass on row 11. Simply by pre-declaring a unit test class it is possible to prepare a class so that the internal members are available for unit testing. A more in depth description of the friend keyword and its usage can be found here 

However testing private data with unit test makes the black box, that objects usually are, transparent. Changing the internal functionality of the objet will then carry a high probability of breaking the unit test even though the functional contract of the object has not been violated. There are good grounds to treat objects as black boxes even during the testing of the objects.

Unit test should only verify the externally visible components of an object so it is possible to safely refactor the code of the object without destroying its usability. Rewriting of a test should only occur when the object has had a breaking change to its interface and this should indeed be a time for reflection on what has been done.  

4 comments:

  1. Why not apply the commando pattern?

    http://www.javaperformancetuning.com/articles/commando.shtml

    ReplyDelete
    Replies
    1. This seems like a good way in java to achieve access to private and protected variables however this does not change my position that the parts of the object should not be tested.

      Even though unit test are meant to be rapid I don't believe that any extra performance enhancements should be added to create unit tests.

      This pattern also seems to carry the burden that it has a break point where it gets usable, that is when the benefit of removing method calls is outweigh the cost of reflection. This cost is certainly not the same between different programming languages so I think there should be some measurements when applying it.

      Thanks for the link, it was a very interesting read.

      Delete
    2. Bah! Should perhaps have read the final part of the article that explains that it's a joke. Good one.

      Delete
  2. OT

    Even if it is a joke and it's definitely not usable for unit testing, many very widespread libraries/frameworks like spring and hibernate make use of reflection to get their work done. This might become evident only when you realise that your code coverage never hits accessor/property methods on entity objects and proxied spring beans.

    This is mostly a result of java having been with us for a longer time letting developers find the quirks around the language and into the VM. Results are seen in high performance open source utility libraries in one end and the new era of languages running on the JVM in the other.

    The commando pattern lets the strict and nowadays code heavy Java keep its place as a first class citizen. It simply opens up the possibilities in the otherwise limited language to give it capabilities of the looser and more flexible ones.

    You can probably find more patterns behind the link below that might seem like jokes, but are actually in use and making sense.

    http://www.lsd.ic.unicamp.br/~oliva/fun/prog/resign-patterns

    Oh, and there are many that are used, and makes no sense at all.

    ReplyDelete