My interpretation of that talk is:
- test components, not classes.
- test components through their interface ports.
It's not stated in the talk, but I think the assumed context for the advice is something like:
- you are developing a system for users, not, say, a utility library or framework.
- the goal of testing is to successfully deliver as much as possible within a competitive budget.
- components are writen in a single, mature, probably statically typed, language like C#/Java.
- a component is of the order of 10000-50000 lines; a Maven or VS project, OSGI plugin, etc.
- components are written by a single developer, or closely integrated team.
- you are following the terminology and approach of something like the hexagonal architecture
- a component port is where you leave the local language, and its type system, behind, switching to http/SQL/XML/bytes/...
- wrapping every port are typed interfaces, in the Java/C# sense, which can have implementations switched out to switch technologies.
So testing a component is the largest possible scope in which something can still be reasonably called unit testing. This is rather different from how some people, especially academics, use the term. It's nothing like the examples in the typical unit test tool tutorial. It does, however, match its origin in hardware testing; boards and modules are unit tested, not wires and screws. Or at least you don't build a mock Boeing to test a screw...
Extrapolating from that, and throwing in some of my own thoughts,
- Every interface is going to be either an input, an output, or a collaborator (like a database).
- you test the input interfaces; call the methods, assert the return values.
- you mock the output interfaces; verify the expected methods are called for a given test case.
- you fake the collaborators; provide a simple but working implementation
If you do that properly and cleanly, you barely need a mocking tool; it only gets used a few times per system.
A database is generally a collaborator, so it gets faked rather than mocked. This would be painful to implement by hand; luckily such things already exist.
The basic test pattern is do some sequence of operations (e.g. save and reload of a document); confirm it works. This is the same as for any other test scenario; no (working) implementation change is likely to cause such a test to fail.
The exception is where database records are written but never read by the system under test; e.g. audit logs or similar. These are outputs, and so should be mocked. The test pattern is do some sequence of operations; confirm the audit interface was called with methods and arguments as specified.
Note that even here, providing you are using a type-safe mocking tool like mockito, renaming an interface method cannot cause a test failure. If you use an IDE with the tests loaded, it will be refactored along with the method rename. If you dont, the test won't compile.