The Debug.Assert(bool) method is a very old API that allows your program to test your assumptions at runtime, but in a way that only impacts performance of debug builds. The method is attributed with [Conditional("DEBUG")] which causes the compiler to drop all calls to it in Release builds.

On .NET Framework, when the tested condition fails, an “Assertion Failed” dialog is displayed, giving the user a chance to Ignore the failure, Abort the program, or attach a debugger to investigate.

But in the .NET (Core) runtime, because the GUI functionality was initially removed (and only exists on Windows), the Debug.Assert behavior changed. Instead of displaying a dialog on failure, it immediately crashes the process. This is particularly annoying when you are running a bunch of tests and only a few of them end up executing because the test host process crashes on a failed Debug.Assert call.

But you can change the behavior. Instead of crashing the process, you can throw an exception when the program runs under a test so the test fails and other tests may continue to execute. It turns out that the behavior to pop a dialog or crash the process is done through the DefaultTraceListener, which has an AssertUiEnabled property that defaults to true. Setting it to false disables its behaviors (on .NET Framework or .NET). By setting this property and adding our own trace listener that throws an exception, we can achieve our goal.

Below is a source file you can add to your test project to achieve this. It uses a module initializer to ensure that it reconfigured the trace listeners before any tests run.

The only caveat here is that crashing the process will always be noticed, while throwing an exception might not be noticed. In particular, if your product code swallows exceptions or a test is verifying that an exception is thrown, throwing an exception from a failing Debug.Assert call may be swallowed and seen as a success instead of calling out that one of your assumptions are incorrect. You can potentially solve this by throwing an exception whose type will not be caught and seen as a success. Or perhaps you can set a field somewhere that your test verifies later to ensure that no Debug.Assert failed along the way.

Leave a Reply

Your email address will not be published. Required fields are marked *