Here's a super quick peek into unit tests compared to functional tests. And full disclaimer here is that depending on your circle of influence, these might be given slightly different names. Try not to dwell on that but instead the comparison and contrast presented!
Unit Tests
Coded tests that take a white-box visibility approach to exercising and asserting that written code, generally a specific function/method, works as it was designed.
Pros:
- Generally very programmer-focused
- Very granular coverage (breaks can identify exact lines where an issue occurs)
- (Should) run extremely quickly
- Have very little test setup in ideal cases
- Provide full control (generally via ‘mocking’ dependencies) to exercise very specific logical paths
Cons:
- Generally more challenging to convey coverage to other stakeholders
- By nature these are brittle and break with refactoring
- Require sets of design patterns to help ensure tests are easy to write/maintain
- Sometimes present false sense of confidence in large codebases (i.e. systems working together) due to mocking requiring assumptions
Functional Tests
Coded tests that take a black-box visibility approach to exercising and asserting that software performs particular functionality as expected.
Pros:
- Generally easier for non-programmer stakeholders to understand
- Generally covers multiple classes/systems/methods working together to demonstrate behavior
- More resilient to refactoring since this approach ignores the internals of what’s being covered
- Exercises REAL parts of the codebase with no mocking
Cons:
- More coarse than unit tests. Breakages might need more investigation.
- Can potentially have more test setup given that multiple things will be interacting
Summary
So which one of these should you and your team be writing? The answer is probably both! There are benefits and drawbacks to both of these testing strategies and they overlap really nicely together. If you know you're going to be refactoring a complex piece of your system, functional tests would be great to put in place so you can check expected behavior after. Unit tests might be great for mocking out complex dependencies or validating a variety of inputs quickly into a function. If you have an understanding of how you can leverage these, you have more tools in your programming toolbox!
Don't like reading? Listen to me instead!