Also for languages with explicit memory management, unit tests can be pretty powerful when wrapped in a runtime memory analysis tool: detecting uninitialized memory, dangling memory etc.
At work, we have a somewhere around 11k unit tests last time I checked; granted, most are more system/integration tests than plain unit tests. The test environment gets deployed across a range of different configurations (OS, database vendors, application containers, JVM versions etc); it’s quite common/annoying that some errors are only reproducible in very specific environments/configurations.
Heh, many years ago, I wrote a payroll + reports application for small casino (a type of casino-in-bars thing that are quite common here) - it was my second project as a solo developer and took place during the time when I thought unit testing was mostly a tool for consultants to embellish their invoices.
Turns out that when your software is essentially dealing with cash flow, it rapidly spins out of the comfort zone every time something looks quirky. After going live and finding the first couple of bugs, every damn anomaly starts looking suspect.
Once the worst of my paranoia had passed, in parts thanks to not uncovering any really serious bugs (aside from a few embarrassing mistakes), income tax laws changes and I had to incorporate it into the software. Naturally, the application still had to be able to generate reports the old way too. And so began another stretch of weeks with too much stress and anxiety.
The above anecdote is of course on the extreme end of stupidity in regards to unit testing. Don’t ask me why I didn’t start writing unit tests asap upon realizing the error of my approach, but I didn’t,
For code out in the wild, only artemis-odb is unit tested: I started doing it when I cleaned up the bugs from vanilla artemis; once dev on new features begun, I tended to write tests for them too. I wasn’t aiming for complete coverage, but I think it’s mostly complete. When refactoring, having a semi-good coverage helps a lot - it was pretty much what made some refactoring work possible without messing up (like when changing the way entity groups were identified within the framework).