I have a class that I am unit testing into with DUnit. It has a number of methods some public methods and 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 different way to declare the private methods so that I can still test them but they are not public?
To test private methods, you just need to test the public methods that call them. Call your public method and make assertions about the result or the state of the object. If the tests pass, you know your private methods are working correctly.
Why We Shouldn't Test Private Methods. As a rule, the unit tests we write should only check our public methods contracts. Private methods are implementation details that the callers of our public methods aren't aware of. Furthermore, changing our implementation details shouldn't lead us to change our tests.
So whether you are using JUnit or SuiteRunner, you have the same four basic approaches to testing private methods: Don't test private methods. Give the methods package access. Use a nested test class.
Moq supports mocking protected methods. Changing the methods to protected , instead of private , would allow you to mock their implementation.
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.
It is a little hacky, but I think this is the simplest and clearer approach. Use this conditional compilation directive:
{$IfNDef TEST}
private
{$EndIf}
Your unit test project must define TEST in project → conditional defines
. Without a visibility specification, they become published.
Beware: if the private visibility isn't the first one in the class declaration, it will get the previous definition. A safer way, but more verbose and less clear, would be:
private
{$IfDef TEST}
public
{$EndIf}
This has a lot of advantages over the subclassing or other approaches:
I think it is a clearer solution, and better than the selected answer.
When I use this, I also configure the test project to put the build objects in a different directory of the main project. This prevents the binaries with the TEST directive to mix with the other code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With