Compartilhar via


Customizing the behavior of System.Diagnostics.Debug.Assert [Matt Ellis]

When Inbar posted his refresher on the System.Diagnostics.Debug class, Ron Cain asked an interesting question about Assert in the context of a test harness. Because of this I thought it might be nice to expound on some of the details on exactly how Debug.Assert ends up popping up UI when a failure occurs and what you can do to change this behavior.

We’ll start by discussing what happens when a simple call like Debug.Assert(false) is made. All Debug.Assert does is check the condition and if its value is false (as it is in this case) calls Debug.Fail with String.Empty as the message. When Debug.Fail is called, we iterate over theTrace.Listeners collection and call the Fail method on each listener and then return. The subtle point here is that Debug.Assert doesn’t pop up the assertion failed dialog, but instead some listener in the Trace.Listeners collection does. The listener that does this is called the DefaultTraceListener.

As its name suggests, the DefaultTraceListener is added by default to the Trace.Listeners collection when your application runs. If you want, you can remove this listener either by calling Trace.Listeners.Remove(“Default”) at some point in your app or by using an application configuration file that removes the listener. An example configuration file would look like:

<configuration>

<system.diagnostics>

  <trace autoflush="false" indentsize="4">

    <listeners>

      <remove name="Default" />

    </listeners>

  </trace>

</system.diagnostics>

</configuration>

If you do either of these two things and then call Debug.Assert(false) your app will continue to run and you’ll have no indication that your assertion failed. If you just want to disable the UI but continue to have debugging messages written to the OutputDebugString (or to a log file if you have specified the DefaultTraceListener.LogFileName property) you can set AssertUiEnabled property on the DefaultTraceListener object to false.

Now, to answer Ron’s question on how you can get Debug.Assert() to play nice within your testing environment. The answer depends somewhat on what your hosting environment is like. If your tests simply run applications and check their return codes you could write a custom trace listener that calls System.Environment.Exit with a special error code whenever Fail is called. Perhaps instead you may choose to write a stack trace when an assert is fired to a predefined output file that your testing harness checks when it returns, if the file is empty after your test case runs then you know there were no asserts.

Hopefully this has helped to remove some of the mystery behind the Assert method on the System.Diagnostics.Debug class. If you have further questions about anything in the Diagnostics name space feel free to drop a comment and I’ll try to respond.

Cheers!

Comments

  • Anonymous
    July 19, 2007
    Hi, It’s very interesting that I been working on that same issue couple of days ago. I have two questions:
  1. I don’t understand why AssertUiEnabled is default to TRUE in ASP.NET application?
  2. Other issue that troubles me is I don’t understand why is the Configuration section classes of all the diagnostics section are internal? (E.g. I wanted to do a simple program that updates the configuration and I had to create wrapper class for the configuration sections and not use the already written classes of .net)? Thanks
  • Anonymous
    July 19, 2007
    I find Debug.Assert frustrating because it does not do what I want: when running under the debugger, pop straight into the debugger. The dialog is an annoying waste of time. I have written my own Assert that just throws an exception, but it is missing one piece of magic from Debug.Assert: How does Debug.Assert keep its own stack frames off the top of the stack? When you click through the dialog the debugger shows the top stack frame from your app, not the Debug class. Is this an undocumented .NET feature?

  • Anonymous
    July 20, 2007
    @Jonathan Edwards, By default Visual Studio won't attempt to step into framework code since you likely don't have symbols or sources for it.  This is similar to if your code call some framework API that throws an exception, Visual Studio show break into the debugger at the point where your code called the offending method, not within the framework code. I think that if you apply System.Diagnostics.DebuggerNonUserCodeAttributeto your new Assert method that Visual Studio will prevent it from being shown on the call stack. Hope this helps! Cheers, Matt

  • Anonymous
    July 31, 2007
    I've been setting /configuration/sytem.diagnostics/assert/@assertuienabled to "false" on all my unit testing and ASP.NET applications and it has worked fine, so far.