Your black box tests will give you the confidence and keep you safe
Don’t underestimate the value of keeping your unit tests in shape. When it’s time for refactoring, your black box tests will help you get the job done faster.
There are many good reasons why you should unit test your code, an important one is that if done right, they serve as a safety net when you do refactoring. Since no developer writes the ideal solution on the first go, refactoring is needed all the time. But to take advantage of your tests when refactoring, your design must allow changing the implementation without rewriting your tests.
The tests that are going to help you in the process are your black box tests, the ones that test your functionality without bothering about implementation details. Any white box tests you might have, that know about the internal structures of your components, will make your mission more risky not to mention painful – and no developer likes to change more code than necessary.
The less your tests know about the internal implementation of your components, the more useful they will be during refactoring. If you have to change your unit tests just as much as the rest of the code, you can’t use them to ensure that you still have the same behavior and quality.
Enforce a good design
When you develop a new component, your tests help you enforce good design. Developers who don’t like writing tests are quite good at coming up with excuses why they shouldn’t – “this can’t be tested, is too difficult”. Well, if it’s difficult to test, it’s probably difficult to use. Maybe it can be designed a bit differently, perhaps the business logic is in the wrong place, or there’s some static dependency that shouldn’t be there.
Coding against interfaces, keeping clear dependencies and loose coupling between components are all factors that simplify your testing quite a bit, and mocking will be a lot easier. Try to separate different concerns, avoid mixing code for transaction management and database access with your business rules. Usually, this also makes it easier to put the right code in the right place.
Getting inside the box
If you feel the urge to get inside the box and test a private method, access or set private fields, your class may be responsible for more than it should, perhaps it has unclear dependencies, or it could be too tightly coupled with other components.
Have a look at the design before bringing on test frameworks with capabilities for breaking encapsulation – save that for the cases when there is no other way out, or you really need to verify implementation details. In a well designed system with unit tests protecting the interface and functionality of each component, refactoring will be a lot faster – and your black box tests will give you the confidence and keep you safe.