The random utterances of David Arno

Real world use-case of “use protected, not private”

evil-privateRecently I wrote an article that challenged the software accepted practice of hiding methods away using the private keyword. Instead I suggested that using protected is actually better practice. In this article, I present a real-world example of this philosophy whereby switching from private to protected makes it far easier to unit test one’s code

Consider the following code fragment:

package demo
{
  import ...
 
  public class Process extends EventDispatcher
  {
    private var loader:URLLoader;
 
    public function loadImagesFromPage(url:String):void
    {
      loadPage(url);
    }
 
    private function loadPage(url):void
    {
      loader = new URLLoader();
      loader.addEventListener(Event.COMPLETE, onPageComplete);
      loader.load(new URLRequest(url));
    }
 
    private function onPageComplete(e:Event):void
    {
      var data:String = loader.data as String;
      var expr1:RegExp = /<img[^>]*>/gi;
      var images:Array = data.match(expr1);
 
      for each (var s:String in images)
      {
        ...
      }
    }
    ...
  }
}

From the perspective of writing unit tests, we are scuppered. The only publicly exposed method is the constructor, which takes a URL and performs an HTTP GET on it in order to fetch the page’s content. The method onPageComplete is completely inaccessible as far as unit testing goes. Our only option is to perform lots of system tests in the hope we fully exercise onPageComplete. In frustration, many developers would then start adding various public methods and read-only properties (getters in Java parlance) to try and get around the problem. In the process, they ride roughshod all over the class’ encapsulation.

Yet this problem arises simply because “private” was used. Change private to protected and a whole new world of unit testing possibilities are opened up. Suddenly we can create a test class that extends Process. This allows us to mock its methods and access all of its innards during the tests. This in turns lets us write unit tests – not integration or system tests, but real unit tests – that test every last little detail of the class. For example:

package demo.tests
{
  import ...
 
  public class ProcessTestcases extends Process
  {
 
    protected override function loadPage(url:String):void
    {
    }
 
    [Test]
    public function testParsingHTML():void
    {
      var html:String = 
        "<html><body>" +
        "<img src='img1'/>" +
        "<Img Src=\"img2.png\"/>" +
        "<IMG SRC='http://www.somewhere.com/src/img3.jpg'/>" +
        "<img src=''/>" +
        "</body></html>";
 
      loader = new URLLoader();
      loader.data = html;
      super.onPageComplete(null);
 
      Assert(...)
    }
  }
}

provides us with an override of loadPage, which prevents Process‘ constructor from attempting to load a page. This then lets up call testParsingHTML directly, ie we can run unit tests against that previously inaccessible method.

Such a technique is immensely useful for unit testing all event based code. It isn’t just limited to event handlers though, by using protected rather than private, you can simplify the unit testing of all your code.


Share This Post...
3 comments so far, click here to read them or add another

3 Comments so far

  1. Tom August 4th, 2010 10:19

    Hey thats clever. Such a neat way of mocking a class for testing might actually let me sell the switch to protected to my colleagues. Thanks.

  2. Dave August 4th, 2010 16:40

    I see your pain, but my diagnosis would be that the class is doing too many things: it’s getting some HTML and then processing it. Note the conjunction in its description!

    Given that you can change this class, why not extract the ‘interesting’ behaviour inside onPageComplete into a separate unit which you can then test cleanly without worrying about HTTP?

  3. David Arno August 4th, 2010 21:57

    @Dave,

    The idea of describing a class and then, if it contains “and” breaking it in two is a good one. However your description is flawed. The class actually grabs images from a web page. No conjunction required unless you start describing how it does it.

    The class, whilst somewhat contrived as I wrote it for a Test Orientated Development (TOD) talk, it is fairly simple. Breaking it’s functionality up into extra classes would therefore necessitate a fair degree of coupling between those classes and would likely make the code more, not less, complicated.

    That aside, the technique is more about testing event-based functionality, rather than HTTP calls. Breaking the code up into smaller classes wouldn’t make testing private event handlers any easier.

Leave a reply

Close