Yeah. Unit tests aren’t especially applicable to the type of software I tend to write (UI mobile apps), though. I use them a lot for the backend code, and a number of the packages that my apps include, but I don’t like to rely on automated UI testing, as these tests are invariably scripted “record/playback/pattern-match” tests. Only useful for testing a minuscule number of “low-hanging fruit” issues. Not at all useful for a “user goes where they want,” unbounded GUI. Maybe an AI-driven testing system might work.
In my experience, there’s no substitute for good, old-fashioned, disciplined “monkey-tests,” when it comes to UI software. Even test harnesses aren’t always relevant, and I end up running most of my tests on the production code, as the project matures.
Requires discipline. And, in my experience, a well-documented codebase (“Why,” as opposed to “what,” when documenting internals), pays off in spades. Headerdoc markup works wonders. It, quite literally, makes self-documenting code, and documenting the interfaces (as opposed to the internals) has a great shelf life.
Since I use Xcode, it "live-parses" my interface docs, and shows them in the QuickHelp panel, on the right side of the screen, so, when I select a function that I wrote, it displays the interface, just like it does for the Apple-authored stuff. Very cool. Since all my included packages (the ones I wrote, anyway -which is 99% of them), use it, I have great "live" documentation.
I used to argue with my Japanese peers about this stuff. They were not fans of automated testing. I was able to get them on board with unit-testing engine code, but they were absolutely correct about testing GUI code, and I had to cede the point to them.
They were very disciplined, when it came to “monkey testing,” code structure, and documentation. One reason, was because they tended to rotate engineers through projects all the time, and leaving a legacy was important. I write about what I have learned, here: https://littlegreenviper.com/miscellany/leaving-a-legacy/