Any idea why private variables and methods aren't visible to test classes by default? it just seems to unnecessarily junk up my code.

Said another way, why wouldn't you want to have privates auto-visible to test classes?

  • 2
    This question is nearly impossible to answer without guesswork and opinions for any not on the Apex team. – Adrian Larson Sep 18 '18 at 19:21

Imagine a box with buttons on it. When you push a button on our hypothetical box, a light on the box turns red, and this something is well-defined; every press of the button turns that light red. How does the box do it? We don't know, and we don't care, just that when we push the button, the light turns red. If the light does not turn red, then we need to open the box and try to figure out why it's not working.

This is one of the core principles of object-oriented programming. The unit test is primarily concerned with making sure that when method X is called, behavior Y is observed to happen. Sometimes, however, we end up with a situation where there is no outside observable behavior, so we need to inspect deeper. This is the reason why we need to sometimes look inside, to see what the internal state looks like. We also use this to manipulate the internal state in ways that are not normally possible for whatever reason, perhaps to make sure the error handling works correctly or to mimic data that can't be replicated in a test.

This is incredibly rare and should be used with the utmost caution, since you're technically able to modify the state of the object in a way that can never happen in real situations. That's the reason why it's not the default, is because it can be used to help convince us that our code is working correctly, when in reality, it is not. There are legitimate cases for doing so, as I said, but it should be avoided at all costs.


Said another way, why wouldn't you want to have privates auto-visible to test classes?

I would rather ask myself, why do I really need it?

A nicely put statement you can find on the Java documentation:

In the spirit of encapsulation, it is common to make fields private.

If at all you want anyone to view your private class variables, you rather make those public or add properties (get methods). And I would consider a Test Class in that category too, so that at least if I am writing my Unit Tests, I know that how my private vs. public variables are behaving and that there's no direct way of exposing my private variables to outside world.

Anything declared as private, if that's exposed even in my test class is definitely not fool-proof then, is what I will consider. Personally I don't know why this annotation is even allowed where you test classes can access private variables. But if at all you want to utilize "spirit" of object oriented encapsulation, you should be really looking to expose anything using the properties or exposing those as public, and that's how actually you can do it.


Another aspect...

When refactoring code it is hugely helpful to know what methods and properties other code may depend on: those methods and properties can't be changed without considering the other code making the job harder. A private method or property is guaranteed to only be referenced within the class so change is easier. But with a @TestVisible private method or property it is clear that there is likely to be a test that needs considering. The good news is that while a change may break the test, it won't (directly) break the product code.

To add to sfdxfox's points, the number of @TestVisible annotations is a useful metric for the quality of your tests and an area to look at in code reviews.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.