Hi, thanks for posting.
Under .NET Framework, the NCrunch task runner builds its own application domain inside the test process and uses this to execute the test and underlying code. The appdomain is tied to the lifespan of the test process.
Under .NET Core and .NET 5+, NCrunch does not build an appdomain and simply uses the default application domain of the task runner, which is essentially a console process.
The behaviour in regards to threading is controlled by the test framework. Threads are created by the test framework and their lifetime is managed by the framework. Depending on which test framework you are using, they may have attributes available for controlling the apartment state of the execution thread.
Note that neither NCrunch nor the test framework have any reliable way to distinguish between test code and production code. It's all just code as far as the system is concerned. It will just call the test method with the execution thread and what happens from there is up to you. It's possible to build an application domain boundary between your test code and production code, but it would be up to you to build this and NCrunch won't try to do it for you.
I have no personal experience in trying to change the CurrentPrincipal on an executing thread, as this isn't something I've had to do myself. Perhaps there is something fundamental inside the runtime that is causing unexpected behaviour here.