Best Practices for Writing Unit Tests
Do you know when it's time to write unit tests? Today, I try to provide insight on best practices for how (and when) to write unit tests
Over the past weeks, I've been asked by a couple of developers how do you know when to write unit tests.
It actually depends on your method of writing code.
For Test-Driven Development (TDD), you write unit tests before writing any implementation. This makes your implementation details in your code shorter and easier to understand. In this instance, the best time to write unit tests is immediately.
For others, most developers write unit tests after the code's been written.
Some don't even write unit tests.
However, the good news is, based on the Stack Overflow Developer Survey Results for 2019, 62.3% of developers do write unit tests.
For those still hesitant about whether unit tests are necessary, I wanted to provide some best practices when it comes to writing unit tests and truly explain why I like writing them.
100% Test Coverage - How much is too much?
I feel this is a myth, so let's get this one out of the way.
Yes, yes, you can write unit tests until your fingers are sore, but the unit tests you write should have value and not used as just a resulting metric. They truly test something in the system and the expected behavior of your class and/or method is correct.
I always pick a threshold high enough to instill confidence in my software like maybe 70-85% of code is covered.
Also, don't game the threshold. You're only cheating yourself.
Write Tests for Mid-to-Advanced Complexity
I've dealt with some pretty complicated code in my time where no unit tests were included at all.
How do you confirm the code works?
Some routines can be extremely complicated which is why I found unit tests so valuable. The only way a developer knew the code was tested was if it ran locally.
I would rather have various unit tests pass instead of finding surprises when the software ships.
Documenting Through Unit Tests
Writing unit tests is similar to documentation. Most developers don't like writing them but let me ask you a question.
Would you rather write documentation for your code or explain what your code does through your unit tests?
While your implementation code should be self-documenting, your unit tests should give developers a look into how it was developed on an abstract level.
Better Than Writing Console Apps
<old man voice> Back in the day, I remember creating small console applications just to test a theory.
Now, your unit tests are your console apps.
They give you clarification and the ability to prove out your ideas with a minimal amount of code.
Besides, it saves space with all of those WebApplicationX.csproj files and project folders littered on your hard drive.
Why Write Them? To Avoid Having Customers Find Issues
As developers, we can't check every single line of code, but it is our job.
Writing unit tests gives the developers a piece of mind when moving on to the next task/feature on-hand.
I would rather write a unit test to confirm the behavior of code than to not write a unit test and have a customer discover an error in the system.
Checks-and-Balances: Confirm Your Code Works
This may be strange for millennials, but older folks used to write checks and record the check in a checkbook. It was called balancing your checkbook.
Writing code is no different.
You write unit tests to confirm the code functions as expected. You wouldn't write one without the other.
It's not like this is the wild West of writing code.
Make methods isolated, but call-able.
As various developers have mentioned, try to make your methods small and isolated by following the SOLID principle.
This makes your code more testable and easier to find.
"Boy, am I glad I found that 500-line method!"...said no developer EVER!
Don't Code Your Unit Tests
Your classes should be similar to your methods: small and testable.
Unfortunately, I've seen longer lines of unit tests than implementation code. Your unit tests should contain minimal setup for classes.
Don't write a 100-line, unit test framework to test your large classes.
Unit testing a class with statics can be troublesome. When you experience a static in your code requiring a unit test, it's best to wrap the static in a general class for testing purposes.
Or you could just change the static into a regular class. ;-)
Arrange / Act / Assert
I always section off my unit tests into three categories: Arrange, Act, and Asset.
- Arrange - Setup the class or classes to test.
- Act - Perform the actual test
- Assert - Based on the results, find out if the tests succeeded.
For each section, try to create a line of code for each section. I understand it may get large, but that could be considered a code smell.
I also want to explain that I use as many Asserts as possible to confirm a unit test passes, but I try not to go past five Asserts.
These are general guidelines for when and how I need to write unit tests. I wrote something similar in previous years and felt this would be a nice compliment to The Ultimate Guide To Unit Testing in ASP.NET MVC.
I understand everyone has their own method of writing them just like I do, but honestly, I feel any unit tests are better than no unit tests, even if they are broke.
How do you write unit tests? Do you TDD? Do you have a standard for your unit tests? Post your comments below and let's discuss.