So you've heard about the wonderful world of test driven development. Maybe you want to take advantage of continuous deployment options, which build on the confidence that testing provides. Or, perhaps you've inherited a messy system full of cross references and you want to do a bit of refactoring. Unit testing is one key to solving these issues.

I'm going to run through some basic concepts you should review yourself and with your team before you commit to a unit testing plan.

Mocking & Dependency Injection

Unit tests are meant to be fast, speedy and deterministic - that is, they shouldn't depend on external services or modules being called to provide data, and they should not be flaky from one test run to the next.

"Mocking" of external modules or things like databases ensures that your code is not dependent on them, and allows you to only test the logic of the part you care about, under as many conditions as you see fit.

Many statically typed languages (like Java and C#) require things like dependency injection to mock objects and function calls.

Python, Javascript et. al don't rely on dependency injection or inversion of control containers to properly mock services and middleware, as their language supports dynamic typing and "monkey patching" of methods.

Having said this, I have personally found that compile-time typesafe languages (Java, C#) are far easier to unit test against, as they force you to code to guaranteed interfaces. Mathematically, the assertions you make are sure to work, and the type-hinting, autocomplete magic of an IDE makes mocking way easier. If you care a lot about this but you write in Javascript, I encourage you to look into TypeScript as a base for your next project, which allows you to write code to an interface spec.

Don't Aim For Complete Code Coverage

It's an unrealistic goal to set, will make your team despise unit testing and eventually you'll give up on unit tests completely (15% code coverage is worse than 45% code coverage over time). It'll damage your agility in the future, as you mock your way to hell, you're locking your team into a single implementation of that code branch. Also, it's a bad metric to be driving your team towards as it's an unrealistic assessment of the quality of your unit tests.

Write Unit Tests As Documentation

Use your unit tests as a way to highlight key sections of logic as your code, as a sort of "how to guide" on how someone who has never seen your underlying code would use your method and should expect it to work.

Get involved

Many open source projects on GitHub rely on unit testing to build confidence in a project's code, so it's a great place to start looking and understanding how to write good unit tests. Take a look at projects built in your preferred language and/or framework - they will often have an idiosyncratic way that unit tests are set up that alleviate domain-specific issues.

I'll note that on top of this, open source projects do tend to teach good general coding habits for people who wish to work in development teams in the future.

Additional Sources

Sandi Metz did a fantastic talk on how to use unit testing safely to maximise your refactoring efforts with little risk. This works especially well for inherited codebases riddled with legacy dependencies.

I wrote a small amount on dependency injection; if you're using Java your best bet is to look into Spring, and Castle is good for C#.

Unit test runners exist for most languages; some of them cover test running ("this is how you run this test") and some cover test assertion ("that output should equal this"), and some combine both. JUnit for Java, Visual Studio has built in test running and annotations for C#, and you'll probably want to look into Karma (runner) and Jasmine (assertion) for Javascript.

There's a fantastic open source rulebook on automated testing in teams by .gov that is well worth a read as well - the principles outlaid there are definitely some I've utilised and can relate to from the past two years.