Writing unit tests is pretty easy if the code is testable and well-structured. Here are a few of the most important principles to keep in mind when writing testable code:
Write functional pieces without side effects
Think of each code block as a functional piece that shouldn't cause any side effects (like I/O). Any side effects should be isolated and wrapped.
Use Inversion of Control / Dependency Injection
The big benefit of using Inversion of Control / Dependency Injection via constructor parameter interfaces is that you easily can mock all those dependencies in your unit tests.
Here's a simple introduction to IoC.
Adhere to the SOLID principles
The SOLID-principles are guidelines for writing good Object-Oriented code. The most important principle for writing testable code is the "Single responsibility principle" which in practice means that you should split your code in small task oriented blocks. A method should seldom be more than a few lines long and it should never "do multiple things" (e.g. DecodeVideoAndAddSubtitles).
Write the unit tests first
One of the core principles of TDD (Test-Driven Development) is that you should write your unit tests before you write the actual code. This will force you to write testable code.
I'm not sure that you have to write all test first (I find that it sometimes limits my object oriented design process), but it's a good practise and you should take 1-2 months to try it out. It can be done.
Extract all non-testable code into wrapper-classes
You will run into code that isn't testable (and never will be), like I/O operations and external APIs - code at the boundaries of your system. Isolate this code into narrow wrappers. Make sure to exclude as much logic from these wrappers as you can.
Try not to use static methods or variables
Static methods can be hard to mock out. Avoid them if possible.
Static variables leave a global state and should only be used in very special cases.
Got any more tips on how to make your code testable? Leave a comment below...