What should be unit tested?
Testers typically like to test everything when the code arrives in their environments. However, when there is confidence that the code is correctly tested at a unit level, the tester can focus on high-priority and complex scenarios instead. Before jumping into unit tests, it is also helpful to understand what scenarios are best-suited for unit testing. While you want most of your testing to be done in this way, there is still a need for integration and end-to-end tests that ensure the individual parts all behave correctly and in unison.
Entry and exit points: All code receives an input and then provides an output. Essentially, what you are looking to unit test is everything that a piece of code can receive, and then you must ensure it sends out the correct output. By catching everything that flows through each piece of code in the system, you greatly reduce the amount of failures that are likely to occur when they are integrated as a whole.
Isolated functionality: While most code will operate on an integrated level, there are many functions that will handle all computation internally. These can be unit tested exclusively and teams should aim to hit 100% unit test coverage on these pieces of code. I have mostly come across isolated functions when working in microservices architecture where authentication or calculator functions have no dependencies. This means that they can be completely unit tested with no need for additional integration.
Boundary value validations: Code behaves the same when it receives valid or invalid arguments, regardless of whether it is entered from a UI, some nitrated API, or directly through the code. There is no need for testers to go through exhaustive scenarios when much of this can be covered in unit tests.
Clear data permutations: When the data inputs and outputs are clear, it makes that code or component an ideal candidate for a unit test. If you’re dealing with complex data permutations, then it is best to tackle these at an integration level. The reason for this is that complex data is often difficult to mock, timeous to process and will slow down your coding pipeline.
Security and performance: While the majority of load, performance and security testing happens at an integration level, these can also be tested at a unit level. Each piece of code should be able to handle an invalid authentication, redirection or SQL/code injection and transmit code efficiently. Unit tests can be created to validate against these. After all, a system’s security and performance is only as effective as its weakest part, so ensuring there are no weak parts is a good place to start.