Should I test private methods or only public ones?
I do not unit test private methods. A private method is an implementation detail that should be hidden to the users of the class. Testing private methods breaks encapsulation.
If I find that the private method is huge or complex or important enough to require its own tests, I just put it in another class and make it public there (Method Object). Then I can easily test the previously-private-but-now-public method that now lives on its own class.
How do I test a class that has private methods, fields or inner classes?
If you have somewhat of a legacy Java application, and you're not allowed to change the visibility of your methods, the best way to test private methods is to use reflection.
Internally we're using helpers to get/set private
and private static
variables as well as invoke private
and private static
methods. The following patterns will let you do pretty much anything related to the private methods and fields. Of course, you can't change private static final
variables through reflection.
Method method = TargetClass.getDeclaredMethod(methodName, argClasses);
method.setAccessible(true);
return method.invoke(targetObject, argObjects);
And for fields:
Field field = TargetClass.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);
Notes:
TargetClass.getDeclaredMethod(methodName, argClasses)
lets you look intoprivate
methods. The same thing applies forgetDeclaredField
.- The
setAccessible(true)
is required to play around with privates.
Unit testing of private methods
If the methods are complex enough to warrant testing in isolation, then refactor them into their own class(es) and test via their public interface(s). Then use them privately in the original class.
How do you unit test private methods?
If you are using .net, you should use the InternalsVisibleToAttribute.
How to write unit testing for Angular / TypeScript for private methods with Jasmine
I'm with you, even though it's a good goal to "only unit test the public API" there are times when it doesn't seem that simple and you feel you are choosing between compromising either the API or the unit-tests. You know this already, since that's exactly what you're asking to do, so I won't get into it. :)
In TypeScript I've discovered a few ways you can access private members for the sake of unit-testing. Consider this class:
class MyThing {
private _name:string;
private _count:number;
constructor() {
this.init("Test", 123);
}
private init(name:string, count:number){
this._name = name;
this._count = count;
}
public get name(){ return this._name; }
public get count(){ return this._count; }
}
Even though TS restricts access to class members using private
, protected
, public
, the compiled JS has no private members, since this isn't a thing in JS. It's purely used for the TS compiler. Therefor:
You can assert to
any
and escape the compiler from warning you about access restrictions:(thing as any)._name = "Unit Test";
(thing as any)._count = 123;
(thing as any).init("Unit Test", 123);The problem with this approach is that the compiler simply has no idea what you are doing right of the
any
, so you don't get desired type errors:(thing as any)._name = 123; // wrong, but no error
(thing as any)._count = "Unit Test"; // wrong, but no error
(thing as any).init(0, "123"); // wrong, but no errorThis will obviously make refactoring more difficult.
You can use array access (
[]
) to get at the private members:thing["_name"] = "Unit Test";
thing["_count"] = 123;
thing["init"]("Unit Test", 123);While it looks funky, TSC will actually validate the types as if you accessed them directly:
thing["_name"] = 123; // type error
thing["_count"] = "Unit Test"; // type error
thing["init"](0, "123"); // argument errorTo be honest I don't know why this works.This is apparently an intentional "escape hatch" to give you access to private members without losing type safety. This is exactly what I think you want for your unit-testing.
Here is a working example in the TypeScript Playground.
Edit for TypeScript 2.6
Another option that some like is to use // @ts-ignore
(added in TS 2.6) which simply suppresses all errors on the following line:
// @ts-ignore
thing._name = "Unit Test";
The problem with this is, well, it suppresses all errors on the following line:
// @ts-ignore
thing._name(123).this.should.NOT.beAllowed("but it is") = window / {};
I personally consider @ts-ignore
a code-smell, and as the docs say:
we recommend you use this comments very sparingly. [emphasis original]
Should you cover private methods with a separate unit test
The idea is that your class exposes a an interface and your tests verify the input/output is correct from that interface. Each class/method should have a single responsibility.
The technique you described of marking a method as protected virtual is one that I have used myself on occasion, but this was within the context of a large legacy code application where it was impractical to refactor everything into a testable state right away. This technique should be used sparingly.
Generally if you feel that a private method is complex enough that it needs its own tests you should probably extract it out to its own class. If the private method does not have a lot of complexity then you will be needlessly asserting implementation details and making your code hard to refactor in future.
If you need to set up many mock objects to test a single class then it is probably violation SRP. One of the great side affects of writing tests is that it highlights any poorly designed classes.
I highly recommend this book to you: https://www.artofunittesting.com/
How to unit test private methods in Typescript
Technically, in current versions of TypeScript private methods are only compile-time checked to be private - so you can call them.
class Example {
public publicMethod() {
return 'public';
}
private privateMethod() {
return 'private';
}
}
const example = new Example();
console.log(example.publicMethod()); // 'public'
console.log(example.privateMethod()); // 'private'
I mention this only because you asked how to do it, and that is how you could do it.
Correct Answer
However, that private method must be called by some other method... otherwise it isn't called at all. If you test the behaviour of that other method, you will cover the private method in the context it is used.
If you specifically test private methods, your tests will become tightly coupled to the implementation details (i.e. a good test wouldn't need to be changed if you refactored the implementation).
Disclaimer
If you still test it at the private method level, the compiler might in the future change and make the test fail (i.e. if the compiler made the method "properly" private, or if a future version of ECMAScript added visibility keywords, etc).
Related Topics
How to Detect Region of Large # of White Pixels Using Opencv
What's the Best Way to Check If a File Exists in C++? (Cross Platform)
Dereferencing a Pointer When Passing by Reference
Check the File-Size Without Opening File in C++
Opencv Orb Not Finding Matches Once Rotation/Scale Invariances Are Introduced
Window C/C++ Crypto API Examples and Tips
Getchar_Unlocked( ) VS Scanf() VS Cin
Why Do Linked Lists Use Pointers Instead of Storing Nodes Inside of Nodes
Forcing Nvidia Gpu Programmatically in Optimus Laptops
Unresolved External Symbol "Public: Virtual Struct Qmetaobject Const * _Thiscall Parent
Garbage Collection Libraries in C++
Using Emit VS Calling a Signal as If It's a Regular Function in Qt
How to Typedef a Template Class
Getline Keeps on Getting Newline Character. How to Avoid This