Testing should be exploratory, to explore as many issue as possible. The hard part is that you need to be a faster learner and first understand how the system suppose work.
All the automatic tests develops write should be call ‘Checks’. They all reaffirmation of what is already know. The reason unit test is so popular those day is that we are so bad at writing and following specifications and unit test is a good alternative because they are precise at defining what function should do.
Any automatic tests done above unit test level is time consuming and ineffective and again they are not testing, they are checks and work as definitions.
The fundamental problem is that soft engineering is precise engineering but human wording is nor precise. The work of defining software and testing software has to be performed by human intelligent and labour. until the time when AI is capable of exploratory testing.
Back to development level. function should be pure. IO operation usually should not be included in test suite because they are slow. High level functions, which are really processes, involving too many details should be ‘test against’ rather than ‘check against’. Efforts should be focus on how to break it rather than checking if it is working as expected.