The philosophy behind testing is a great one. Create a separate independent angle to reveal bugs you wouldn't otherwise, simply by defining start parameters and expected results.
Sadly most people don't take this principle to it's final conclusion enough and get stuck writing tests for every single function.
For the purpose of this illustration we will divide our applications code into different layers.
The first layer, or the "immediate layer" consists of everything that is directly related to features that are accessible for end users.
In general all code we write is ultimately human centered, meaning the final layer is a human mind.
After the first come many other layers of code, for example layers taking care of API calls, the APIs themselves, the databases and so on.
Since every layer depends heavily on the next, in theory we only need to write tests for the immediate layer of our code. If these tests succeed, by implication, the deeper layers have to be at least "correct enough", for application to work.
So naturally we ask the question "why write tests for deeper layers at all?"
Our aim is to create the highest amount of quality in the shortest amount of time.
When a test on the immediate layer fails, we know what functionality will be unavailable for the end user. Depending on the depth of our program, we might spend forever trying to find out at what level the problem is exactly (sometimes stack traces are simply not enough).
If we encounter such a bug, we write tests only specific parts of our deeper layers, that seem to be the cause.
This way we our tests are not a waste of time, but precisely placed pieces of code that dynamically cover any unknown that actually gives us trouble.
*Good principles enable life to flourish, while rigid practice makes even the deepest wells run dry."