It should be noted, if it wasn't obvious, that
MPWTest is
opinionated software, meaning it
achieves some of its smoothness by gleefully embracing constraints that some might view as
potentially crippling limitations.
Maybe the biggest of these constraints, mentioned in the previous post, is that MPWTest only tests
frameworks. This means that the following workflow is not supported out of the box:
The point being that this is a workflow I not just somewhat indifferently do not want, but rather
emphatically and actively
want to avoid. Tests that are run (only?) when launching the
app are application tests. My perspective is that unit tests are an integral part of the
class. This may seem a subtle distinction, but subtle differences in something you do
constantly can have huge impacts. "Steter Tropfen höhlt den Stein."
Another aspect is that launching the app for testing as a permanent and fixed part of your build
process seems highly annoying at best. Linker finishes, app pops up, runs for a couple of seconds,
shuts down again. I don't see that as viable. For testing to be integral and pervasive, it has
to be invisible when the tests succeed.
The testing pyramid is helpful here: my contention is that you want to be
at the bottom of that pyramid, ideally all of the time. Realistically, you're
probably not going to get there, but you should push really, really hard, even making
sacrifices that appear to be unreasonable to achieve that goal.
Framework-oriented programming
Only testing frameworks begs the question as to how to test those parts of the application
not in frameworks. For me the answer is simple: there isn't any production code outside
of frameworks.
None. Not the UI, not the application delegate. Only the auto-generated main().
The benefits of this approach are plentiful, the effort minimal. And if you think this is
an, er, eccentric position to take, the program you almost certainly use to create apps
for iOS/macOS etc. takes the same eccentric position: Xcode's main executable is 45K in size and
only contains a main() function and some Swift boilerplate.

If all your code is in frameworks, only testing frameworks is not a problem. That may seem
like a somewhat extreme case of sour grapes, with the arbitrary limitations of a one-off
unit testing framework driving major architectural decisions, but the causality is the
other way around: I embraced framework-oriented programming before and independently of
MPWTest.
iOS
Another issue is iOS. Running a command-line tool that dynamically loads and tests frameworks
is at least tricky and may be impossible, so that approach currently does not work. My current
approach is that I view on-device and on-simulator tests as higher-up in the testing hierarchy:
they are more costly, less numerous and run less frequently.
The vast majority of code lives in cross-platform frameworks (see: Ports and Adapters) and is
developed and tested primarily on macOS. I have found this to be much faster than
using the simulator or a device in day-to-day programming, and have used this "mac-first"
technique even on projects where we were using XCTest.
Although not testing on the target platform may be seen as a problem, I have found
discrepancies to be between exceedingly rare and non-existent, with "normal" code
trending towards the latter. One of the few exceptions in the not-quite-so-normal
code that I sometimes create was the change of calling conventions on arm64, which
meant that plain method pointers (IMPs) no longer worked, but had to be cast to
the "correct" pointer type, only on device. Neither macOS nor the simulator
would show the problem.
For that purpose, I hacked together a small iOS app that runs the tests specified
in a plist in the app bundle. There is almost certainly a better way to handle this, but
I haven't had the cycles or motivation to look into it.
How to approximate
So you can't or don't want to adopt MPWTest. That doesn't mean you can't get at least some
of the benefits of the approach. As a start, instead of using Cmd-B in Xcode to build, just
use Cmd-U instead. That's what I did when working on Wunderlist, where we used XCTest.
Second, adopt framework-oriented programming and the Ports and Adapters style as much as possible.
Put all your code in frameworks, and as much as possible in cross-platform frameworks that you
can test/run on macOS, and even if you are developing exclusively for iOS, create a macOS target
for that framework. This makes using Cmd-U to build much less painful.
Third, adhere to a strict 1:1 mapping between production classes and test classes, and place
your test classes in the same file as the class they are testing.
My practical experience with both JUnit and XCTest on medium-sized projects does not
square with the assertion that the difference is not that big: you still have to
create these additional classes, they have to communicate with the class under tests
(
self in MPWTest), you have to track changes etc. And of course, you
have to know to configure und use the framework differently from the way it was
built, intended and documented. And what I've seen of OCUnit use was that the
tests were not co-located with the class, but in a separate part of the project.
A final note is that the trick of interchangeably using the class as the test fixture is only
really possible in a language like Objective-C where classes are first class objects.
It simply wouldn't be possible in Java. This is how the class can test itself, and the
tests become an integral part of the class, rather than something that's added
somewhere else.