tags:

views:

1093

answers:

4

I have a class that I am unit testing into with dUnit It has a number of methods some public Methods & Private Methods

type
  TAuth = class(TDataModule)
  private
    procedure PrivateMethod;
  public
    procedure PublicMethod;
  end;

In order to write a unit test for this class I have to make all the methods public.

Is there a differt way to declare the PrivateMethods so that I can still unit test them but they are not Public ?

+10  A: 

You don't need to make them public. Protected will do. Then you can subtype the class for unit testing and surface the protected methods. Example:

type
  TAuth = class(TDataModule)
  protected
    procedure MethodIWantToUnitTest;
  public
    procedure PublicMethod;
  end;

Now you can subtype it for your unit test:

interface

uses
  TestFramework, Classes, AuthDM;

type
  // Test methods for class TAuthDM
  TestAuthDM = class(TTestCase)
     // stuff
  end;

  TAuthDMTester = class(TAuthDM)
  public
    procedure MethodIWantToUnitTestMadePublic;
  end;

implementation

procedure TAuthDMTester.MethodIWantToUnitTestMadePublic;
begin
  MethodIWantToUnitTest;
end;

However, if the methods you want to unit test are doing things so intimately with the data module that it is not safe to have them anything but private, then you should really consider refactoring the methods in order to segregate the code which needs to be unit tested and the code which accesses the innards of the data module.

Craig Stuntz
Yeah without sounding too negative I don't agree with making your private methods protected for the sake of unit testing as they are private for a reason. I think you should be testing the public interface. It's the public methods which are going to be using your private methods anyway.
Ben Daniel
I (respectfully) disagree, for reasons I elaborate here:http://blogs.teamb.com/craigstuntz/2009/01/12/37919/
Craig Stuntz
@Craig/Ben: private and protected are different isibilities and each has it's merits and disadvantages; If you want to e able to test the private methods, making those protected is simply a crude way of making them accessible to your testing framework (DUnit). What's next: private is evil, and strict private even more? I agree with Ben: unit testing is for testing your contract (eg the public interface with it's explicit (interface) and explicit (usage) rules). If the private members need testing, you should make that interface formal (part of an interface perhaps, inner class etc).
Ritsaert Hornstra
+9  A: 

"Don't test your privates"

Vegar
I agree strongly with this. If its private, then it shouldn't be accessed from outside objects there for shouldn't be tested beyond its interaction with other methods which ARE exposed to the outside. If you feel you need to test the private method then should it be private in the first place?
skamradt
+1. I also strongly agree. By making your private methods protected, your opening up your object wide open for any descendant class to use your base class as you didn't intend it to.
Ben Daniel
Besides my previous comment, your private methods will get implicitly tested by testing the public methods which call them! :)
Ben Daniel
@Ben: if the public methods include time-consuming or risky calls to other systems (databases, bank accounts, nuclear plant control systems) I would prefer to test only the relevant part, e.g. the password validation code. Object state includes values of private variables, so testing an object might require that they are accessible. Extended RTTI can be used now to read private variables so making them protected is no longer required.
mjustin
+2  A: 

I recommend the "XUnit Test Patterns" book by Gerard Meszaros:

Test-Specific Subclass

Question: How can we make code testable when we need to access private state of the SUT?

Answer: Add methods that expose the state or behavior needed by the test to a subclass of the SUT.

... If the system under test (SUT) was not designed specifically to be testable, we may find that the test cannot get access to state that it must initialize or verify at some point in the test.

The article also explains when to use it and which risks it carries.

mjustin
A: 

Put the DUnit code within your unit. You can then access anything you like.

Brian Frost
... by using conditional directives only
too