Update: Thanks to James and Samuel. I’ve wrongly assumed that every test runner in the world re-instantiates the test fixture before executing each test method – but some do and some don’t. In this case I was using NUnit and the “mystery” is solved by adding an NUnit [Setup] method to create a fresh, new expando for each test run. Seems obvious, but only after ejecting all assumptions.
xUnit.net and the Visual Studio mstest tools DO create a fresh instance of the test fixture for each test method they execute inside the fixture. NUnit and MBUnit only create the fixture once, and as Jim Newkirk says:
I think one of the biggest screw-ups that was made when we wrote NUnit V2.0 was to not create a new instance of the test fixture class for each contained test method. I say "we" but I think this one was my fault. I did not quite understand the reasoning in JUnit for creating a new instance of the test fixture for each test method. I look back now and see that reusing the instance for each test method allows someone to store a member variable from one test and use it another. This can introduce execution order dependencies which for this type of testing is an anti-pattern.
The anti-pattern is demonstrated below. 
The following tests all pass for .NET 4.0’s ExpandoObject.
private dynamic expando = new ExpandoObject();
[Test]
public void Can_Add_A_Member()
{
var expected = "Scott";
expando.Name = expected;
Assert.AreEqual(expected, expando.Name);
}
[Test]
public void But_Cannot_Reflect_It()
{
expando.Name = "Scott";
Assert.IsNull(expando.GetType().GetProperty("Name"));
}
[Test]
public void Is_A_Dictionary()
{
var expected = "Scott";
var dictionary = expando as IDictionary<string, object>;
expando.Name = expected;
Assert.AreEqual(expected, dictionary["Name"]);
}
[Test]
public void And_Also_Enumerable()
{
var enumerable = expando
as IEnumerable<KeyValuePair<string, object>>;
expando.Name = "Scott";
Assert.IsTrue(enumerable.Any(kv => kv.Key == "Name"));
}
What’s The Mystery?
ExpandoObject implements INotifyPropertyChanged and the following test will pass.
[Test]
public void Will_Raise_PropertyChangedEvent()
{
dynamic expando = new ExpandoObject();
var propertyName = "";
((INotifyPropertyChanged)expando).PropertyChanged +=
(sender, args) =>
{
propertyName = args.PropertyName;
};
expando.Name = "Scott";
Assert.AreEqual("Name", propertyName);
}
But, this version of the test fails unless you run under the debugger.
private dynamic expando = new ExpandoObject();
[Test]
public void Will_Raise_PropertyChangedEvent()
{
var propertyName = "";
((INotifyPropertyChanged)expando).PropertyChanged +=
(sender, args) =>
{
propertyName = args.PropertyName;
};
expando.Name = "Scott";
Assert.AreEqual("Name", propertyName);
}
In the passing test expando is local variable. In the failing test expando is a field. Scary.