Base types, Collections, Diagnostics, IO, RegEx…
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:
<trace autoflush="false" indentsize="4">
<remove name="Default" />
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.
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)?
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?
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!
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.