views:

428

answers:

1

I'm getting an Object Disposed Exception when I try to call TraceSource.TraceData with my VS2008 unit test project. I have included a very small code sample below which consistently repros the issue. I'm only seeing this after I run my first unit test - but I have a hunch it'll affect me once my website is up and running with lots of users.

It's like the underlying stream is being closed after the first unit test. Any help greatly from the 'overflow' gurus would be v much appreciated.

Steps:

1) Create a VS 2008 Unit Test project

2) Add a class with this code:

namespace TracingError
{
    using System.Diagnostics;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    [TestClass]
    public class UnitTest1
    {
        public static TraceSource ts = new TraceSource("TraceTest");

        [TestMethod]
        public void A()
        {
            ts.TraceEvent(TraceEventType.Information, 1, "Hello from A");
        }

        [TestMethod]
        public void B()
        {
            ts.TraceEvent(TraceEventType.Information, 1, "Hello from B");
        }
    }
}

3) Add an app.config with this code:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.diagnostics>
    <sources>
      <source name="TraceTest" switchName="SourceSwitch" switchType="System.Diagnostics.SourceSwitch">
        <listeners>
          <add name="console" type="System.Diagnostics.ConsoleTraceListener" initializeData="false" />
          <remove name="Default" />
        </listeners>
      </source>
    </sources>
    <switches>
      <add name="SourceSwitch" value="Verbose" />
    </switches>
    <trace autoflush="true" indentsize="4"></trace>
  </system.diagnostics>
</configuration>
A: 

I encountered the same problem when running tests that exercised code with Trace.WriteLine calls. Running a single test is fine, but running multiple triggered the following call stack:

System.IO.__Error.WriterClosed()
System.IO.StringWriter.Write(Char[] buffer, Int32 index, Int32 count)
System.IO.TextWriter.WriteLine(String value)
System.IO.TextWriter.SyncTextWriter.WriteLine(String value)
System.Diagnostics.TextWriterTraceListener.WriteLine(String message)
System.Diagnostics.TraceInternal.WriteLine(String message)
System.Diagnostics.Trace.WriteLine(String message)

After some investigation I found that placing the following code in your test setup worked around the problem:

[TestInitialize()]
public void Setup()
{
    Array.ForEach((from TraceListener tl in Trace.Listeners
                   where tl.Name != "Default"
                   select tl).ToArray(),
                   tl => Trace.Listeners.Remove(tl));

}

Apparently, when running in the mstest environment, there is a problem with multiple trace listeners. MSTest is adding a System.Diagnostics.TextWriterTraceListener that is using a stream that is disposed after the first test. The workaround simply removes all Trace listeners other than the default, effectively removing the mstest-added listener. The problem appears to be related to some improper handling of the trace stream created by mstest. Previously I stated that mstest created an AppDomain for each test. This is not true.

I see that you filed a bug report with Microsoft here, but did not receive any useful feedback. Hopefully this quick fix will work for you, as it did for me.

Todd Stout