During the course of the WPF project we are working on at work, we decided to go down the Agile/XP/TDD/Mocks/Continuous Integration route, which means Unit tests, lots of them.
We are using NUnit, which I really like, but we are also using WPF, we are obviously using the latest/greatest patterns AKA MVVM, but from time tom time it is nice to be able to test certain things on WPF controls/windows etc etc.
So I set out to create a small NUnit test like the following:
/* Style Definitions */ table.MsoNormalTable {mso-style-name:”Table Normal”; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-priority:99; mso-style-qformat:yes; mso-style-parent:””; mso-padding-alt:0cm 5.4pt 0cm 5.4pt; mso-para-margin:0cm; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:11.0pt; font-family:”Calibri”,”sans-serif”; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:”Times New Roman”; mso-fareast-theme-font:minor-fareast; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:”Times New Roman”; mso-bidi-theme-font:minor-bidi;}
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
Now to me this looked fine, but when I ran this code I got the following horror show.
Where NUnit moaned about “The calling thread must be STA”. Oh, that’s to bad. So I had a small think, and then came up with this small idea, just pass the original code to a helper class and have it run that in a Thread using STA threading apartment state. Sounds cool, but did it work. Well yes actually it did, and here is the small helper class.
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }And here is how to use this from a NUnit test.
/* Style Definitions */ table.MsoNormalTable {mso-style-name:”Table Normal”; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-priority:99; mso-style-qformat:yes; mso-style-parent:””; mso-padding-alt:0cm 5.4pt 0cm 5.4pt; mso-para-margin:0cm; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:11.0pt; font-family:”Calibri”,”sans-serif”; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:”Times New Roman”; mso-fareast-theme-font:minor-fareast; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:”Times New Roman”; mso-bidi-theme-font:minor-bidi;}
And just to prove it works, here is a screen shot of the actual test running successfully.
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }
Here is a link to a small test project that you can see this working with :Â wpfandnunittest1.zip in case you want to use this in your own projects.
Enjoy
Nice job man. I wrote about this topic a while back, in case you’re interested: http://www.codeproject.com/KB/WPF/UnitTestDispatcherTimer.aspx
Josh
Doh, I even left a comment on that article you wrote, must have forgot about that. Oh well proves we are both cool, I guess.
there is problem with this, here is an example:
add the following to class UserControl1
private string foo;
public String Foo
{
get
{
return “foo”;
}
set
{
foo = value;
}
}
add the following test to class UserControlTests
[Test]
public void TestFoo()
{
ThreadExecutor.RunCodeAsSTA(
delegate
{
WpfAndNUnitTest.UserControl1 uc1 = new WpfAndNUnitTest.UserControl1();
uc1.Foo = “Set the property”;
Assert.AreEqual(“Set the property”, uc1.Foo);
});
}
the test should fail, but it succeeds.
basically the RunCodeAsSTA must not only kicks off the new Thread, it should be wait for the thead to complete before return.
Daniel thanks for your comments, I’ll Look into this.
Daniel, I have now fixed this, thanks for letting me know about that.
I didn’t try out the code but in reading it I’m wondering, wouldn’t the unit test pass if the assert failed or if you threw an exception since you’re eating the exception? I remember reading about nUnit cross threading issues a while back on Provost’s site – http://www.peterprovost.org/blog/post/NUnit-and-Multithreaded-Tests-CrossThreadTestRunner.aspx. I’m not sure if the same approach still applies or is required.
Andrew, Having just read Provost’s site, you probably would want to store the Exception as he shows, or you could in my example log it, or re throw and catch that outside the STA codeblock call. I didn’t do that as I wanted to keep it a simple example, I figure people could throw and catch what they want.
Oh well looks like there are lots of resources now, for people to choose from
Hi Sacha,
what do you think about Pex?
http://research.microsoft.com/Pex/
Regards,
Alex
Alex
I haven’t heard of PEX I’ll have a look though, thanks for the link
Very interesting read!
I wrote a post about testing xaml behaviour using unit tests.
http://blog.fohjin.com/2008/09/how-to-test-your-xaml-behavior-using.html
-Mark
Mark your post is cool also. Thanks for sharing
Wouldn’t it be easier to set the threading model to STA in the nunit config file.
I also needed to do this when using WatiN for testing my web application.
(example config:
2
3
4
5
6
7
8
9
10
11
12
13
14
)
Oops my < and > aren’t shown…
1 <?xml version="1.0" encoding="utf-8" ?>
2 <configuration>
3 <configSections>
4 <sectionGroup name="NUnit">
5 <section name="TestRunner" type="System.Configuration.NameValueSectionHandler"/>
6 </sectionGroup>
7 </configSections>
8 <NUnit>
9 <TestRunner>
10 <!– Valid values are STA,MTA. Others ignored. –>
11 <add key="ApartmentState" value="STA" />
12 </TestRunner>
13 </NUnit>
14 </configuration>
Oeps my < and > aren’t shown…
1 <?xml version="1.0" encoding="utf-8" ?>
2 <configuration>
3 <configSections>
4 <sectionGroup name="NUnit">
5 <section name="TestRunner" type="System.Configuration.NameValueSectionHandler"/>
6 </sectionGroup>
7 </configSections>
8 <NUnit>
9 <TestRunner>
10 <!– Valid values are STA,MTA. Others ignored. –>
11 <add key="ApartmentState" value="STA" />
12 </TestRunner>
13 </NUnit>
14 </configuration>
Sorry, sorry
Apparently Mark Nijhof already mentoins this in his blog post!
And Sorry Sasha for spamming your blog (it was unintentional) 🙂
Cohen
Yeah thats works for me also.
offtopic: sacha, did you ever try ReShaper?
Yeah we use Re-Sharper at work, though I have mixed feelings about it, generally I like it.