We’re almost ready to dive in to actually writing some unit tests, but we still have 2 best practices to cover. Yeah I know we’ve talked about a lot before writing code, but a proper understanding of best practices is going to make the whole writing code part so much easier.
Other Posts in the Series
Only one assertion per test
Yup that’s right, you should only have 1 assertion for each test written in 99% of cases. If you’re function does 2 things, then write 2 tests for the function not one big test that does has 2 assertions testing the 2 different parts of the functions.
But why only a single assertion per test???
A test should only fail for a single reason, not many possible reason inside a test. Sticking with a single assertion per test makes sure that this happens. It lets you write singularly focused code and you can tell right away where your code is having an issue because the test only has 1 reason to fail.
Your test name should be precise and clear. If you’re testing A and B in a test, what do you call it that’s precise and clear? Sticking with a single assertion per test helps make it all easier.
Tests should be concise and readable. So you setup your test data (we’ll cover how) then test the outcome of your function with an assertion then your test is done. No 30 line tests that do 3 things, you’re just going to confuse yourself.
All of the above points can be traced back to the long term maintainability of your test suit. If you don’t make it easy to read/understand for future you (who is not nearly as smart as current coffee fueled you) then your tests are simply going to lapse and become totally useless.
Now at the end let my remind you that this is a ‘best practice’ not a hard fast rule. Your default way to write a test should be to write a single assertion per test and very occasionally you’re going to find a reason not to do it.
First, stop and take a look at the base code. Can you simplify/refactor it so you can get to a single assertion? If so, go ahead and write the tests needed then refactor the code to match the tests.
If you can’t put in 2 assertions maybe even 3. Remember that the more complex you make your test to read/understand the higher the bar is raised for long term maintainability.
Test the expected and unexpected
Our second best practice is to not only test the expected output, but what does your code do with bad data?
If you need an email in the function what happens if you don’t get an email?
What if you’re supposed to email a password to a user and the email provided doesn’t actually match a user in your system? Should it still be sent or should we stop our process?
Do your tests cover those scenarios?
The point is that you’re not just going to have a 1:1 ratio for test:functions. You’re likely to have many more tests than functions, at least 2 tests for every 1 function in your code.
Next time we’ll actually start digging in to writing some tests for our plugins.