It depends on how you model the domain of your program.
If you model domains in terms of data stored in data structures and methods that read data from one data structure and store derived data in another data structure (procedures or functions depend on your procedural or functional design), then the layout of the objects is not suitable. So-called "state" testing is what you want. The result you care about is that the procedure puts the right data in the right variables and what it calls for this to happen is just an implementation detail.
If you model domains in terms of message transfer protocols with which objects interact, then protocols are what you need and what data objects store to coordinate their behavior in the protocols in which they play roles - this is just an implementation in detail. In this case, mock objects are the right tool for specifying and checking based on state, closely linking tests to minor implementation details.
And most object-oriented programs have a combination of styles. Some code will be written exclusively functionally, transforming immutable data structures. Another code will coordinate the behavior of objects that change their hidden internal state over time.
Regarding high test coverage, that really doesn't say much. A low test coverage indicates where you have poor testing, but a high test coverage does not indicate that the code is adequately tested. Tests can, for example, go through code paths and thus increase coverage statistics, but actually do not make any statements about what these code codes did. In addition, it is important how the different parts of the program behave in combination, which the unit test will not tell you about. If you want to verify that your tests really test the behavior of your system, you can use the Mutation Testing tool. This is a slow process, so this is what you run in the nightly build, and not with every registration.
source share