<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;A0EHRns-eyp7ImA9WhRUFEs.&quot;"><id>tag:blogger.com,1999:blog-8942599</id><updated>2012-01-25T00:33:57.553-05:00</updated><category term="AOP" /><category term="Visual Studio" /><category term="Analytics" /><category term="SQL" /><category term="CSS" /><category term="SharePoint" /><category term="rants" /><category term="Windows Services" /><category term="selenium" /><category term="Tips" /><category term="msbuild" /><category term="general" /><category term="opinions" /><category term="windows 7" /><category term="twelve-days-of-code" /><category term="Legacy Projects" /><category term="vegas mix06" /><category term="TDD" /><category term="BDD" /><category term="web 2.0" /><category term="Software Design" /><category term="FxCop" /><category term="selenium toolkit" /><category term="log4net" /><category term=".net" /><category term="fun" /><category term="guided by tests" /><category term="blogging" /><category term="cool tech" /><category term="unity" /><title>the urban canuk, eh</title><subtitle type="html">Living idyllically in a .NET, C#, TDD world</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://www.bryancook.net/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://www.bryancook.net/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>bryan</name><uri>http://www.blogger.com/profile/01332614158223702009</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>192</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/bryanbcook" /><feedburner:info uri="bryanbcook" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId>bryanbcook</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><feedburner:feedFlare href="http://add.my.yahoo.com/rss?url=http%3A%2F%2Ffeeds.feedburner.com%2Fbryanbcook" src="http://us.i1.yimg.com/us.yimg.com/i/us/my/addtomyyahoo4.gif">Subscribe with My Yahoo!</feedburner:feedFlare><feedburner:feedFlare href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Fbryanbcook" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare href="http://feeds.my.aol.com/add.jsp?url=http%3A%2F%2Ffeeds.feedburner.com%2Fbryanbcook" src="http://o.aolcdn.com/favorites.my.aol.com/webmaster/ffclient/webroot/locale/en-US/images/myAOLButtonSmall.gif">Subscribe with My AOL</feedburner:feedFlare><feedburner:feedFlare href="http://www.bloglines.com/sub/http://feeds.feedburner.com/bryanbcook" src="http://www.bloglines.com/images/sub_modern11.gif">Subscribe with Bloglines</feedburner:feedFlare><feedburner:feedFlare href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Fbryanbcook" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare href="http://fusion.google.com/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2Fbryanbcook" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare href="http://www.pageflakes.com/subscribe.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Fbryanbcook" src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif">Subscribe with Pageflakes</feedburner:feedFlare><feedburner:feedFlare href="http://www.plusmo.com/add?url=http%3A%2F%2Ffeeds.feedburner.com%2Fbryanbcook" src="http://plusmo.com/res/graphics/fbplusmo.gif">Subscribe with Plusmo</feedburner:feedFlare><feedburner:feedFlare href="http://my.feedlounge.com/external/subscribe?url=http%3A%2F%2Ffeeds.feedburner.com%2Fbryanbcook" src="http://static.feedlounge.com/buttons/subscribe_0.gif">Subscribe with FeedLounge</feedburner:feedFlare><feedburner:feedFlare href="http://www.live.com/?add=http%3A%2F%2Ffeeds.feedburner.com%2Fbryanbcook" src="http://tkfiles.storage.msn.com/x1piYkpqHC_35nIp1gLE68-wvzLZO8iXl_JMledmJQXP-XTBOLfmQv4zhj4MhcWEJh_GtoBIiAl1Mjh-ndp9k47If7hTaFno0mxW9_i3p_5qQw">Subscribe with Live.com</feedburner:feedFlare><feedburner:browserFriendly>Hey! Your interest in my blog is really appreciated. Thanks! Please feel free to add your voice to the conversation by leaving comments on posts that interest you.</feedburner:browserFriendly><entry gd:etag="W/&quot;A0EHRns9eyp7ImA9WhRUFEs.&quot;"><id>tag:blogger.com,1999:blog-8942599.post-4737507392430228296</id><published>2012-01-23T13:48:00.001-05:00</published><updated>2012-01-25T00:33:57.563-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-25T00:33:57.563-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Tips" /><category scheme="http://www.blogger.com/atom/ns#" term=".net" /><category scheme="http://www.blogger.com/atom/ns#" term="Visual Studio" /><title>Execute Batch from Visual Studio</title><content type="html">&lt;p&gt;Since as long as I can remember, I’ve kept a command-line window open while I worked. It’s a warm fuzzy feeling of how computers used to work. I tend to structure commonly used tasks as &lt;em&gt;msbuild&lt;/em&gt; or &lt;em&gt;nant&lt;/em&gt; scripts, and then add handy batch files that pass the appropriate parameters to the script.&lt;/p&gt;  &lt;p&gt;Unfortunately, most of my team-mates don’t live in the command-line, so running a batch file breaks their traditional flow. &lt;/p&gt;  &lt;p&gt;Here’s a short tip on how to execute batch files without having to leave the comfort of the IDE. You’ve probably seen this tip before, but as always, I often use my blog as a digital memory. If it helps you, great.&lt;/p&gt;  &lt;p&gt;Visual Studio supports the ability to associate tools and alternate editors for different files. Adding support for batch files is simply a matter of opening the context-menu for a file and choosing &lt;em&gt;“Open With..”.&lt;/em&gt; Unfortunately, there’s no mechanism to supply parameters to your program, so adding support for a Command Prompt requires a small subtle hack that passes our parameters to the program we want.&lt;/p&gt;  &lt;h3&gt;To Associate Batch files to a Custom Command&lt;/h3&gt;  &lt;p&gt;First, we need to create a simple batch file that passes the arguments that Visual Studio provides onto our batch file.&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;If you haven't already, add your batch file to your solution. These are best treated as &lt;a href="http://msdn.microsoft.com/en-us/library/1ee8zw5t(v=vs.71).aspx" target="_blank"&gt;Solution items&lt;/a&gt; that aren’t part of your compilation process. &lt;/li&gt;    &lt;li&gt;Open notepad and save the following script as &lt;em&gt;C:\ExecuteBatch.cmd&lt;/em&gt; &lt;/li&gt; &lt;/ol&gt;  &lt;pre class="brush: plain; gutter: false; auto-links: false;"&gt;@cmd /c %1&lt;/pre&gt;

&lt;p&gt;Once this is in place,&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Associate the batch file in Visual Studio to the command line by right-clicking on the batch file and choose &lt;i&gt;&amp;quot;Open With...&amp;quot;&lt;/i&gt;. &lt;/li&gt;

  &lt;li&gt;In the dialog that appears, provide a name and associate it to the &lt;i&gt;ExecuteBatch.cmd&lt;/i&gt;. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="http://lh4.ggpht.com/-2AWjf66eWWw/Tx2rfa4pvRI/AAAAAAAAAiw/UzCN084WBf4/s1600-h/image%25255B3%25255D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/-tm9UdYqRRt4/Tx2rfkzITlI/AAAAAAAAAi4/fnmfcB6SgMI/image_thumb%25255B1%25255D.png?imgmax=800" width="644" height="416" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Optional: You can associate the Command as the &lt;strong&gt;default program for this extension&lt;/strong&gt;, by selecting your custom command and clicking on the “&lt;em&gt;Set as Default&lt;/em&gt;” button. Note that if you edit the file frequently you might want to skip this step, but you’ll have to right-click the file and choose &lt;em&gt;“Open With…”&lt;/em&gt; anytime you want to run your custom command.&lt;/p&gt;

&lt;h3&gt;Gotchas &amp;amp; Caveats&lt;/h3&gt;

&lt;p&gt;Just a few closing points:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;If you set your custom command as the default, note that there is no confirmation if you accidentally double-click the batch file. If your script is potentially destructive or long-running, you might want to add a prompt at the beginning of the batch file before running. &lt;/li&gt;

  &lt;li&gt;The ExecuteBatch.cmd provided above will close the window immediately after the batch terminates. If you want to review the output of the script before the window closes, you might want to add a pause to the end of the script. &lt;/li&gt;

  &lt;li&gt;Lastly, when adding new scripts to Visual Studio it will perform the default action when the file is added to the solution. If you don’t want to run the script when the file is added, you might want to temporarily assign a different editor (Source Code Editor) before you precede. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy Coding.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8942599-4737507392430228296?l=www.bryancook.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/ZCVUdpKwiQsxsN7pFw6JhFx8IzI/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ZCVUdpKwiQsxsN7pFw6JhFx8IzI/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/ZCVUdpKwiQsxsN7pFw6JhFx8IzI/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/ZCVUdpKwiQsxsN7pFw6JhFx8IzI/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=hUrqY4eSQN8:FwEPV1WGBgc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=hUrqY4eSQN8:FwEPV1WGBgc:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=hUrqY4eSQN8:FwEPV1WGBgc:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=hUrqY4eSQN8:FwEPV1WGBgc:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?i=hUrqY4eSQN8:FwEPV1WGBgc:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bryanbcook/~4/hUrqY4eSQN8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.bryancook.net/feeds/4737507392430228296/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8942599&amp;postID=4737507392430228296" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/4737507392430228296?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/4737507392430228296?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/bryanbcook/~3/hUrqY4eSQN8/execute-batch-from-visual-studio.html" title="Execute Batch from Visual Studio" /><author><name>bryan</name><uri>http://www.blogger.com/profile/01332614158223702009</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh4.ggpht.com/-tm9UdYqRRt4/Tx2rfkzITlI/AAAAAAAAAi4/fnmfcB6SgMI/s72-c/image_thumb%25255B1%25255D.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.bryancook.net/2012/01/execute-batch-from-visual-studio.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkIEQX87fip7ImA9WhRRFEU.&quot;"><id>tag:blogger.com,1999:blog-8942599.post-2177118215865273552</id><published>2011-11-28T08:55:00.000-05:00</published><updated>2011-11-28T08:55:00.106-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-28T08:55:00.106-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Tips" /><category scheme="http://www.blogger.com/atom/ns#" term="Visual Studio" /><category scheme="http://www.blogger.com/atom/ns#" term="TDD" /><title>Fixing Parallel Test Execution in Visual Studio 2010</title><content type="html">&lt;p&gt;As the number of tests in my project grow, so does the length of my continuous integration build. Fortunately, the new parallel test execution of Visual Studio 2010 allow us to trim down the amount of time consumed by our unit tests. If your unit tests meet the criteria for thread-safety you can configure your unit tests to run in parallel simply by adding the following to your test run configuration:&lt;/p&gt;  &lt;pre class="brush: xml; gutter: false; toolbar: false; auto-links: false; highlight: [5];"&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;
&amp;lt;TestSettings name=&amp;quot;Local&amp;quot; id=&amp;quot;5082845d-c149-4ade-a9f5-5ff568d7ae62&amp;quot; xmlns=&amp;quot;http://microsoft.com/schemas/VisualStudio/TeamTest/2010&amp;quot;&amp;gt;
  &amp;lt;Description&amp;gt;These are default test settings for a local test run.&amp;lt;/Description&amp;gt;
  &amp;lt;Deployment enabled=&amp;quot;false&amp;quot; /&amp;gt;
  &amp;lt;Execution parallelTestCount=&amp;quot;0&amp;quot;&amp;gt;
    &amp;lt;TestTypeSpecific /&amp;gt;
    &amp;lt;AgentRule name=&amp;quot;Execution Agents&amp;quot;&amp;gt;
    &amp;lt;/AgentRule&amp;gt;
  &amp;lt;/Execution&amp;gt;
&amp;lt;/TestSettings&amp;gt;&lt;/pre&gt;

&lt;p&gt;The ideal setting of “0” implies that the test runner will automatically figure out the number of concurrent tests to execute based on the number of processors on the local machine. Based on this, a single-core CPU will run 1 test simultaneously, a dual-core CPU can run 2 and a quad-core CPU can 4. Technically, a quad-core hyper-threaded machine has 8 processors but when &lt;em&gt;parallelTestCount&lt;/em&gt; is set to zero the test run on that machine fails instantly:&lt;/p&gt;

&lt;p align="center"&gt;&lt;strong&gt;&lt;font color="#ff0000"&gt;Test run is aborting on '&amp;lt;machine-name&amp;gt;', number of hung tests exceeds maximum allowable '5'.&lt;/font&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;So what gives? &lt;/h3&gt;

&lt;p&gt;Well, routing through the disassembled source code for the test runner we learn that the number of tests that can be executed simultaneously interferes with the maximum number of tests that can hang before the entire test run is considered to be in a failed state. Unfortunately the maximum number of tests that can hang &lt;strong&gt;has been hardcoded to 5&lt;/strong&gt;. Effectively, when the 6th test begins to execute the test runner believes that the other 5 executing tests are in a failed state so it aborts everything. Maybe the team writing this feature picked “5” as an arbitrary number, or legitimately believed there wouldn’t be more than 4 CPUs before the product shipped, or simply didn’t make the connection between the setting and the possible hardware. I do sympathize for the mistake: the developers wanted the number to be low because a higher number could add several minutes to a build if the tests were actually in an non-responsive state.&lt;/p&gt;

&lt;p&gt;The &lt;a href="http://connect.microsoft.com/VisualStudio/feedback/details/587386/running-more-than-five-tests-in-parallel-does-not-work" target="_blank"&gt;Connect issue&lt;/a&gt; lists this feature as being fixed, although their are no posted workarounds and a there’s a lot of feedback that feature doesn’t work on high-end machines even with the latest service pack. But it &lt;em&gt;is&lt;/em&gt; fixed, no-one knows about it.&lt;/p&gt;

&lt;p&gt;Simply add the following to your registry (you will likely have to create the key) and configure the maximum amount based on your CPU. I’m showing the default value of 5, but I figure number of CPUs + 1 is probably right.&lt;/p&gt;
&lt;em&gt;Windows 32 bit:&lt;/em&gt; 

&lt;pre class="brush: plain; gutter: false; auto-links: false;"&gt;[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\10.0\EnterpriseTools\QualityTools\Agent]
&amp;quot;MaximumAllowedHangs&amp;quot;=&amp;quot;5&amp;quot;&lt;/pre&gt;
&lt;em&gt;Windows 64 bit:&lt;/em&gt; 

&lt;pre class="brush: plain; gutter: false; auto-links: false;"&gt;[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\EnterpriseTools\QualityTools\Agent]
&amp;quot;MaximumAllowedHangs&amp;quot;=&amp;quot;5&amp;quot; &lt;/pre&gt;

&lt;p&gt;Note: although you should be able to set the &lt;em&gt;parallelTestCount&lt;/em&gt; setting to anything you want, overall performance is constrained by the raw computing power of the CPU, so anything more than 1 test per CPU creates contention between threads which degrades performance. Sometimes I set the &lt;em&gt;parallelTestCount&lt;/em&gt; to 4 on my dual-core CPU to check for possible concurrency issues with the code or tests.&lt;/p&gt;

&lt;h3&gt;Epilogue&lt;/h3&gt;

&lt;p&gt;So what’s with the Connect issue? Having worked on enterprise software my guess is this: the defect was logged and subsequently fixed, the instructions were given to the tester and verified, but these instructions never tracked forward with the release notes or correlated back to the Connect issue. Ultimately there’s probably a small handful of people at Microsoft that actually know this registry setting exists, fewer that understand why, and those that do either work on a different team or no longer work for the company. Software is hard: one small fissure and the whole thing seems to fall apart. &lt;/p&gt;

&lt;p&gt;Something within the process is clearly missing. However, as a software craftsman and TDD advocate I’m less concerned that the process didn’t capture the workaround as I am that the code randomly pulls settings from the registry – this is a magic string hack that’s destined to get lost in the weeds. Why isn’t this number calculated based on the number of processors? Or better, why not make &lt;em&gt;MaximumAllowedHangs&lt;/em&gt; configurable from the test settings file so that it can be unit tested without tampering with the environment? How much more effort would it really take, assuming both solutions would need proper documentation and tests?&lt;/p&gt;

&lt;p&gt;Hope this helps.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8942599-2177118215865273552?l=www.bryancook.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/rcpQ-NCQMb7VFu3P7JVNHt8fWGk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/rcpQ-NCQMb7VFu3P7JVNHt8fWGk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/rcpQ-NCQMb7VFu3P7JVNHt8fWGk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/rcpQ-NCQMb7VFu3P7JVNHt8fWGk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=h_c-G4hlA7Q:1I7QqWxnZ1E:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=h_c-G4hlA7Q:1I7QqWxnZ1E:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=h_c-G4hlA7Q:1I7QqWxnZ1E:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=h_c-G4hlA7Q:1I7QqWxnZ1E:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?i=h_c-G4hlA7Q:1I7QqWxnZ1E:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bryanbcook/~4/h_c-G4hlA7Q" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.bryancook.net/feeds/2177118215865273552/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8942599&amp;postID=2177118215865273552" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/2177118215865273552?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/2177118215865273552?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/bryanbcook/~3/h_c-G4hlA7Q/fixing-parallel-test-execution-in.html" title="Fixing Parallel Test Execution in Visual Studio 2010" /><author><name>bryan</name><uri>http://www.blogger.com/profile/01332614158223702009</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.bryancook.net/2011/11/fixing-parallel-test-execution-in.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak8HRnc9fyp7ImA9WhRREUs.&quot;"><id>tag:blogger.com,1999:blog-8942599.post-2627090543634396557</id><published>2011-11-24T16:07:00.001-05:00</published><updated>2011-11-24T16:07:17.967-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-24T16:07:17.967-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="cool tech" /><category scheme="http://www.blogger.com/atom/ns#" term="Tips" /><title>iPhone to PC Adapter</title><content type="html">&lt;p&gt;&lt;strike&gt;Merry&lt;/strike&gt; Happy Thanks Giving! I had some time on my hands so I decided to try something new.&lt;/p&gt;  &lt;p&gt;Here’s a quick review of my iPhone headset to PC adapter that I bought a few weeks ago. Hopefully this video comes just in time for Christmas ideas and Black Friday shopping. &lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:5737277B-5D6D-4f48-ABFC-DD9C333F4C5D:0f612cf5-eb84-421d-8fd9-a291e86f8eab" class="wlWriterEditableSmartContent"&gt;&lt;div id="819d9161-5728-4bd1-a7d0-21213e1125e4" style="margin: 0px; padding: 0px; display: inline;"&gt;&lt;div&gt;&lt;a href="http://www.youtube.com/watch?v=GJCHsgZn2hY&amp;amp;feature=youtube_gdata_player" target="_new"&gt;&lt;img src="http://lh6.ggpht.com/-vvm0NzE68Bs/Ts6yBR1O-vI/AAAAAAAAAig/A-djmUXo2G0/video9fddb06bb5bf%25255B15%25255D.jpg?imgmax=800" style="border-style: none" galleryimg="no" onload="var downlevelDiv = document.getElementById('819d9161-5728-4bd1-a7d0-21213e1125e4'); downlevelDiv.innerHTML = &amp;quot;&amp;lt;div&amp;gt;&amp;lt;object width=\&amp;quot;576\&amp;quot; height=\&amp;quot;324\&amp;quot;&amp;gt;&amp;lt;param name=\&amp;quot;movie\&amp;quot; value=\&amp;quot;http://www.youtube.com/v/GJCHsgZn2hY?hl=en&amp;amp;hd=1\&amp;quot;&amp;gt;&amp;lt;\/param&amp;gt;&amp;lt;embed src=\&amp;quot;http://www.youtube.com/v/GJCHsgZn2hY?hl=en&amp;amp;hd=1\&amp;quot; type=\&amp;quot;application/x-shockwave-flash\&amp;quot; width=\&amp;quot;576\&amp;quot; height=\&amp;quot;324\&amp;quot;&amp;gt;&amp;lt;\/embed&amp;gt;&amp;lt;\/object&amp;gt;&amp;lt;\/div&amp;gt;&amp;quot;;" alt=""&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;  &lt;p&gt;By the way, Thanks Giving was 5 weeks ago.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8942599-2627090543634396557?l=www.bryancook.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/e8RPyZEi0OK09Xv8vYaf9YVumAM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/e8RPyZEi0OK09Xv8vYaf9YVumAM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/e8RPyZEi0OK09Xv8vYaf9YVumAM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/e8RPyZEi0OK09Xv8vYaf9YVumAM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=mgf7cP4ZZys:nOXo1eYtOQU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=mgf7cP4ZZys:nOXo1eYtOQU:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=mgf7cP4ZZys:nOXo1eYtOQU:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=mgf7cP4ZZys:nOXo1eYtOQU:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?i=mgf7cP4ZZys:nOXo1eYtOQU:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bryanbcook/~4/mgf7cP4ZZys" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.bryancook.net/feeds/2627090543634396557/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8942599&amp;postID=2627090543634396557" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/2627090543634396557?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/2627090543634396557?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/bryanbcook/~3/mgf7cP4ZZys/iphone-to-pc-adapter.html" title="iPhone to PC Adapter" /><author><name>bryan</name><uri>http://www.blogger.com/profile/01332614158223702009</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh6.ggpht.com/-vvm0NzE68Bs/Ts6yBR1O-vI/AAAAAAAAAig/A-djmUXo2G0/s72-c/video9fddb06bb5bf%25255B15%25255D.jpg?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.bryancook.net/2011/11/iphone-to-pc-adapter.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C08EQXs9fip7ImA9WhRSGUU.&quot;"><id>tag:blogger.com,1999:blog-8942599.post-5173715046469351951</id><published>2011-11-22T12:07:00.002-05:00</published><updated>2011-11-22T12:10:00.566-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-22T12:10:00.566-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".net" /><category scheme="http://www.blogger.com/atom/ns#" term="TDD" /><category scheme="http://www.blogger.com/atom/ns#" term="Software Design" /><title>Static is Dead to Me</title><content type="html">&lt;p&gt;The more software I write with a test-first methodology, the more I struggle with the use of singletons and static classes. They’ve become a design smell, and I’ve grown to realize that if given enough care and thought towards a design most static dependencies aren’t needed. My current position is that most singletons are misplaced artefacts without a proper home, and static methods seem like an amateurish gateway to procedural programming.&lt;/p&gt;  &lt;p&gt;Despite my obvious knee-jerk loathing for static, in truth there’s nothing really wrong with it -- it’s hard to build any real-world application without the use of some static methods. I continue to use static in my applications but its use is reserved for fundamental top-level application services. All told, there should only be a handful of classes that are accessible as static members.&lt;/p&gt;  &lt;p&gt;From a test-driven development perspective, there are several strong arguments against the use of static:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Lack of Isolation.&lt;/strong&gt; When a class uses a static method in another type, it becomes directly coupled to that implementation. From a testing perspective it becomes impossible to test the consuming class without satisfying the requirements of the static dependency. This increases the complexity and fragility of the tests as the implementation details of the static dependency leak into many tests. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Side Effects.&lt;/strong&gt; Static methods allow us to define objects that maintain state that is global in nature. This global state represents a problem from a testing perspective because any state that must be set up for a test fixture must be reset after the test completes. Failure to clean-up the global state can corrupt the environment and lead to &lt;em&gt;side-effects in other tests&lt;/em&gt; that depend on this shared state. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Inability to run tests in parallel.&lt;/strong&gt; A fundamental requirement for reliable tests is a predictable, well-known state before and after each test. If tests depend on global state that can be mutated by multiple tests simultaneously then it is impossible to run more than one test at a time. Given the raw computing power of a hyper-threaded, multi-core machine, it seems a crime to design our code that limits testing to only one core. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Hidden dependencies. &lt;/strong&gt;Classes that pull dependencies into them from a static singleton or service-locator &lt;a href="http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/"&gt;creates an API that lies to you&lt;/a&gt;. Tests for these classes become unnecessarily complex and increasingly brittle. &lt;/li&gt; &lt;/ul&gt;  &lt;h3&gt;An Alternative to Static&lt;/h3&gt;  &lt;p&gt;Rather than designing objects to be global services that are accessed through static methods, I design them to be regular objects first. There are no static methods or fields. Classes are designed to be thread-safe, but make no assumptions about their lifetime.&lt;/p&gt;  &lt;p&gt;This small change means that I expect all interaction to be with an instance of my object rather through a member that is Type specific. This suggests two problems: how will consumers of my class obtain a reference to my object, and how do I ensure that all consumers use the same object?&lt;/p&gt;  &lt;h4&gt;Obtaining a Reference&lt;/h4&gt;  &lt;p&gt;Not surprisingly, the problem related to obtaining a reference to my object is easily solved using my favourite Inversion of Control technique, Constructor Injection. While there are many IoC patterns to choose from, I prefer constructor injection for the following reasons:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Consuming classes do not have to depend on a specific framework to obtain a reference. &lt;/li&gt;    &lt;li&gt;Consuming classes are explicit about their required dependencies. This fosters a consistent and meaningful API where objects are assembled in predictable and organized manner rather than randomly consumed. &lt;/li&gt;    &lt;li&gt;Consuming classes don’t have to worry about which instance or the lifetime of the object they have received. This solves many testing problems as concurrent tests can work with different objects. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;The difference between accessing my object through a static member versus an object instance is very subtle, but the main distinction is that using the object reference requires some forethought as the dependency must be explicitly defined as a member of the consuming class.&lt;/p&gt;  &lt;h4&gt;Obtaining the Same Reference&lt;/h4&gt;  &lt;p&gt;By forgoing the use of static, we’ve removed the language feature that would simplify the ability to ensure only a single instance of our object is consumed. Without &lt;em&gt;static &lt;/em&gt;we need to solve this problem through the structure of our code or through features of our application architecture. Without a doubt it’s harder, but I consider the well structured and tested code worth it (so don’t give up).&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;em&gt;Eliminating Singletons through Code Structure:&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;My original position is that most singletons are simply misplaced artefacts. By this I mean static is used for its convenience rather than to expose the class as a global application service. In these situations it’s far more likely that the static class provides a service that is used in one area of the application graph. I’d argue that with some analysis the abstraction or related classes could be rearranged to create and host the service as an instance thereby negating the need for a singleton.&lt;/p&gt;  &lt;p&gt;This approach typically isn’t easy because the analysis requires you to understand the lifetime and relationship of all objects in the graph. For small applications with emergent design, the effort is obtainable and extremely rewarding when all the pieces fit together nicely. The effort for larger applications may require a few attempts to get it right. Regardless of application size, sticking with an inverted dependencies approach will make the problem obvious when it occurs. &lt;/p&gt;  &lt;p&gt;An inversion of control container can lessen the pain.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;i&gt;Eliminating Singletons through Architecture:&lt;/i&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Perhaps my favourite mechanism for eliminating singletons is to use an Inversion of Control container and configure it with the responsibility of maintaining the object lifetime.&lt;/p&gt;  &lt;p&gt;This example shows programmatic registration of a concrete type as a singleton.&lt;/p&gt;  &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;private void InitializeGlobalServices(IUnityContainer container)
{
   // configure the container to cache a single instance of the service
   // the first time it is used.
   container.RegisterType&amp;lt;MyServiceProvider&amp;gt;(new ContainerControlledLifetimeManager());
}&lt;/pre&gt;

&lt;p&gt;The real advantage here is that any object can be made static without rewriting code. As a further optimization, we can also introduce an interface:&lt;/p&gt;

&lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;private void InitializeGlobalService(IUnityContainer container)
{
   container.RegisterType&amp;lt;IServiceProvider,MyServiceProvider(
       new ContainerControlledLifetimeManager());
}&lt;/pre&gt;

&lt;h3&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Somewhere in my career I picked up the design philosophy that “&lt;i&gt;objects should not have a top”&lt;/i&gt;, meaning that they should be open-ended in order to remix them into different applications. Eventually the "top" is the main entry-point into the application which is responsible for assembling the objects to create the application. &lt;/p&gt;

&lt;p&gt;Dependency Injection fits nicely into this philosophy and in my view is the principle delivery mechanism for loosely coupled and testable implementations. Static however works against this in every regard: it couples us to implementations and limits our capability to test.&lt;/p&gt;

&lt;p&gt;The clear winner is dependency injection backed by the power of an inversion of control container that can do the heavy lifting for you. As &lt;a href="http://www.bryancook.net/2011/08/on-dependency-injection-and-violating.html" target="_blank"&gt;per my previous post&lt;/a&gt;, if you limit usage of the container to the top-level components, life is simple.&lt;/p&gt;

&lt;p&gt;Happy coding.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8942599-5173715046469351951?l=www.bryancook.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/b7RsNAgoiYdbkuLXuC6rbmypTR0/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/b7RsNAgoiYdbkuLXuC6rbmypTR0/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/b7RsNAgoiYdbkuLXuC6rbmypTR0/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/b7RsNAgoiYdbkuLXuC6rbmypTR0/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=fBhBUgSo2SE:4jX8CNWHC_g:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=fBhBUgSo2SE:4jX8CNWHC_g:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=fBhBUgSo2SE:4jX8CNWHC_g:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=fBhBUgSo2SE:4jX8CNWHC_g:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?i=fBhBUgSo2SE:4jX8CNWHC_g:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bryanbcook/~4/fBhBUgSo2SE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.bryancook.net/feeds/5173715046469351951/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8942599&amp;postID=5173715046469351951" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/5173715046469351951?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/5173715046469351951?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/bryanbcook/~3/fBhBUgSo2SE/more-software-i-write-with-test-first.html" title="Static is Dead to Me" /><author><name>bryan</name><uri>http://www.blogger.com/profile/01332614158223702009</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.bryancook.net/2011/11/more-software-i-write-with-test-first.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0EDSHY6cSp7ImA9WhdaFEs.&quot;"><id>tag:blogger.com,1999:blog-8942599.post-6103177670055872487</id><published>2011-10-24T10:14:00.001-04:00</published><updated>2011-10-24T10:14:39.819-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-24T10:14:39.819-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".net" /><category scheme="http://www.blogger.com/atom/ns#" term="TDD" /><category scheme="http://www.blogger.com/atom/ns#" term="guided by tests" /><title>Guided by Tests–Wrap Up</title><content type="html">&lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;This post is ninth and last in a series about a group TDD experiment to build an application in &lt;strike&gt;5&lt;/strike&gt; 7 days using only tests.&amp;#160; Read the &lt;a href="http://www.bryancook.net/2011/09/guided-by-tests.html"&gt;beginning here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;This last post is aimed at wrapping up the series by looking back at some of the metrics we can collect from our code and tests. There’s some interesting data about the experiment as well as feedback for the design available.&lt;/p&gt;  &lt;p&gt;We’ll use three different data sources for our application metrics:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Visual Studio Code Analysis &lt;/li&gt;    &lt;li&gt;MSTest Code Coverage &lt;/li&gt;    &lt;li&gt;NDepend Code Analysis &lt;/li&gt; &lt;/ul&gt;  &lt;h3&gt;Visual Studio Code Analysis&lt;/h3&gt;  &lt;p&gt;The code analysis features of Visual Studio 2010 provide a convenient view of some common static analysis metrics. Note that &lt;a href="http://blogs.msdn.com/b/codeanalysis/archive/2010/03/22/what-s-new-in-code-analysis-for-visual-studio-2010.aspx"&gt;this feature only ships&lt;/a&gt; with the Premium and Ultimate versions. Here’s a quick screen capture that shows a high level view of the metrics for our project. &lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;Tip: When reading the above graph, keep an eye on the the individual class values not the roll-up namespace values.&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/-ZuQNYsf0Mhg/TqVyw1ta4JI/AAAAAAAAAhM/zwtenGzT0vs/s1600-h/image3.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/-woktprEhvbw/TqVyxtdN1pI/AAAAAAAAAhU/NiQiYjl3WMk/image_thumb1.png?imgmax=800" width="644" height="337" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Here’s a breakdown of what some of these metrics mean and what we can learn from our experiment. &lt;/p&gt;  &lt;h4&gt;Maintainability Index&lt;/h4&gt;  &lt;p&gt;I like to think of the Maintainability Index as a high level metric that summarizes how much trouble a class is going to give you over time. Higher numbers are better, and problems usually start below the 20-30 range. The formula for the maintainability index is actually quite complex, but looking at the above data you can see how the other metrics drive the index down. &lt;/p&gt;  &lt;p&gt;Our &lt;em&gt;GraphBuilder&lt;/em&gt; is the lowest in our project, coming in at an index of 69. This is largely influenced by the density of operations and complexity to lines of code – our &lt;em&gt;GraphBuilder&lt;/em&gt; is responsible for constructing the graph from conditional logic of the model. The maintainability index is interesting, but I don’t hold much stock in it alone.&lt;/p&gt;  &lt;h4&gt;Lines of Code&lt;/h4&gt;  &lt;p&gt;Lines of Code is the logical lines of code which means code lines without whitespace and stylistic formatting. Some tools, like NDepend, record other metrics for lines of code, such as number of IL instructions per line. Visual Studio’s Lines of Code metric is simple and straight forward.&lt;/p&gt;  &lt;p&gt;There are a few interesting observations for our code base. &lt;/p&gt;  &lt;p&gt;First, the number of lines of code per class is quite low. Even the &lt;em&gt;NDependStreamParser&lt;/em&gt; which tops the chart at 22 lines is extremely low considering that it reads data from several different Xml Elements. The presence of many small classes suggests that classes are designed to do one thing well.&lt;/p&gt;  &lt;p&gt;Secondly, there are more lines of code in our test project than production code. Some may point to this as evidence that unit testing introduces more effort than writing the actual code – I see the additional code as the following:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;We created hand-rolled mocks and utility classes to generate input. These are not present in the production code. &lt;/li&gt;    &lt;li&gt;Testing code is more complicated than writing it as there are many different paths the code might take. There should be more code here. &lt;/li&gt;    &lt;li&gt;We didn’t write the code and then the tests, we did them at the same time &lt;/li&gt;    &lt;li&gt;Our tests ensured that we only wrote code needed to make the tests pass. This allowed us to aggressively remove all duplication in the production code. &lt;em&gt;Did I mention the largest and most complicated class is 22 lines long?&lt;/em&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;h4&gt;Cyclomatic Complexity&lt;/h4&gt;  &lt;p&gt;Cyclomatic Complexity, also known as Conditional Complexity, represents the number of paths of execution a method can have – so classes that have a &lt;em&gt;switch&lt;/em&gt; or multiple &lt;em&gt;if&lt;/em&gt; statements will have higher complexity than those that do not. The metric is normally applied at the method level, not the class, but if you look at the graph above, more than half of the classes average below 5 and the other half are less than 12. Best practices suggest that Cyclomatic Complexity should be less than 15-20 &lt;em&gt;per method&lt;/em&gt;. So we’re good.&lt;/p&gt;  &lt;p&gt;Although the graph above doesn’t display our 45 methods, the cyclomatic complexity for most methods is 1-2. The only exception to this is our &lt;em&gt;NDependStreamParser&lt;/em&gt; and &lt;em&gt;GraphBuilder&lt;/em&gt;, which have methods with a complexity value of 6 and 5 respectively.&lt;/p&gt;  &lt;p&gt;In my view, I see cyclomatic complexity as a metric for how many tests are needed for a class.&lt;/p&gt;  &lt;h4&gt;Depth of Inheritance&lt;/h4&gt;  &lt;p&gt;The “depth of inheritance” metric refers to the number of base classes involved in the inheritance of a class. Best practices aim to keep this number as low as possible since each level in the inheritance hierarchy represents a dependency that can influence or break implementers.&lt;/p&gt;  &lt;p&gt;Our graph shows very low inheritance depth which supports our design philosophy of using composition and dependency inversion instead of inheritance. There are a few red flags in the graph though: our &lt;em&gt;AssemblyGraphLayout&lt;/em&gt; has an inheritance depth of 9, a consequence of extending &lt;a href="http://graphsharp.codeplex.com/SourceControl/changeset/view/e0b4fccb9d23#Source%2fGraph%23.Controls%2fControls%2fGraphLayout.cs"&gt;a class from the GraphSharp library&lt;/a&gt; and it highlights possible brittleness surrounding that library.&lt;/p&gt;  &lt;h4&gt;Class Coupling&lt;/h4&gt;  &lt;p&gt;The class coupling metric is a very interesting metric because it shows us how many classes our object consumes or creates. Although we don’t get much visibility into the coupling (NDepend can help us here) it suggests that classes with a higher coupling are much more sensitive to changes. Our &lt;em&gt;GraphBuilder&lt;/em&gt; has a Class Coupling of 11, including several types from the System namespace (&lt;em&gt;IEnumerable&amp;lt;T&amp;gt;,&lt;/em&gt; &lt;em&gt;Dictionary&lt;/em&gt;, &lt;em&gt;KeyValuePair&lt;/em&gt;) but also has knowledge of our Graph and model data.&lt;/p&gt;  &lt;p&gt;Class coupling combined with many lines of code and high cyclomatic complexity are highly sensitive to change, which explains why the &lt;em&gt;GraphBuilder&lt;/em&gt; has the lowest Maintenance Index of the bunch.&lt;/p&gt;  &lt;h3&gt;Code Coverage&lt;/h3&gt;  &lt;p&gt;Code coverage is a metric that shows which execution paths within our code base are covered by unit tests. While code coverage can’t vouch for the quality of the tests or production code, it can indicate the strength of the testing strategy.&lt;/p&gt;  &lt;p&gt;Under the rules of our experiment, there should be 100% code coverage because we’ve mandated that no code is written without a test. We have 93.75% coverage, which has the following breakdown:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/-IyRD319URz4/TqVyyAYlVnI/AAAAAAAAAhc/vtdszUI0SNc/s1600-h/DependencyViewer-Coverage3.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="DependencyViewer-Coverage" border="0" alt="DependencyViewer-Coverage" src="http://lh4.ggpht.com/-YvRMRXFqico/TqVyyaJBiqI/AAAAAAAAAhk/YiHDXd4BU28/DependencyViewer-Coverage_thumb1.png?imgmax=800" width="644" height="297" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Interestingly enough, the three areas of with no code coverage are the key obstacles we identified early in the experiment. Here are the snippets of code that have no coverage:&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Application Start-up Routine&lt;/strong&gt;&lt;/p&gt;  &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;protected override void OnStartup(StartupEventArgs e)
{
    var shell = new Shell();
    shell.DataContext = new MainViewModelFactory().Create();

    shell.Show();
}&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Launching the File Dialog&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;internal virtual void ShowDialog(OpenFileDialog dialog)
{
    dialog.ShowDialog();
}&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Code behind for Shell&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;public Shell()
{
    InitializeComponent();
}&lt;/pre&gt;

&lt;p&gt;We’ve designed our solution to limit the amount of “untestable” code, so these lines of code are expected. From this we can establish that our testing strategy has three weaknesses, two of which are covered by launching the application. If we wanted to write automation for testing the user-interface, these would be the areas we’d want early feedback from. &lt;/p&gt;

&lt;h3&gt;NDepend Analysis&lt;/h3&gt;

&lt;p&gt;NDepend is a static code analysis tool that provides more detailed information than the standard Visual Studio tools. The product has several different pricing levels including open-source and evaluation licenses and has many great visualizations and features that can help you learn more about your code. While there are many visuals that I could present here, I’m listing two interesting diagrams.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DependencyGraph:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This graph shows dependencies between namespaces. I’ve configured this graph to show two things:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Box Size represents Afferent Coupling where larger boxes are used by many classes &lt;/li&gt;

  &lt;li&gt;Line Size represents the number of methods between the dependent components. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="http://lh6.ggpht.com/-OhDZDr0EsbQ/TqVyylw-lsI/AAAAAAAAAhs/YHCNPgBY6yw/s1600-h/DependencyMatrix-Graph3.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="DependencyMatrix-Graph" border="0" alt="DependencyMatrix-Graph" src="http://lh5.ggpht.com/-0zgEaHodgdw/TqVyy00U6dI/AAAAAAAAAh0/a9TmJcTR0Ak/DependencyMatrix-Graph_thumb1.png?imgmax=800" width="644" height="199" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dependency Matrix:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A slightly different view of the same information is the Dependency Matrix. This is the graph represented in a cross-tabular format.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh4.ggpht.com/-mcEfObxom1Y/TqVyzP1KAYI/AAAAAAAAAh8/ZwwHIkKqKbE/s1600-h/DependencyMatrix-Namespaces3.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="DependencyMatrix-Namespaces" border="0" alt="DependencyMatrix-Namespaces" src="http://lh6.ggpht.com/-kw77mu89sVU/TqVyzrXGw2I/AAAAAAAAAiE/kvFt2hSiE2s/DependencyMatrix-Namespaces_thumb1.png?imgmax=800" width="644" height="474" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Both of these views help us better visualize the Class Coupling metric that Visual Studio pointed out earlier, but the information it provides is quite revealing. Both diagrams show that the &lt;em&gt;Model&lt;/em&gt; namespace is used by the &lt;em&gt;ViewModels&lt;/em&gt; and &lt;em&gt;Controls&lt;/em&gt; namespaces. This represents a refactoring or restructuring problem as these layers really should not be aware of the model: Views shouldn’t have details about the ViewModel; Service layer should only know about the Model and ViewModels; Controls should know about ViewModel data if needed; ViewModels should represent view-abstractions and thus should not have Model knowledge.&lt;/p&gt;

&lt;p&gt;The violations have occurred because we established our AssemblyGraph and related items as part of the model.&amp;#160; This was a concept we wrestled with at the beginning of the exercise, and now the NDepend graph helps visualize the problem more concretely. As a result of this choice, we’re left with the following violations:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The control required to layout our graph is a GraphLayout that uses our Model objects. &lt;/li&gt;

  &lt;li&gt;The MainViewModel references the Graph as a property which is bound to the View. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The diagram shows a very thin line, but this model to view model state problem has become a common theme in recent projects. Maybe we need a state container to hold onto the Model objects and maybe the Graph should be composed of ViewModel objects instead of Model data. It’s worth consideration, and maybe I’ll revisit this and blog about this problem some more in an upcoming post.&lt;/p&gt;

&lt;h3&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;To wrap up the series, let’s look back on how we got here:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;We started things off by &lt;a href="http://www.bryancook.net/2011/09/guided-by-testsday-two.html"&gt;breaking the use case down&lt;/a&gt; into small logical chunks. This separation of concerns approach allowed us to create small focused classes and reduced the amount of complexity overall.&lt;/li&gt;

  &lt;li&gt;When we started coding, we &lt;a href="http://www.bryancook.net/2011/09/guided-by-testsday-two.html"&gt;started with the area we knew most about&lt;/a&gt; and we leveraged our knowledge of the NDepend file format to create a reader that would build up a model object for us.&lt;/li&gt;

  &lt;li&gt;We worked backward, and &lt;a href="http://www.bryancook.net/2011/09/guided-by-testsday-three.html"&gt;we isolated the problematic areas&lt;/a&gt; and stubbed them out with an interface until we could revisit their implementation. We &lt;a href="http://www.bryancook.net/2011/09/guided-by-testsday-three.html"&gt;created hand-rolled mocks&lt;/a&gt; and later &lt;a href="http://www.bryancook.net/2011/09/guided-by-testsday-five.html"&gt;used a framework to dynamically generate mock&lt;/a&gt; implementations for us.&lt;/li&gt;

  &lt;li&gt;We iteratively realized parts of our use case, which meant we actively thought about how these components would be used by callers. Under &lt;a href="http://www.bryancook.net/2011/09/guided-by-testsday-one.html"&gt;the rules of our experiment&lt;/a&gt;, we wrote tests to satisfy those scenarios.&lt;/li&gt;

  &lt;li&gt;After &lt;a href="http://www.bryancook.net/2011/10/guided-by-testsday-six.html"&gt;linking all the parts together&lt;/a&gt; and repurposing some XAML, we had our first run of the application. We came back and &lt;a href="http://www.bryancook.net/2011/10/guided-by-testsday-seven.html"&gt;flushed out the implementation of our FileDialog using tests&lt;/a&gt; for what would normally be considered “untestable”.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope you have enjoyed the series and found something to take away. I challenge you to find a similar problem and champion its development within your development group.&lt;/p&gt;

&lt;p&gt;Happy Coding.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8942599-6103177670055872487?l=www.bryancook.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/vgcegbcEIWU1jVN1EgUhOO2jJno/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/vgcegbcEIWU1jVN1EgUhOO2jJno/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/vgcegbcEIWU1jVN1EgUhOO2jJno/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/vgcegbcEIWU1jVN1EgUhOO2jJno/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=3smvslyAgT8:T6FB2_YkgqQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=3smvslyAgT8:T6FB2_YkgqQ:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=3smvslyAgT8:T6FB2_YkgqQ:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=3smvslyAgT8:T6FB2_YkgqQ:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?i=3smvslyAgT8:T6FB2_YkgqQ:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bryanbcook/~4/3smvslyAgT8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.bryancook.net/feeds/6103177670055872487/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8942599&amp;postID=6103177670055872487" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/6103177670055872487?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/6103177670055872487?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/bryanbcook/~3/3smvslyAgT8/guided-by-testswrap-up.html" title="Guided by Tests–Wrap Up" /><author><name>bryan</name><uri>http://www.blogger.com/profile/01332614158223702009</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh5.ggpht.com/-woktprEhvbw/TqVyxtdN1pI/AAAAAAAAAhU/NiQiYjl3WMk/s72-c/image_thumb1.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.bryancook.net/2011/10/guided-by-testswrap-up.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEcFSXs8fSp7ImA9WhdaFEs.&quot;"><id>tag:blogger.com,1999:blog-8942599.post-577556121957828315</id><published>2011-10-11T09:00:00.000-04:00</published><updated>2011-10-24T10:20:18.575-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-24T10:20:18.575-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".net" /><category scheme="http://www.blogger.com/atom/ns#" term="TDD" /><category scheme="http://www.blogger.com/atom/ns#" term="guided by tests" /><title>Guided by Tests–Day Seven</title><content type="html">&lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;This post is eighth in a series about a group TDD experiment to build an application in &lt;strike&gt;5&lt;/strike&gt; 7 days using only tests.&amp;#160; Read the &lt;a href="http://www.bryancook.net/2011/09/guided-by-tests.html"&gt;beginning here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Today is the day we test the untestable. Early in the experiment &lt;a href="http://www.bryancook.net/2011/09/guided-by-testsday-three.html"&gt;we hit a small road block&lt;/a&gt; when our code needed to interact with the user-interface. Since unit-testing the user-interface wasn’t something we wanted to pursue, we wrapped the &lt;em&gt;OpenFileDialog&lt;/em&gt; behind a wrapper with an expectation that we would return to build out that component with tests later. The session for this day would prove to be an interesting challenge.&lt;/p&gt;  &lt;h3&gt;The Challenges of Physical Dependencies&lt;/h3&gt;  &lt;p&gt;Although using a wrapper to shield our code from difficult to test dependencies is a common and well accepted technique, it would be irresponsible not to test the internal implementation details of that wrapper. Testing against physical dependencies is hard because they introduce a massive amount of overhead, but if we can isolate the logic from the physical dependency we can use unit tests to get 80-90% of the way there. To get the remaining part, you either test manually or write a set of integration or functional tests.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;The technique outlined below can be used for testing user-interface components like this one, email components and in a pinch it can work for network related services.&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;h3&gt;&lt;/h3&gt;  &lt;h3&gt;Testing our Wrapper&lt;/h3&gt;  &lt;p&gt;Time to write some tests for our &lt;em&gt;IFileDialog&lt;/em&gt;. I have some good news and bad news.&lt;/p&gt;  &lt;p&gt;The good news is Microsoft provides a common OpenFileDialog as part of WPF, meaning that I don’t have to roll my own and I can achieve a common look and feel with other applications with little effort. This also means we can assume that the &lt;em&gt;FileOpenDialog&lt;/em&gt; is defect free, so we don’t have to write unit tests for it.&lt;/p&gt;  &lt;p&gt;The bad news is, I use this common so infrequently that I forget how to use it. &lt;/p&gt;  &lt;p&gt;So instead of writing a small utility application to play with the component, I write a test that shows me exactly how the component works:&lt;/p&gt;  &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;[TestMethod]
public void WhenSelectAFileFromTheDialog_AndUserSelectsAFile_ShouldReturnFileName()
{
    var dialog = new OpenFileDialog();
    dialog.Show(); // this will show the dialog

    Assert.IsNotNull(dialog.FileName); 
}&lt;/pre&gt;

&lt;p&gt;When I run this test, the file dialog is displayed. If I don’t select a file, the test fails. Now that we know how it works, we can rewrite our test and move this code into a concrete implementation.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Unit Test:&lt;/b&gt; &lt;/p&gt;

&lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;[TestMethod]
public void WhenSelectingAFile_AndUserMakesAValidSelection_ShouldReturnFileName()
{
    var subject = new FileDialog();
    string fileName = subject.SelectFile();
    Assert.IsNotNull(fileName);
}&lt;/pre&gt;

&lt;p&gt;&lt;b&gt;Production Code:&lt;/b&gt; &lt;/p&gt;

&lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;public class FileDialog : IFileDialog
{
    public string SelectFile()
    {
        var dialog = new OpenFileDialog();
        dialog.Show();

        return dialog.FileName;
    }
}&lt;/pre&gt;

&lt;p&gt;The implementation is functionally correct, but when I run the test I have to select a file in order to have the test pass. This is not ideal. We need a means to intercept the dialog and simulate the user selecting a file. Otherwise, someone will have to babysit the build and manually click file dialog prompts until the early morning hours.&lt;/p&gt;

&lt;h3&gt;Partial Mocks To the Rescue&lt;/h3&gt;

&lt;p&gt;Instead of &lt;em&gt;isolating the instance&lt;/em&gt; of our &lt;em&gt;OpenFileDialog&lt;/em&gt; with a mock implementation, we intercept &lt;em&gt;the activity&lt;/em&gt; and allow ourselves to supply a different implementation for our test. The following shows a simple change to the code to make this possible.&lt;/p&gt;

&lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;public class FileDialog : IFileDialog
{
    public string SelectFile()
    {
        var dialog = new OpenFileDialog();

        Show(dialog);

        return dialog.FileName;
    }

    internal virtual void Show(OpenFileDialog dialog)
    {
        dialog.Show();
    }
}&lt;/pre&gt;

&lt;p&gt;This next part is a bit weird. In the last several posts, we’ve used Moq to replace our dependencies with fake stand-in implementations. For this post, we’re going to mock &lt;em&gt;the subject of the test&lt;/em&gt;, and fake out specific methods on the subject. Go back and re-read that. You can stop re-reading that now.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;As an aside: I often don’t like showing this technique because I’ve seen it get abused. I’ve seen abuses where developers use this technique to avoid breaking classes down into smaller responsibilities; they fill their classes with virtual methods and then stub out huge chunks of the subject. This feels like shoddy craftsmanship and doesn’t sit well with me – granted, it works, but it leads to problems. First, the areas that they’re subverting never get tested. Secondly, it’s too easy for developers to forget what they’re doing and they start to write tests for the mocking framework instead of the subject’s functionality. So use with care. In this example, I’m subverting one line of a well tested third-party component in order to avoid human-involvement in the test.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In order to intercept the &lt;em&gt;Show&lt;/em&gt; method and replace it with our own implementation we can use Moq’s &lt;em&gt;Callback&lt;/em&gt; feature. &lt;a href="http://www.bryancook.net/2010/10/callbacks-with-moq.html"&gt;I’ve written about this Moq’s support for Callbacks before&lt;/a&gt;, but in a nutshell Moq can intercept the original method and inbound arguments for use within your test. &lt;/p&gt;

&lt;p&gt;Our test now looks like this:&lt;/p&gt;

&lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;[TestMethod]
public void WhenSelectingAFile_AndUserMakesAValidSelection_ShouldReturnFileName()
{
    // setup a partial mock for our subject
    var mock = new Mock&amp;lt;FileDialog&amp;gt;();
    FileDialog subject = mock.Object;

    // The Show method in our FileDialog is virtual, so we can setup
    //    an alternate behavior when it's called.
    // We configure the Show method to call the SelectAFile method
    //    with the original arguments
    mock.Setup( partialMock =&amp;gt; partialMock.Show(It.IsAny&amp;lt;OpenFileDialog&amp;gt;())
        .Callback( SelectAFile );

    string fileName = subject.SelectFile();
    Assert.IsNotNull(fileName);
}

// we alter the original inbound argument to simulate
//    the user selecting a file
private void SelectAFile(OpenFileDialog dialog)
{
    dialog.FileName = &amp;quot;Foo&amp;quot;;
}&lt;/pre&gt;

&lt;p&gt;Now when our test runs the FileDialog returns “Foo” without launching a popup. Now we can write tests for a few extra scenarios:&lt;/p&gt;

&lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;[TestMethod]
public void WhenSelectingAFile_AndTheUserCancelsTheFileDialog_NoFileNameShouldBeReturned()
{
    // we're mocking out the call to show the dialog,
    // so without any setup on the mock, the dialog will not return a value.

    string fileName = Subject.SelectFile();

    Assert.IsNull(fileName);
}

[TestMethod]
public void WhenSelectingAFile_BeforeUserSelectsAFile_EnsureDefaultDirectoryIsApplicationRootFolder()
{
    // ARRANGE:
    string expectedDirectory = Environment.CurrentDirectory;

    Mock.Get(Subject)
        .Setup(d =&amp;gt; d.ShowDialog(It.IsAny&amp;lt;OpenFileDialog&amp;gt;()))
        .Callback&amp;lt;OpenFileDialog&amp;gt;(
            win32Dialog =&amp;gt;
            {
                // ASSERT: validate that the directory is set when the dialog is shown
                Assert.AreEqual(expectedDirectory, win32Dialog.InitialDirectory);
            });

    // ACT: invoke showing the dialog
    Subject.SelectFile();
}&lt;/pre&gt;

&lt;p&gt;Next: Review some of the application metrics for our experiment in the &lt;a href="http://www.bryancook.net/2011/10/guided-by-testswrap-up.html"&gt;Guided by Tests – Wrap Up&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8942599-577556121957828315?l=www.bryancook.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/pEYAJy8obexhYox7j9GOh8yQYSk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/pEYAJy8obexhYox7j9GOh8yQYSk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/pEYAJy8obexhYox7j9GOh8yQYSk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/pEYAJy8obexhYox7j9GOh8yQYSk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=MqQ8DyA6xaw:v4p5vmNmILk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=MqQ8DyA6xaw:v4p5vmNmILk:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=MqQ8DyA6xaw:v4p5vmNmILk:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=MqQ8DyA6xaw:v4p5vmNmILk:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?i=MqQ8DyA6xaw:v4p5vmNmILk:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bryanbcook/~4/MqQ8DyA6xaw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.bryancook.net/feeds/577556121957828315/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8942599&amp;postID=577556121957828315" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/577556121957828315?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/577556121957828315?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/bryanbcook/~3/MqQ8DyA6xaw/guided-by-testsday-seven.html" title="Guided by Tests–Day Seven" /><author><name>bryan</name><uri>http://www.blogger.com/profile/01332614158223702009</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.bryancook.net/2011/10/guided-by-testsday-seven.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0MCRHg4fCp7ImA9WhdaFEs.&quot;"><id>tag:blogger.com,1999:blog-8942599.post-6742420175855385389</id><published>2011-10-04T08:31:00.000-04:00</published><updated>2011-10-24T10:11:05.634-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-24T10:11:05.634-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".net" /><category scheme="http://www.blogger.com/atom/ns#" term="TDD" /><category scheme="http://www.blogger.com/atom/ns#" term="guided by tests" /><title>Guided by Tests–Day Six</title><content type="html">&lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;This post is seventh in a series about a group TDD experiment to build an application in &lt;strike&gt;5&lt;/strike&gt; 7 days using only tests.&amp;#160; Read the &lt;a href="http://www.bryancook.net/2011/09/guided-by-tests.html"&gt;beginning here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Today is the day where we put it all together, wire up a user-interface and cross our fingers when we run the application. I joked with the team that “today is the day we find out what tests we missed.” Bugs are simply tests we didn’t think about.&lt;/p&gt;  &lt;h3&gt;Outstanding Design Concerns&lt;/h3&gt;  &lt;p&gt;At this point we have all the parts for our primary use case. And although we’ve designed the parts to be small with simple responsibilities, we’ve been vague about how the structure of the overall application. Before we can show a user-interface, we’ve got a few remaining design choices.&lt;/p&gt;  &lt;h4&gt;Associating the Command to the View&lt;/h4&gt;  &lt;p&gt;In the &lt;a href="http://www.bryancook.net/2011/09/guided-by-testsday-five.html"&gt;last post we looked at the NewProjectCommand&lt;/a&gt;&lt;em&gt;&lt;/em&gt;. After reviewing our choices about the relationship between the Command and the ViewModel we decided that the most pragmatic choice was to have the Command hold a reference to the ViewModel, though we didn’t define where either object fit into the overall application. The next question presented to the team was whether we make the command independent of the ViewModel and reside in a menu-control or other top-level ViewModel, or should we add a Command property to the ViewModel?&lt;/p&gt;  &lt;p&gt;The team decided to take the convenience route and put our &lt;em&gt;NewProjectCommand &lt;/em&gt;as a property on our &lt;em&gt;MainViewModel&lt;/em&gt;. Ultimately, this decision means that our MainViewModel becomes the top-level ViewModel that the View will bind to. This decision is largely view-centric and should be easy to change in the future if we need to reorganize the structure of the application.&lt;/p&gt;  &lt;p&gt;With this decision resolved, we’ve got a better picture of how the user-interface and logical model will work. Before we start working on the xaml, we need to figure out how all these pieces come together.&lt;/p&gt;  &lt;h4&gt;Assembling the MainViewModel&lt;/h4&gt;  &lt;p&gt;The parts of our application have been designed with the Dependency Inversion Principle in mind – our objects don’t have a “top” and expect that the caller will pass in the proper configuration. Eventually, something must take the responsibility to configure the object graph. The next question is: where should this happen?&lt;/p&gt;  &lt;p&gt;Someone suggested stitching the components together in the application start-up routine. While this is logically where this activity should occur, it doesn’t make sense to burden the start-up routine with these implementation details. If we did, we’d likely have a monster start-up routine that would change constantly. Plus, we’d have little means to test it without invoking the user-interface.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;Achieving 100% code coverage, though a noble effort, is not always realistic. In most applications it’s likely that 10% of the codebase won’t have tests because those areas border on the extreme edges of the application. Writing unit tests for extreme edges is hard (“unit” tests for user-interface components is especially difficult) and it helps to have a balanced testing strategy that includes unit, system integration and functional UI automation to cover these areas.&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Rather than including these details in the application start-up routine, we’ll move as much code as possible into testable components. The goal is to make the start-up routine so simple that it won’t require changes. This will minimize the untestable areas of the application.&lt;/p&gt;  &lt;p&gt;To accomplish this, we decided to create a Factory for a MainViewModel.&lt;/p&gt;  &lt;h3&gt;Realizations for the MainViewModel Factory&lt;/h3&gt;  &lt;p&gt;The primary responsibility of our factory is to assemble our ViewModel with a fully configured &lt;em&gt;NewProjectCommand. &lt;/em&gt;The test looks something like this:&lt;/p&gt;  &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;[TestMethod]
public void CreatingAViewModel_WithDefaults_ShouldSetupViewModel()
{
    var factory = new MainViewModelFactory();
    var viewModel = factory.Create();
    
    Assert.IsNotNull(viewModel, &amp;quot;ViewModel was not created.&amp;quot;);
    Assert.IsNotNull(viewModel.NewProject, &amp;quot;Command was not wired up.&amp;quot;);
}&lt;/pre&gt;

&lt;p&gt;In order to make the test pass, we’ll need to wire-up the all the components of our solution within the factory. The argument checking we’ve introduced in the constructors of our command and loader guarantees that. Ultimately, the factory looks like this:&lt;/p&gt;

&lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;public class MainViewModelFactory
{
    public MainViewModel Create()
    {
        var vm = new MainViewModel();

        IFileDialog dialog = new MockFileDialog();
        IGraphDataParser graphParser = new NDependStreamParser();
        var graphBuilder = new GraphBuilder();

        var loader = new ProjectLoader(dialog, graphParser);

        vm.NewProject = new NewProjectCommand(vm, loader, graphBuilder);

        return vm;
    }
}&lt;/pre&gt;

&lt;p&gt;With that all in place, the application start-up routine is greatly simplified. We could probably optimize it further, but we’re anxious to see our application running today, so this will do:&lt;/p&gt;

&lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        var shell = new Shell();
        shell.DataContext = new MainViewModelFactory().Create();
        shell.Show();
    }
}&lt;/pre&gt;

&lt;h3&gt;Running the App for the first time&lt;/h3&gt;

&lt;p&gt;Ready for our first bug? We borrowed some XAML from &lt;a href="http://sachabarber.net/?p=815"&gt;Sacha’s post&lt;/a&gt;, and after we discovered that we needed a one-line user control, we wired up a crude Button to our NewProject command. Then we launched the app, crossed our fingers, and upon clicking the “New Project” button….. nothing happened!&lt;/p&gt;

&lt;p&gt;We set a breakpoint and then walked through the command’s execution. Everything was perfect, except we had forgotten one small detail: we forgot to notify the user-interface that we had produced a graph.&lt;/p&gt;

&lt;p&gt;As a teaching opportunity, we wrote a unit test for our first bug:&lt;/p&gt;

&lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;[TestClass]
public class MainViewModelTests
{
    [TestMethod]
    public void WhenGraphPropertyChanges_ShouldNotifyTheUI()
    {
        string propertyName = null;

        var viewModel = new MainViewModel();
        viewModel.PropertyChanged += (sender,e) =&amp;gt; 
            propertyName = e.PropertyName;

        viewModel.Graph = new AssemblyGraph();

        Assert.AreEqual(&amp;quot;Graph&amp;quot;, propertyName,
            &amp;quot;The user interface wasn't notified.&amp;quot;);
    }
}&lt;/pre&gt;

&lt;p&gt;And on second attempt (read: messing with xaml styles for a while) the app produces the following graph:&lt;/p&gt;

&lt;div align="center"&gt;&lt;a href="http://lh6.ggpht.com/-L-0FOlVd8P8/ToqMGRUGQoI/AAAAAAAAAhE/hVSq0cb6RJE/s1600-h/WPF-ComponentDependenciesDiagram%25255B3%25255D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="WPF-ComponentDependenciesDiagram" border="0" alt="WPF-ComponentDependenciesDiagram" src="http://lh5.ggpht.com/-oi_WUTWIGpQ/ToqMIYLBzDI/AAAAAAAAAhI/uljTsNA8XMA/WPF-ComponentDependenciesDiagram_thumb%25255B1%25255D.png?imgmax=800" width="644" height="471" /&gt;&lt;/a&gt; &lt;/div&gt;

&lt;p&gt;Next: Read about polishing off the File Dialog in &lt;a href="http://www.bryancook.net/2011/10/guided-by-testsday-seven.html"&gt;Day Seven&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8942599-6742420175855385389?l=www.bryancook.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/uEhx0_uzMXTIZD1emuEk8qR0Ay0/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/uEhx0_uzMXTIZD1emuEk8qR0Ay0/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/uEhx0_uzMXTIZD1emuEk8qR0Ay0/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/uEhx0_uzMXTIZD1emuEk8qR0Ay0/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=NKAw5kPvLDo:QobkLOxh5mo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=NKAw5kPvLDo:QobkLOxh5mo:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=NKAw5kPvLDo:QobkLOxh5mo:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=NKAw5kPvLDo:QobkLOxh5mo:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?i=NKAw5kPvLDo:QobkLOxh5mo:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bryanbcook/~4/NKAw5kPvLDo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.bryancook.net/feeds/6742420175855385389/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8942599&amp;postID=6742420175855385389" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/6742420175855385389?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/6742420175855385389?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/bryanbcook/~3/NKAw5kPvLDo/guided-by-testsday-six.html" title="Guided by Tests–Day Six" /><author><name>bryan</name><uri>http://www.blogger.com/profile/01332614158223702009</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh5.ggpht.com/-oi_WUTWIGpQ/ToqMIYLBzDI/AAAAAAAAAhI/uljTsNA8XMA/s72-c/WPF-ComponentDependenciesDiagram_thumb%25255B1%25255D.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.bryancook.net/2011/10/guided-by-testsday-six.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0MFQHw4fip7ImA9WhdaFEs.&quot;"><id>tag:blogger.com,1999:blog-8942599.post-560512554495825358</id><published>2011-09-20T09:38:00.001-04:00</published><updated>2011-10-24T10:10:11.236-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-24T10:10:11.236-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".net" /><category scheme="http://www.blogger.com/atom/ns#" term="TDD" /><category scheme="http://www.blogger.com/atom/ns#" term="guided by tests" /><title>Guided by Tests–Day Five</title><content type="html">&lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;This post is sixth in a series about a group TDD experiment to build an application in 5 days using only tests.&amp;#160; Read the &lt;a href="http://www.bryancook.net/2011/09/guided-by-tests.html"&gt;beginning here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Today is the fifth day of our five day experiment to write an application over lunch hours using TDD. Five days was a bit ambitious, as a lot of time was spent teaching concepts, so the team agreed to tack on a few extra days just to see it all come together. So, my bad.&lt;/p&gt;  &lt;p&gt;By the fifth day, we had all the necessary pieces to construct a graph from our NDepend xml file. Today we focused our attention on how these pieces would interact.&lt;/p&gt;  &lt;h3&gt;Next Steps&lt;/h3&gt;  &lt;p&gt;If we look back to our original flow diagram (shown below), upon receiving input from the user we need to orchestrate between loading model data from a file and converting into a Graph object so that it can be put into the UI. As we have the loading and conversion parts in place, our focus is how to receive input, perform the work and update the UI.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/-DdPZ1ScxXiQ/TniXQSMtXwI/AAAAAAAAAg8/M8mqiqWNFSM/s1600-h/LogicalFlowDiagram2.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="LogicalFlowDiagram" border="0" alt="LogicalFlowDiagram" src="http://lh3.ggpht.com/-Qj2k6jBBbUM/TniXQ0yndNI/AAAAAAAAAhA/fAU6-E-wIOE/LogicalFlowDiagram_thumb.png?imgmax=800" width="244" height="131" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Within WPF and the MVVM architecture, the primary mechanism to handle input from the user is a concept known as Commanding, and commands are implemented by the &lt;em&gt;ICommand &lt;/em&gt;interface:&lt;/p&gt;  &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;namespace System.Windows.Input
{
    public interface ICommand
    {
        bool CanExecute( object parameter );
        void Execute( object parameter );

        event EventHandler CanExecuteChanged;
    }
}&lt;/pre&gt;

&lt;p&gt;While it’s clear that we’ll use a custom command to perform our orchestration logic, the question that remains is how we should implement it. There are several options available, and two popular MVVM choices are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;use the &lt;em&gt;&lt;a href="http://compositewpf.codeplex.com/SourceControl/changeset/view/52595#1024518"&gt;DelegateCommand&lt;/a&gt;&lt;/em&gt; that ships with &lt;a href="http://compositewpf.codeplex.com/"&gt;Microsoft’s Prism framework&lt;/a&gt;, or; &lt;/li&gt;

  &lt;li&gt;an old school approach where we encapsulate the logic for the command as its own class. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The elegance of the &lt;em&gt;DelegateCommand&lt;/em&gt; allows the user to supply delegates for the &lt;em&gt;Execute&lt;/em&gt; and &lt;em&gt;CanExecute&lt;/em&gt; methods, and typically these delegates live within the body of the ViewModel class. When given the choice I prefer command classes for application-level operations as it aligns well to the &lt;a href="http://en.wikipedia.org/wiki/Single_responsibility_principle"&gt;Single Responsibility Principle&lt;/a&gt; and our separation of concerns approach. &lt;em&gt;(I tend to use the DelegateCommand option to perform view-centric operations such as toggling visibility of view-elements, etc.)&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;Writing a Test for an ICommand&lt;/h3&gt;

&lt;p&gt;As a team, we dug into writing the test for our &lt;em&gt;NewProjectCommand&lt;/em&gt;. Assuming we’d use the &lt;em&gt;ICommand&lt;/em&gt; interface, we stubbed in the parts we knew before we hit our first roadblock:&lt;/p&gt;

&lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;[TestClass]
public class NewProjectCommandTests
{
    [TestMethod]
    public void WhenExecutingTheCommand_DefaultScenario_ShouldShowGraphInUI()
    {
        var command = new NewProjectCommand();
        
        command.Execute( null );

        Assert.Fail(); // what should we assert?
    }
}&lt;/pre&gt;

&lt;p&gt;Two immediate concerns arise:&lt;/p&gt;

&lt;p&gt;First, we have a testing concern. How can we assert that the command accomplished what it needed to do? The argument supplied to the &lt;i&gt;Execute&lt;/i&gt; command typically originates from xaml binding syntax, which we won’t need, so it's not likely that the command will take any parameters. Moreover, the &lt;i&gt;Execute&lt;/i&gt; method doesn't have a return value, so we won't have any insight into the outcome of the method.&lt;/p&gt;

&lt;p&gt;Our second concern is a design problem. It's clear that our command will need to associate graph-data to a ViewModel representing our user-interface, but how much information should the Command have about the ViewModel and how will the two communicate?&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;This is one of the parts I love about Test Driven Development. There is no separation between testing concerns and design problems because every test you write is a design choice.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;Reviewing our Coupling Options&lt;/h3&gt;

&lt;p&gt;We have several options to establish the relationship between our Command and our ViewModel:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Accessing the ViewModel through the WPF’s Application.Current; &lt;/li&gt;

  &lt;li&gt;Making our ViewModel a Singleton; &lt;/li&gt;

  &lt;li&gt;Create a globally available ServiceLocator that can locate the ViewModel for us; &lt;/li&gt;

  &lt;li&gt;Pass the ViewModel to the command through Constructor Injection &lt;/li&gt;

  &lt;li&gt;Have the Command and ViewModel communicate through an independent publisher/subscriber model &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s a further breakdown of those options…&lt;/p&gt;

&lt;h4&gt;Application.Current.MainWindow&lt;/h4&gt;

&lt;p&gt;The most readily available solution within WPF is to leverage the framework’s application model. You can access the top-level ViewModel with some awkward casting:&lt;/p&gt;

&lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;var viewModel = Application.Current.MainWindow.DataContext as MainViewModel;&lt;/pre&gt;

&lt;p&gt;I’m not a huge fan of this for many reasons:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Overhead:&lt;/strong&gt; the test suddenly requires additional plumbing code to initialize the WPF Application with a MainWindow bound to the proper ViewModel. This isn’t difficult to do, but it adds unwarranted complexity. &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;Coupling:&lt;/strong&gt; Any time we bind to a top-level property or object, we’re effectively limiting our ability to change that object. In this case, we’re assuming that the MainWindow will always be bound to this ViewModel; if this were to change, all downstream consumers would also need to change. &lt;/li&gt;

  &lt;li&gt;&lt;strong&gt;Shared State:&lt;/strong&gt; By consuming a static property we are effectively making the state of ViewModel shared by all tests. This adds some additional complexity to the tests to ensure that the shared-state is properly reset to a neutral form. As a consequence, it’s impossible to run the tests in parallel. &lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;ViewModel as Singleton / ServiceLocator&lt;/h4&gt;

&lt;p&gt;This approach is a slight improvement over accessing the DataContext of the current application’s MainWindow. It eliminates the concerns surrounding configuring the WPF Application, and we gain some type-safety as we shouldn’t have to do any casting to get our ViewModel. &lt;/p&gt;

&lt;p&gt;Despite this, Singletons like the Application.Current variety are &lt;a href="http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/"&gt;hidden dependencies&lt;/a&gt; that make it difficult to understand the scope and responsibilities of an object. I tend to avoid this approach for the same reasons listed above.&lt;/p&gt;

&lt;h4&gt;Constructor Injection&lt;/h4&gt;

&lt;p&gt;Rather than having the Command reach out to static resource to obtain a reference to the ViewModel, we can use Constructor Injection to pass a reference into the Command so that it has all the resources it needs. (This is the approach we’ve been using thus far for our application, too) This approach makes sense from an API perspective as consumers of your code will be able to understand the Command’s dependencies when they try to instantiate it. The downside to this approach is additional complexity is needed to construct the command. (Hint: We’ll see this in the next post.)&lt;/p&gt;

&lt;p&gt;This approach also eliminates the shared-state and parallelism problem but it still couples us the Command to the ViewModel. This might not be a problem if the relationship between the two objects remains fixed – for example, if the application were to adopt a multi-tabbed interface the relationship between the command and ViewModel would need to change.&lt;/p&gt;

&lt;h4&gt;Message-based Communication&lt;/h4&gt;

&lt;p&gt;The best form of loose-coupling comes from message-based communication, where the ViewModel and the Command know absolutely nothing about each other and only communicate indirectly through an intermediary broker. In this implementation, the Command would orchestrate the construction of the Graph and then publish a message through the broker. The broker, in turn, would deliver the message to a receiver that would associate the graph to the ViewModel.&lt;/p&gt;

&lt;p&gt;Such an implementation would allow both the ViewModel and the Command implementations to be change independently as long as they both adhere to the message publish/subscription contracts. I prefer this approach for large scale applications, though it introduces a level of indirection that can be frustrating at times.&lt;/p&gt;

&lt;p&gt;This approach would likely work well if we needed to support a multi-tabbed user interface.&lt;/p&gt;

&lt;h3&gt;Back to the Tests&lt;/h3&gt;

&lt;p&gt;Given our time constraints and our immediate needs, the team decided constructor injection was the way to go for our test. &lt;/p&gt;

&lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;[TestClass]
public class NewProjectCommandTests
{
    [TestMethod]
    public void WhenExecutingTheCommand_DefaultScenario_ShouldShowGraphInUI()
    {
        var viewModel = new MainViewModel();
        var command = new NewProjectCommand(viewModel);
        
        command.Execute( null );

        Assert.IsNotNull( viewModel.Graph,
            &amp;quot;Graph was not displayed to the user.&amp;quot;);
    }
}&lt;/pre&gt;

&lt;p&gt;To complete the test the team made the following realizations:&lt;/p&gt;

&lt;table border="0" cellspacing="0" cellpadding="2" width="768"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td valign="top" width="349"&gt;&lt;strong&gt;Realization&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="top" width="419"&gt;&lt;strong&gt;Code Written&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="349"&gt;Tests are failing because Execute throws a &lt;em&gt;NotImplementedException&lt;/em&gt;. Let’s commit a sin and get the test to pass.&lt;/td&gt;

      &lt;td valign="top" width="419"&gt;&lt;strong&gt;Implementation:&lt;/strong&gt; 

        &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;public void Execute(object unused)
{
    // hack to get the test to pass
    _viewModel.Graph = new AssemblyGraph();
}&lt;/pre&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="349"&gt;Our command will need a ProjectLoader. Following guidance from the previous day, we extracted an interface and quickly added it to the constructor.&lt;/td&gt;

      &lt;td valign="top" width="419"&gt;&lt;strong&gt;Test Code: 
          &lt;br /&gt;&lt;/strong&gt;

        &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;var viewModel = new MainViewModel();
var projectLoader = new Mock&amp;lt;IProjectLoader&amp;gt;().Object;

var command = new NewProjectCommand(
                    viewModel,
                    projectLoader);&lt;/pre&gt;

        &lt;br /&gt;&lt;strong&gt;Implementation: 
          &lt;br /&gt;&lt;/strong&gt;

        &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;///&amp;lt;summary&amp;gt;Default Constructor&amp;lt;/summary&amp;gt;
public NewProjectCommand(
        MainViewModel viewModel,
        IProjectLoader projectLoader)
{
    _viewModel = viewModel;
    _projectLoader = projectLoader;
}&lt;/pre&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="349"&gt;We should only construct the graph if we get data from the loader. 
        &lt;br /&gt;

        &lt;br /&gt;(Fortunately, &lt;a href="http://code.google.com/p/moq/issues/detail?id=5"&gt;moq will automatically return non-null for IEnumerable types&lt;/a&gt;, so our tests pass accidentally)&lt;/td&gt;

      &lt;td valign="top" width="419"&gt;&lt;strong&gt;Implementation: 
          &lt;br /&gt;

          &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;public void Execute(object unused)
{
    IEnumerable&amp;lt;ProjectAssembly&amp;gt; model
        = _projectLoader.Load();

    if (model != null)
    {
        _viewModel.Graph = new AssemblyGraph();
    }
}&lt;/pre&gt;
        &lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="349"&gt;We’ll need a GraphBuilder to convert our model data into a graph for our viewmodel. Following some obvious implementation, we’ll add the GraphBuilder to the constructor. 
        &lt;br /&gt;

        &lt;br /&gt;A few minor changes and our test passes.&lt;/td&gt;

      &lt;td valign="top" width="419"&gt;&lt;strong&gt;Test Code: 
          &lt;br /&gt;&lt;/strong&gt;

        &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;var viewModel = new MainViewModel();
var projectLoader = new Mock&amp;lt;IProjectLoader&amp;gt;();
var graphBuilder = new GraphBuilder();

var command = new NewProjectCommand(
                    viewModel,
                    projectLoader,
                    graphBuilder);&lt;/pre&gt;

        &lt;br /&gt;&lt;strong&gt;Implementation:&lt;/strong&gt; 

        &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;public void Execute(object unused)
{
    IEnumerable&amp;lt;ProjectAssemby&amp;gt; model
        = _projectLoader.Load();

    if (model != null)
    {
        _viewModel.Graph = 
        	_graphBuilder.BuildGraph( model );
    }
}&lt;/pre&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="349"&gt;Building upon our findings from the previous days, we recognize our coupling to the &lt;em&gt;GraphBuilder&lt;/em&gt; and we recognize that we should probably write some tests that demonstrate that the &lt;em&gt;NewProjectCommand&lt;/em&gt; can handle failures from both the &lt;em&gt;IProjectLoader&lt;/em&gt; and &lt;em&gt;GraphBuilder&lt;/em&gt; dependencies. But rather than extract an interface for the GraphBuilder, we decide that we’d simply make the &lt;em&gt;BuildGraph&lt;/em&gt; method virtual instead – just to show we can.&amp;#160; &lt;br /&gt;

        &lt;br /&gt;Only now, when we run the test the test fails. It seems our graph was not created?&lt;/td&gt;

      &lt;td valign="top" width="419"&gt;&lt;strong&gt;Test Code:&lt;/strong&gt; 

        &lt;br /&gt;

        &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;var viewModel = new MainViewModel();
var projectLoader = new Mock&amp;lt;IProjectLoader&amp;gt;().Object;
var graphBuilder = new Mock&amp;lt;GraphBuilder&amp;gt;().Object;

var command = new NewProjectCommand(
                    viewModel,
                    projectLoader,
                    graphBuilder);

// ...&lt;/pre&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;Finally, in order to get our test to pass, we need to configure the mock for our GraphBuilder to construct a Graph. The final test (shown below) looks like this. Note the &lt;em&gt;IsAnyModel&lt;/em&gt; is a handy shortcut for simplifiying Moq’s matcher syntax.&lt;/p&gt;

&lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;[TestClass]
public class NewProjectCommandTests
{
    [TestMethod]
    public void WhenExecutingTheCommand_DefaultScenario_ShouldShowGraphInUI()
    {
        // ARRANGE: setup dependencies
        var viewModel = new MainViewModel();
        var projectLoader = new Mock&amp;lt;IProjectLoader&amp;gt;().Object;
        var graphBuilder = new Mock&amp;lt;GraphBuilder&amp;gt;().Object;

        // Initialize subject under test
        var command = new NewProjectCommand(
                            viewModel,
                            projectLoader,
                            graphBuilder);
        
        Mock.Get(graphBuilder)
            .Setup( g =&amp;gt; g.BuildGraph( IsAnyModel() ))
            .Returns( new AssemblyGraph() );

        // ACT: Execute our Command
        command.Execute( null );

        // ARRANGE: Verify that the command executed correctly
        Assert.IsNotNull( viewModel.Graph,
            &amp;quot;Graph was not displayed to the user.&amp;quot;);
    }

    private IEnumerable&amp;lt;ProjectAssembly&amp;gt; IsAnyModel()
    {
        return It.IsAny&amp;lt;IEnumerable&amp;lt;ProjectAssembly&amp;gt;&amp;gt;();
    }
}&lt;/pre&gt;

&lt;p&gt;Of course, we’d need a few additional tests:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;When the project loader or graph builder throw an exception. &lt;/li&gt;

  &lt;li&gt;When the project loader doesn’t load a project, the graph should not be changed &lt;/li&gt;

  &lt;li&gt;When the Command is created incorrectly, such as null arguments &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next: &lt;a href="http://www.bryancook.net/2011/10/guided-by-testsday-six.html"&gt;Day Six&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8942599-560512554495825358?l=www.bryancook.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/v0QeLq9Gcqi0tRYmwRFrbGXsOyo/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/v0QeLq9Gcqi0tRYmwRFrbGXsOyo/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/v0QeLq9Gcqi0tRYmwRFrbGXsOyo/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/v0QeLq9Gcqi0tRYmwRFrbGXsOyo/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=Od84iO7Zlp4:zEJVC6SnwlI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=Od84iO7Zlp4:zEJVC6SnwlI:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=Od84iO7Zlp4:zEJVC6SnwlI:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=Od84iO7Zlp4:zEJVC6SnwlI:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?i=Od84iO7Zlp4:zEJVC6SnwlI:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bryanbcook/~4/Od84iO7Zlp4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.bryancook.net/feeds/560512554495825358/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8942599&amp;postID=560512554495825358" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/560512554495825358?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/560512554495825358?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/bryanbcook/~3/Od84iO7Zlp4/guided-by-testsday-five.html" title="Guided by Tests–Day Five" /><author><name>bryan</name><uri>http://www.blogger.com/profile/01332614158223702009</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh3.ggpht.com/-Qj2k6jBBbUM/TniXQ0yndNI/AAAAAAAAAhA/fAU6-E-wIOE/s72-c/LogicalFlowDiagram_thumb.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.bryancook.net/2011/09/guided-by-testsday-five.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEAGSH49fyp7ImA9WhdVFU8.&quot;"><id>tag:blogger.com,1999:blog-8942599.post-148083026464019843</id><published>2011-09-13T08:41:00.000-04:00</published><updated>2011-09-20T09:52:09.067-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-20T09:52:09.067-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".net" /><category scheme="http://www.blogger.com/atom/ns#" term="TDD" /><category scheme="http://www.blogger.com/atom/ns#" term="guided by tests" /><title>Guided by Tests–Day Four</title><content type="html">&lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;This post is fifth in a series about a group TDD experiment to build an application in 5 days using only tests.&amp;#160; Read the &lt;a href="http://www.bryancook.net/2011/09/guided-by-tests.html"&gt;beginning here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;As previously mentioned during Day Three, we split the group into two teams so that one focused on the process to load a new project while the other focused on constructing a graph. This post will focus on the efforts of the team working through the tests and implementation of the &lt;em&gt;GraphBuilder&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;This team had a unique advantage over the other team in that they had a blog post that outlined how to use the Graph# framework. I advised the team that they could refer to the post, even download the example if needed, but all code introduced into the project had to follow the rules of the experiment: all code must be written to satisfy the requirements of a test.&lt;/p&gt;  &lt;h3&gt;A Change in Approach&lt;/h3&gt;  &lt;p&gt;The goals for this team we’re different too. We already had our data well defined and had a reasonable expectation of what the results should be. As such, we took a different approach to writing the tests. Up to this point, our process has involved writing one test at a time and only the code needed to satisfy that test. We wouldn’t identify other tests that we’d need to write until we felt the current test was complete.&lt;/p&gt;  &lt;p&gt;For this team, we had a small brain-storming session and defined all the possible scenarios we would need to test upfront.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;I love this approach and tend to use it when working with my teams. I usually sit down with the developer and envision how the code would be used. From this discussion we stub out a series of failing tests (Assert.Fail) and after some high level guidance about what we need to build I leave them to implement the tests and code. The clear advantage to this approach is that I can step in for an over-the-shoulder code-review and can quickly get feedback on how things are going. When the developer says things are moving along I can simply challenge them to “prove it”. The developer is more than happy to show their progress with working tests, and the failing tests represent a great opportunity to determine if the developer has thought about how to finish them. Win/Win.&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;The test cases we identified for our graph builder:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;When building a graph from an empty list, it should produce an empty graph &lt;/li&gt;    &lt;li&gt;When building a graph from a single assembly, the graph should contain one vertex. &lt;/li&gt;    &lt;li&gt;When building a graph with two independent assemblies, the graph should contain two vertices and there shouldn’t be any edges between them. &lt;/li&gt;    &lt;li&gt;When building a graph with one assembly referencing another, the graph should contain two vertices and one edge &lt;/li&gt;    &lt;li&gt;When building a graph where two assemblies have forward and backward relationships (the first item lists the second vertex as a dependency, the second item lists the first as a “referenced by”), the graph should contain unique edges between items. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;By the time the team had begun to develop the third test, most of the dependent object model had been defined. The remaining tests represented implementation details. For example, to establish a relationship between assemblies we would need to store them into a lookup table. Whether this lookup table should reside within the &lt;em&gt;GraphBuilder&lt;/em&gt; or pushed lower into the &lt;em&gt;Graph&lt;/em&gt; itself is an optimization that can be determined later if needed. The tests would not need to change to support this refactoring effort.&lt;/p&gt;  &lt;h3&gt;Interesting Finds&lt;/h3&gt;  &lt;p&gt;The session on the fourth day involved a review of the implementation and an opportunity to refactor both the tests and the code. One of the great realizations was the ability to reduce the verbosity of initializing the test data.&lt;/p&gt;  &lt;p&gt;We started with a lot of duplication and overhead in the tests:&lt;/p&gt;  &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;[TestMethod]
public void AnExample_ItDoesntMatter_JustKeepReading()
{
    var assembly1 = new ProjectAssembly
                        {
                            FullName = &amp;quot;Assembly1&amp;quot;
                        };
    var assembly2 = new ProjectAssembly
                        {
                            FullName = &amp;quot;Assembly2&amp;quot;
                        };

    _projectList.Add(assembly1);
    _projectList.Add(assembly2);

    Graph graph = Subject.BuildGraph(_projectList);

    // Assertions...
}&lt;/pre&gt;

&lt;p&gt;We moved some of the initialization logic into a helper method, which improved readability:&lt;/p&gt;

&lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;[TestMethod]
public void AnExample_ItDoesntMatter_JustKeepReading()
{
    var assembly1 = CreateProjectAssembly(&amp;quot;Assembly1&amp;quot;);
    var assembly2 = CreateProjectAssembly(&amp;quot;Assembly2&amp;quot;);

    _projectList.Add(assembly1);
    _projectList.Add(assembly2);

    Graph graph = Subject.BuildGraph(_projectList);

    // Assertions...
}

private ProjectAssembly CreateProjectAssembly(string name)
{
    return new ProjectAssembly()
            {
                FullName = name
            };
}&lt;/pre&gt;

&lt;p&gt;However, once we discovered the name of the assembly wasn’t important and that they just had to be unique, we optimized this further:&lt;/p&gt;

&lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;[TestMethod]
public void AnExample_ItDoesntMatter_JustKeepReading()
{
    var assembly1 = CreateProjectAssembly();
    var assembly2 = CreateProjectAssembly();

    _projectList.Add(assembly1);
    _projectList.Add(assembly2);

    Graph graph = Subject.BuildGraph(_projectList);

    // Assertions...
}

private ProjectAssembly CreateProjectAssembly(string name = null)
{
    if (name == null)
        name = Guid.NewGuid().ToString();

    return new ProjectAssembly()
            {
                FullName = name
            };
}&lt;/pre&gt;

&lt;p&gt;If we really wanted to, we could optimize this further by pushing this initialization logic into the production code directly.&lt;/p&gt;

&lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;[TestMethod]
public void WhenConstructingAProjectAssembly_WithNoArguments_ShouldAutogenerateAFullName()
{
    var assembly = new ProjectAssembly();

    bool nameIsPresent = !String.IsNullOrEmpty(assembly.FullName);

    Assert.IsTrue( nameIsPresent,
        &amp;quot;Name was not automatically generated.&amp;quot;);
}&lt;/pre&gt;

&lt;p&gt;Continue Reading: &lt;a href="http://www.bryancook.net/2011/09/guided-by-testsday-five.html"&gt;Day Five&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8942599-148083026464019843?l=www.bryancook.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/fjp5yUGUfjgEyTTJVQoi_gv7PxU/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/fjp5yUGUfjgEyTTJVQoi_gv7PxU/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/fjp5yUGUfjgEyTTJVQoi_gv7PxU/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/fjp5yUGUfjgEyTTJVQoi_gv7PxU/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=O_b4Gp-rLj8:QSlkI6kMakM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=O_b4Gp-rLj8:QSlkI6kMakM:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=O_b4Gp-rLj8:QSlkI6kMakM:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=O_b4Gp-rLj8:QSlkI6kMakM:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?i=O_b4Gp-rLj8:QSlkI6kMakM:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bryanbcook/~4/O_b4Gp-rLj8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.bryancook.net/feeds/148083026464019843/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8942599&amp;postID=148083026464019843" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/148083026464019843?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/148083026464019843?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/bryanbcook/~3/O_b4Gp-rLj8/guided-by-testsday-four.html" title="Guided by Tests–Day Four" /><author><name>bryan</name><uri>http://www.blogger.com/profile/01332614158223702009</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.bryancook.net/2011/09/guided-by-testsday-four.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEQNQXgzfSp7ImA9WhdWGU8.&quot;"><id>tag:blogger.com,1999:blog-8942599.post-3532765428739624308</id><published>2011-09-09T15:03:00.001-04:00</published><updated>2011-09-13T09:59:50.685-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-13T09:59:50.685-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".net" /><category scheme="http://www.blogger.com/atom/ns#" term="TDD" /><category scheme="http://www.blogger.com/atom/ns#" term="guided by tests" /><title>Guided by Tests–Day Three</title><content type="html">&lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;This post is fourth in a series about a group TDD experiment to build an application in 5 days using only tests.&amp;#160; Read the &lt;a href="http://www.bryancook.net/2011/09/guided-by-tests.html"&gt;beginning here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;By day three, our collective knowledge about what we were building was beginning to shape. After reviewing the tests from the previous day, it was time for an interesting discussion: what’s next?&lt;/p&gt;  &lt;h3&gt;Determining Next Steps&lt;/h3&gt;  &lt;p&gt;In order to determine our next steps, the team turned the logical flow diagram of our use-case. We decomposed the logical flow into the following steps:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Receive input from the UI, maybe a menu control or some other UI action. &lt;/li&gt;    &lt;li&gt;Prompt the user for a file, likely using a standard open file dialog. &lt;/li&gt;    &lt;li&gt;Take the response from the dialog and feed it into our stream parser. &lt;/li&gt;    &lt;li&gt;Take the output of the stream parser and build a graph &lt;/li&gt;    &lt;li&gt;Take the graph and update the UI, likely a ViewModel. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Following a &lt;a href="http://en.wikipedia.org/wiki/Separation_of_concerns"&gt;Separation of Concerns&lt;/a&gt; approach, we want to design our solution so that each part has very little knowledge about the surrounding parts. It was decided that we can clearly separate the building of the graph from the prompting the user part. In my view, we know very little about the UI at this point so we shouldn’t concern ourselves with how the UI initiates this activity. Instead, we can treat the prompting the user for a file and orchestrating interaction with our parser as a single concern.&lt;/p&gt;  &lt;p&gt;It was time to split the group in two and start on different parts. Team one would focus on the code that would call the &lt;em&gt;NDependStreamParser;&lt;/em&gt; Team two would focus on the code that consumed the list of &lt;em&gt;ProjectAssembly&lt;/em&gt; items to produce a graph.&lt;/p&gt;  &lt;blockquote&gt;&lt;em&gt;Note: Day Four was spent reviewing and finishing the code for team two. For the purposes of this post, I’m going to focus on the efforts of Team one.&lt;/em&gt; &lt;/blockquote&gt;  &lt;h3&gt;The Next Test&lt;/h3&gt;  &lt;div&gt;   &lt;p&gt;The team decided that we should name this concern, “&lt;em&gt;NewProjectLoader”&lt;/em&gt; as it would orchestrate the loading of our model. We knew that we’d be prompting for a file, so we named the test accordingly:&lt;/p&gt;    &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;[TestClass]
public class NewProjectLoaderTests
{
    [TestMethod]
    public void WhenLoadingANewProject_WithAValidFile_ShouldLoadModel()
    {
        Assert.Fail();
    }
}&lt;/pre&gt;

  &lt;p&gt;Within a few minutes the team quickly filled in the immediately visible details of the test.&lt;/p&gt;

  &lt;table border="0" cellspacing="0" cellpadding="2" width="706"&gt;&lt;tbody&gt;
      &lt;tr&gt;
        &lt;td valign="top" width="349"&gt;&lt;strong&gt;Realization&lt;/strong&gt;&lt;/td&gt;

        &lt;td valign="top" width="355"&gt;&lt;strong&gt;Code Written&lt;/strong&gt;&lt;/td&gt;
      &lt;/tr&gt;

      &lt;tr&gt;
        &lt;td valign="top" width="349"&gt;Following the first example from the day before, the team filled in their assertions and auto-generated the parts they needed. 
          &lt;br /&gt;

          &lt;br /&gt;To make the tests pass, they hard-coded a response.&lt;/td&gt;

        &lt;td valign="top" width="355"&gt;&lt;strong&gt;Test Code: 
            &lt;br /&gt;&lt;/strong&gt;

          &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;var loader = new NewProjectLoader();

IEnumerable&amp;lt;ProjectAssembly&amp;gt; model 
	= loader.Load();

Assert.IsNotNull(model,
    &amp;quot;Model was not loaded.&amp;quot;);&lt;/pre&gt;
          &lt;strong&gt;Implementation:&lt;/strong&gt; 

          &lt;br /&gt;

          &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;public IEnumerable&amp;lt;ProjectAssembly&amp;gt; Load()
{
    return new List&amp;lt;ProjectAssembly&amp;gt;();
}&lt;/pre&gt;
        &lt;/td&gt;
      &lt;/tr&gt;

      &lt;tr&gt;
        &lt;td valign="top" width="349"&gt;How should we prompt the user for a file?&lt;/td&gt;

        &lt;td valign="top" width="355"&gt;Hmmm.&lt;/td&gt;
      &lt;/tr&gt;
    &lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;div&gt;&amp;#160;&lt;/div&gt;

&lt;h3&gt;Our Next Constraint&lt;/h3&gt;

&lt;p&gt;The team now needed to prompt the user to select a file. Fortunately, WPF provides the &lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.win32.openfiledialog.aspx"&gt;&lt;em&gt;OpenFileDialog&lt;/em&gt;&lt;/a&gt; so we won’t have to roll our own dialog. Unfortunately, if we introduce it into our code we’ll be tightly coupled to the user-interface. &lt;/p&gt;

&lt;p&gt;To isolate ourselves from this dependency, we need to introduce a small interface:&lt;/p&gt;

&lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;namespace DependencyViewer
{
    public interface IFileDialog
    {
        string SelectFile();
    }
}&lt;/pre&gt;

&lt;p&gt;Through tests, we introduced these changes:&lt;/p&gt;

&lt;div&gt;
  &lt;table border="0" cellspacing="0" cellpadding="2" width="768"&gt;&lt;tbody&gt;
      &lt;tr&gt;
        &lt;td valign="top" width="349"&gt;&lt;strong&gt;Realization&lt;/strong&gt;&lt;/td&gt;

        &lt;td valign="top" width="417"&gt;&lt;strong&gt;Code Written&lt;/strong&gt;&lt;/td&gt;
      &lt;/tr&gt;

      &lt;tr&gt;
        &lt;td valign="top" width="349"&gt;We need to introduce our File Dialog to our Loader. 
          &lt;br /&gt;

          &lt;br /&gt;We decide our best option is to introduce the dependency through the constructor of the loader. 

          &lt;br /&gt;

          &lt;br /&gt;This creates a small compilation error that is quickly resolved. 

          &lt;br /&gt;

          &lt;br /&gt;Our tests still passes. 

          &lt;br /&gt;

          &lt;br /&gt;&lt;/td&gt;

        &lt;td valign="top" width="417"&gt;&lt;strong&gt;Test Code: 
            &lt;br /&gt;&lt;/strong&gt;

          &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;IFileDialog dialog = null;
var loader = new NewProjectLoader(dialog);
IEnumerable&amp;lt;ProjectAssembly&amp;gt; model 
	= loader.Load();

Assert.IsNotNull(model,
    &amp;quot;Model was not loaded.&amp;quot;);&lt;/pre&gt;
          &lt;strong&gt;Implementation:&lt;/strong&gt; 

          &lt;br /&gt;

          &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;public class NewProjectLoader
{
    private IFileDialog _dialog;

    public NewProjectLoader(
	IFileDialog dialog)
    {
        _dialog = dialog;
    }
    // ...&lt;/pre&gt;
        &lt;/td&gt;
      &lt;/tr&gt;

      &lt;tr&gt;
        &lt;td valign="top" width="349"&gt;Now, how should we prompt for a file? 
          &lt;br /&gt;

          &lt;br /&gt;The code should delegate to our &lt;em&gt;IFileDialog&lt;/em&gt; and we can assume that if they select a file, the return value will not be null. 

          &lt;br /&gt;

          &lt;br /&gt;The test compiles, but the test fails because the dialog is null.&lt;/td&gt;

        &lt;td valign="top" width="417"&gt;&lt;strong&gt;Implementation:&lt;/strong&gt; 

          &lt;br /&gt;

          &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;public IEnumerable&amp;lt;ProjectAssembly&amp;gt; Load()
{
    string fileName = _dialog.SelectFile();
    if (!String.IsNullOrEmpty(fileName))
    {
        return new List&amp;lt;ProjectAssembly&amp;gt;();
    }

    throw new NotImplementedException();
}&lt;/pre&gt;
        &lt;/td&gt;
      &lt;/tr&gt;

      &lt;tr&gt;
        &lt;td valign="top" width="349"&gt;We don’t have an implementation for &lt;em&gt;IFileDialog&lt;/em&gt;. So we’ll define a dummy implementation and use Visual Studio to auto-generate the defaults. 

          &lt;br /&gt;

          &lt;br /&gt;Our test fails because the auto-generated code throws an error (&lt;em&gt;NotImplementedException)&lt;/em&gt;.&lt;/td&gt;

        &lt;td valign="top" width="417"&gt;&lt;strong&gt;Test Code: 
            &lt;br /&gt;&lt;/strong&gt;

          &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;IFileDialog dialog = new MockFileDialog();
var loader = new NewProjectLoader(dialog);
IEnumerable&amp;lt;ProjectAssembly&amp;gt; model 
	= loader.Load();

Assert.IsNotNull(model,
    &amp;quot;Model was not loaded.&amp;quot;);&lt;/pre&gt;
        &lt;/td&gt;
      &lt;/tr&gt;

      &lt;tr&gt;
        &lt;td valign="top" width="349"&gt;We can easily fix the test replacing the exception with a non-null file name.&lt;/td&gt;

        &lt;td valign="top" width="417"&gt;&lt;strong&gt;Implementation: 
            &lt;br /&gt;&lt;/strong&gt;

          &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;public class MockFileDialog 
    : IFileDialog
{
    public string SelectFile()
    {
        return &amp;quot;Foo&amp;quot;;
    }
}&lt;/pre&gt;
        &lt;/td&gt;
      &lt;/tr&gt;

      &lt;tr&gt;
        &lt;td valign="top" width="349"&gt;The test passes, but we’re not done. We need to construct a valid model. 
          &lt;br /&gt;

          &lt;br /&gt;We use a technique known as “&lt;strong&gt;Obvious Implementation&lt;/strong&gt;” and we introduce our &lt;em&gt;NDependStreamParser&lt;/em&gt; directly into our Loader. 

          &lt;br /&gt;

          &lt;br /&gt;The test breaks again, this time because “Foo” is not a valid filename.&lt;/td&gt;

        &lt;td valign="top" width="417"&gt;&lt;strong&gt;Implementation: 
            &lt;br /&gt;&lt;/strong&gt;

          &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;string fileName = _dialog.SelectFile();
if (!String.IsNullOrEmpty(fileName))
{
    using(var stream = XmlReader.Create(fileName))
    {
        var parser = new NDependStreamParser();
        return parser.Parse(stream);
    }
}
//...&lt;/pre&gt;
        &lt;/td&gt;
      &lt;/tr&gt;

      &lt;tr&gt;
        &lt;td valign="top" width="349"&gt;Because our solution is tied to a &lt;em&gt;FileStream&lt;/em&gt;, we need to specify a proper file name.&amp;#160; To do this we need to modify our &lt;em&gt;MockFileDialog&lt;/em&gt; so that we we can assign a FileName from within the test. 

          &lt;br /&gt;

          &lt;br /&gt;In order to get a valid file, we need to include a file as part of the project and then enable Deployment as part of the mstest test settings. 

          &lt;br /&gt;

          &lt;br /&gt;&lt;em&gt;(Note: We could have changed the signature of the loader to take a filename, but we chose to keep the dependency to the file here mainly for time concerns.)&lt;/em&gt;&lt;/td&gt;

        &lt;td valign="top" width="417"&gt;&lt;strong&gt;Implementation: 
            &lt;br /&gt;

            &lt;br /&gt;&lt;/strong&gt;

          &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;public class MockFileDialog
    : IFileDialog
{
    public string FileName;

    public string SelectFile()
    {
        return FileName;
    }
}&lt;/pre&gt;

          &lt;br /&gt;&lt;strong&gt;Test Code: 
            &lt;br /&gt;&lt;/strong&gt;

          &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;[DeploymentItem(&amp;quot;AssembliesDependencies.xml&amp;quot;)]
[TestMethod]
public void WhenLoadingANewProject...()
{
    var dialog = new MockFileDialog();
    dialog.FileName = &amp;quot;AssembliesDependencies.xml&amp;quot;;
    var loader = new NewProjectLoader(dialog);

    //...&lt;/pre&gt;
        &lt;/td&gt;
      &lt;/tr&gt;
    &lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;br /&gt;

&lt;h3&gt;Isolating Further&lt;/h3&gt;

&lt;p&gt;While our test passes and it represents the functionality we want, we’ve introduced a design problem such that we’re coupled to the implementation details of the &lt;em&gt;NDependStreamParser&lt;/em&gt;. Some may make the case that this is the nature of our application, we only need this class and if the parser’s broken so is our loader. I don’t necessarily agree. &lt;/p&gt;

&lt;p&gt;The problem with this type of coupling is that when the parser breaks, the unit tests for the loader will also break. If we allow this type of coupling you can draw a logical conclusion that other classes will have tight coupling and thus when the parser breaks it will have a cascade effect on the majority of our tests. This defeats the purpose of our early feedback mechanism. Besides, why design our classes to be black-boxes that will have to change if we introduce different types of parsers?&lt;/p&gt;

&lt;p&gt;The solution is to introduce an interface for our parser. Resharper makes this really easy, simply click our class and choose “Extract Interface”.&lt;/p&gt;

&lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;public interface IGraphDataParser
{
    IEnumerable&amp;lt;ProjectAssembly&amp;gt; Parse(XmlReader reader);
}&lt;/pre&gt;

&lt;h4&gt;Adding a Mocking Framework&lt;/h4&gt;

&lt;p&gt;Whereas we created a hand-rolled mock (aka Test Double) for our &lt;em&gt;IFileDialog&lt;/em&gt;, it’s time to introduce a mocking framework that can create mock objects in memory.&amp;#160; Using &lt;a href="http://nuget.codeplex.com/"&gt;NuGet&lt;/a&gt; to simplify our assembly management, we add a reference to &lt;a href="http://code.google.com/p/moq/"&gt;Moq&lt;/a&gt; to our test project.&lt;/p&gt;

&lt;h4&gt;Refactoring Steps&lt;/h4&gt;

&lt;p&gt;We made the following small refactoring changes to decouple ourselves from the &lt;em&gt;NDependStreamParser&lt;/em&gt;.&lt;/p&gt;

&lt;table border="0" cellspacing="0" cellpadding="2" width="768"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td valign="top" width="349"&gt;&lt;strong&gt;Realization&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="top" width="417"&gt;&lt;strong&gt;Code Written&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="349"&gt;Stream Parser should be a field. 
        &lt;br /&gt;&amp;#160; &lt;br /&gt;

        &lt;br /&gt;&lt;/td&gt;

      &lt;td valign="top" width="417"&gt;&lt;strong&gt;Implementation:&lt;/strong&gt; 

        &lt;br /&gt;

        &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;// NewProjectLoader.cs

IFileDialog _dialog;
NDependStreamParser _parser;

public IEnumerable&amp;lt;ProjectAssembly&amp;gt; Load()
{
    string fileName = _dialog.SelectFile();
    if (!String.IsNullOrEmpty(fileName))
    {
        using (var stream = 
		XmlReader.Create(fileName))
        {
            _parser = new NDependStreamParser();
            return _parser.Parse(stream);
        }
    }

    throw new NotImplementedException();
}&lt;/pre&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="349"&gt;We need to use the interface rather than the concrete type.&lt;/td&gt;

      &lt;td valign="top" width="417"&gt;&lt;strong&gt;Implementation: 
          &lt;br /&gt;&lt;/strong&gt;

        &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;public class NewProjectLoader
{
    IFileDialog _dialog;
    IGraphDataParser _parser;

    // ...&lt;/pre&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="349"&gt;We should initialize the parser in the constructor instead of the &lt;em&gt;Load&lt;/em&gt; method.&lt;/td&gt;

      &lt;td valign="top" width="417"&gt;&lt;strong&gt;Implementation: 
          &lt;br /&gt;&lt;/strong&gt;

        &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;public class NewProjectLoader
{
    IFileDialog _dialog;
    IGraphDataParser _parser;

    public NewProjectLoader(IFileDialog dialog)
    {
        _dialog = dialog;
        _parser = new NDependStreamParser();
    }

    // ...&lt;/pre&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="349"&gt;We should initialize the parser from outside the constructor. 
        &lt;br /&gt;

        &lt;br /&gt;This introduces a minor compilation problem that requires us to change the test slightly.&lt;/td&gt;

      &lt;td valign="top" width="417"&gt;&lt;strong&gt;Test Code: 
          &lt;br /&gt;&lt;/strong&gt;

        &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;var dialog = new MockFileDialog();
var parser = new NDependStreamParser();

var loader = new NewProjectLoader(dialog, parser);&lt;/pre&gt;

        &lt;br /&gt;&lt;strong&gt;Implementation:&lt;/strong&gt; 

        &lt;br /&gt;

        &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;public class NewProjectLoader
{
    IFileDialog _dialog;
    IGraphDataParser _parser;

    public NewProjectLoader(
            IFileDialog dialog,
            IGraphDataParser parser)
    {
        _dialog = dialog;
        _parser = parser;
    }

    // ...&lt;/pre&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="349"&gt;We need to replace our &lt;em&gt;NDependStreamParser&lt;/em&gt; with a mock implementation. 

        &lt;br /&gt;

        &lt;br /&gt;&lt;/td&gt;

      &lt;td valign="top" width="417"&gt;&lt;strong&gt;Test Code:&lt;/strong&gt; 

        &lt;br /&gt;

        &lt;br /&gt;

        &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;var dialog = new MockFileDialog();
var paser = new Mock&amp;lt;IGraphDataParser&amp;gt;().Object;

var loader = new NewProjectLoader(dialog, parser);&lt;/pre&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;Strangely enough, &lt;a href="http://code.google.com/p/moq/issues/detail?id=5"&gt;there’s a little known feature of Moq&lt;/a&gt; that will ensure mocks that return &lt;em&gt;IEnumerable&lt;/em&gt; collections will never be null, so our test passes!&lt;/p&gt;

&lt;h3&gt;Additional Tests&lt;/h3&gt;

&lt;p&gt;We wrote the following additional tests:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;WhenLoadingANewProject_WithNoFileSpecfied_ShouldNotReturnAModel &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next: &lt;a href="http://www.bryancook.net/2011/09/guided-by-testsday-four.html"&gt;Day Four&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8942599-3532765428739624308?l=www.bryancook.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/sXawjo0QC5ju1eVrGPr6vIqnUVI/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/sXawjo0QC5ju1eVrGPr6vIqnUVI/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/sXawjo0QC5ju1eVrGPr6vIqnUVI/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/sXawjo0QC5ju1eVrGPr6vIqnUVI/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=nqtu85XH5_k:TmdFQQ7PIPQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=nqtu85XH5_k:TmdFQQ7PIPQ:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=nqtu85XH5_k:TmdFQQ7PIPQ:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=nqtu85XH5_k:TmdFQQ7PIPQ:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?i=nqtu85XH5_k:TmdFQQ7PIPQ:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bryanbcook/~4/nqtu85XH5_k" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.bryancook.net/feeds/3532765428739624308/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8942599&amp;postID=3532765428739624308" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/3532765428739624308?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/3532765428739624308?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/bryanbcook/~3/nqtu85XH5_k/guided-by-testsday-three.html" title="Guided by Tests–Day Three" /><author><name>bryan</name><uri>http://www.blogger.com/profile/01332614158223702009</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.bryancook.net/2011/09/guided-by-testsday-three.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0cNQX46cCp7ImA9WhdWFUQ.&quot;"><id>tag:blogger.com,1999:blog-8942599.post-5819878781880088049</id><published>2011-09-08T08:30:00.000-04:00</published><updated>2011-09-09T15:04:50.018-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-09T15:04:50.018-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".net" /><category scheme="http://www.blogger.com/atom/ns#" term="TDD" /><category scheme="http://www.blogger.com/atom/ns#" term="guided by tests" /><title>Guided by Tests–Day Two</title><content type="html">&lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;This post is third in a series about a group TDD experiment to build an application in 5 days using only tests.&amp;#160; Read the &lt;a href="http://www.bryancook.net/2011/09/guided-by-tests.html"&gt;beginning here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Today we break new ground on our application, starting with writing our first test. Today is still a teaching session, where I’ll write the first set of tests to demonstrate naming conventions and how to demonstrate how to use TDD with the &lt;a href="http://www.bryancook.net/2011/09/guided-by-testsday-one.html" target="_blank"&gt;rules we defined&lt;/a&gt; the day before. But first, we need to figure out where we should start.&lt;/p&gt;  &lt;h3&gt;Logical Flow&lt;/h3&gt;  &lt;p&gt;In order to determine where we should start it helps to draw out the logical flow of our primary use case: create a new dependency viewer from an NDepend &lt;em&gt;AssembliesDependencies.xml&lt;/em&gt; file.&amp;#160; The logical flow looks something like this:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh5.ggpht.com/-nGIxSwQMr7s/TmhPjuH2oiI/AAAAAAAAAg0/9J_p0lenGwY/s1600-h/LogicalFlowDiagram%25255B121%25255D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="LogicalFlowDiagram" border="0" alt="LogicalFlowDiagram" src="http://lh3.ggpht.com/-3DWnGwTRKpA/TmhPkG-CBQI/AAAAAAAAAg4/6LbOCtLc4pk/LogicalFlowDiagram_thumb%25255B119%25255D.png?imgmax=800" width="376" height="208" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;User clicks “New” &lt;/li&gt;    &lt;li&gt;The user is prompted to select a file &lt;/li&gt;    &lt;li&gt;Some logical processing occurs where the file is read, &lt;/li&gt;    &lt;li&gt;…a graph is produced, &lt;/li&gt;    &lt;li&gt;…and the UI is updated. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;The question on where to start is an interesting one. Given limited knowledge of what we need to build or how these components will interact, what area of the logical flow do we know the most about? What part can we reliably predict the outcome?&lt;/p&gt;  &lt;p&gt;Starting from scratch, it seemed the most reasonable choice was to start with the part that reads our NDepend file. We know the structure of the file and we know that the contents of the file will represent our model.&lt;/p&gt;  &lt;h3&gt;Testing Constraints&lt;/h3&gt;  &lt;p&gt;When developing with a focus on testability, there are certain common problems that arise when trying to get a class under the test microscope. You learn to recognize them instantly, and I’ve jokingly referred to this as &lt;em&gt;spidey-sense&lt;/em&gt; – you just know these are going to be problematic before you start. &lt;/p&gt;  &lt;p&gt;While this is not a definitive list, the obvious ones are:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;User Interface:&lt;/strong&gt; Areas that involve the user-interface can be problematic for several reasons:       &lt;ul&gt;       &lt;li&gt;Some test-runners have a technical limitation and cannot launch a user-interface based on the threading model. &lt;/li&gt;        &lt;li&gt;The UI may require complex configuration or additional prerequisites (style libraries, etc) and is subject to change frequently &lt;/li&gt;        &lt;li&gt;The UI may unintentionally require human interaction during the tests, thereby limiting our ability to reliably automate. &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;File System:&lt;/strong&gt; Any time we need files or folder structure, we are dependent on the environment to be setup a certain way with dummy data. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Database / Network:&lt;/strong&gt; Being dependent on external services is additional overhead that we want to avoid. Not only will tests run considerably slower, but the outcome of the test is dependent on many factors that may not be under our control (service availability, database schema, user permissions, existing data). &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Some of the less obvious ones are design considerations which may make it difficult to test, such as tight coupling to implementation details of other classes (static methods, use of “new”, etc).&lt;/p&gt;  &lt;p&gt;In our case, our first test would be dependent on the file system. We will likely need to test several different scenarios, which will require many different files.&amp;#160; While we could go this route, working with the file system directly would only slow us down. We needed to find a way to isolate ourselves.&lt;/p&gt;  &lt;p&gt;The team tossed around several different suggestions, including passing just xml as string. Ultimately, as this class must read the contents of the file we decided that the best way to work with Xml was an &lt;em&gt;XmlReader&lt;/em&gt;. We could simulate many different scenarios by setting up a stream containing our test data.&lt;/p&gt;  &lt;h3&gt;Our First Test&lt;/h3&gt;  &lt;p&gt;So after deciding that the name of our class would be named &lt;em&gt;NDependStreamParser&lt;/em&gt;, our first test looked something like this:&lt;/p&gt;  &lt;pre class="brush: csharp; auto-links: false;"&gt;using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace DependencyViewer
{
    [TestClass]
    public class NDependStreamParserTests
    {
        [TestMethod]
        public void TestMethod1()
        {
            Assert.Fail();
        }
    }
}&lt;/pre&gt;

&lt;p&gt;We know very little about what we need. But at the very least, the golden rule is to ensure that all tests must fail from the very beginning. Writing “&lt;em&gt;Assert.Fail();”&lt;/em&gt; is a good habit to establish.&lt;/p&gt;

&lt;p&gt;In order to help identify what we need, it helps to work backward. So we start by writing our assertions first and then, working from the bottom up, fill in the missing pieces.&amp;#160; Our discovery followed this progression:&lt;/p&gt;

&lt;table border="0" cellspacing="0" cellpadding="2" width="783"&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td valign="top" width="363"&gt;&lt;strong&gt;Realization&lt;/strong&gt;&lt;/td&gt;

      &lt;td valign="top" width="418"&gt;&lt;strong&gt;Code Written&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="363"&gt;At the end of the tests, we’ll have some sort of results. The results should not be null. 
        &lt;br /&gt;

        &lt;br /&gt;At this point, test compiles, but it’s red.&lt;/td&gt;

      &lt;td valign="top" width="418"&gt;&lt;strong&gt;Test Code: &lt;/strong&gt;

        &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;object results = null;
Assert.IsNotNull( results,
           “Results were not produced.”);&lt;/pre&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="363"&gt;Where will the results come from? We’ll need a parser. The results will come after we call Parse. 
        &lt;br /&gt;

        &lt;br /&gt;The code won’t compile because this doesn’t exist. If we use the auto-generate features of Visual Studio / Resharper the test compiles, but because of the default &lt;em&gt;NotImplementedException&lt;/em&gt;, the test fails.&lt;/td&gt;

      &lt;td valign="top" width="418"&gt;&lt;strong&gt;Test Code: &lt;/strong&gt;

        &lt;br /&gt;

        &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;var parser = new NDependStreamParser(); 
object results = parser.Parse();
Assert.IsNotNull( results,
           “Results were not produced.”);&lt;/pre&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="363"&gt;We need to make the test pass. 
        &lt;br /&gt;

        &lt;br /&gt;Do whatever we need to make it green.&lt;/td&gt;

      &lt;td valign="top" width="418"&gt;&lt;strong&gt;Implementation:&lt;/strong&gt; 

        &lt;br /&gt;

        &lt;br /&gt;

        &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;public object Parse()
{
    // yes, it's a dirty hack. 
    // but now the test passes.
    return new object();
}&lt;/pre&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="363"&gt;Our tests passes, but we’re clearly not done. How will we parse? The data needs to come from somewhere. We need to read from a stream. 
        &lt;br /&gt;

        &lt;br /&gt;Introducing the stream argument into the Parse method won’t compile (so the tests are red), but this is a quick fix in the implementation.&lt;/td&gt;

      &lt;td valign="top" width="418"&gt;&lt;strong&gt;Test Code:&lt;/strong&gt; 

        &lt;br /&gt;

        &lt;br /&gt;

        &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;var parser = new NDependStreamParser();
var sr = new StringReader(&amp;quot;&amp;quot;);
var reader = XmlReader.Create(sr);
object results = parser.Parse(reader);
// ...&lt;/pre&gt;

        &lt;br /&gt;&lt;strong&gt;Implementation:&lt;/strong&gt; 

        &lt;br /&gt;

        &lt;br /&gt;

        &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;public object Parse(XmlReader reader) { //...&lt;/pre&gt;
      &lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign="top" width="363"&gt;Our return type shouldn’t be “Object”. What should it be? 
        &lt;br /&gt;

        &lt;br /&gt;After a short review of the NDepend AssembliesDependencies.xml file, we decide that we should read the list of assemblies from the file into a model object which we arbitrarily decide should be called &lt;em&gt;ProjectAssembly&lt;/em&gt;. At a minimum, &lt;em&gt;Parse&lt;/em&gt; should return an &lt;em&gt;IEnumerable&amp;lt;ProjectAssembly&amp;gt;. 
          &lt;br /&gt;

          &lt;br /&gt;&lt;/em&gt;There are a few minor compilation problems to address here, including the auto-generation of the &lt;em&gt;ProjectAssembly&lt;/em&gt; class. These are all simple changes that can be made in under 60 seconds.&lt;/td&gt;

      &lt;td valign="top" width="418"&gt;&lt;strong&gt;Test Code:&lt;/strong&gt; 

        &lt;br /&gt;

        &lt;br /&gt;

        &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;var parser = new NDependStreamParser();
var sr = new StringReader(&amp;quot;&amp;quot;);
var reader = XmlReader.Create(sr);
IEnumerable&amp;lt;ProjectAssembly&amp;gt; results 
    = parser.Parse(reader);
// ...&lt;/pre&gt;

        &lt;br /&gt;&lt;strong&gt;Implementation:&lt;/strong&gt; 

        &lt;br /&gt;

        &lt;br /&gt;

        &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;public IEnumerable&amp;lt;ProjectAssembly&amp;gt; Parse(
	XmlReader reader)
{
    return new List&amp;lt;ProjectAssembly&amp;gt;();
}&lt;/pre&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;At this point, we’re much more informed about how we’re going to read the contents from the file. We’re also ready to make some design decisions and rename our test accordingly to reflect what we’ve learned. We decide that (for simplicity sake) the parser should always return a list of items even if the file is empty. While the implementation may be crude, the test is complete for this scenario, so we rename our test to match this decision and add an additional assertion to improve the intent of the test.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;Sidenote: The naming convention for these tests is based on Roy Osherove’s naming convention, which has three parts:&lt;/em&gt;&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;&lt;em&gt;Feature being tested &lt;/em&gt;&lt;/li&gt;

    &lt;li&gt;&lt;em&gt;Scenario &lt;/em&gt;&lt;/li&gt;

    &lt;li&gt;&lt;em&gt;Expected Behaviour&lt;/em&gt; &lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;[TestMethod]
public void WhenParsingAStream_WithNoData_ShouldProduceEmptyContent()
{
    var parser = new NDependStreamParser();
    var sr = new StringReader(&amp;quot;&amp;quot;);
    var reader = XmlReader.Create(sr);

    IEnumerable&amp;lt;ProjectAssembly&amp;gt; results =
        parser.Parse(reader);

    Assert.IsNotNull( results,
        &amp;quot;The results were not produced.&amp;quot; );

    Assert.AreEqual( 0, results.Count(),
        &amp;quot;The results should be empty.&amp;quot; );
}&lt;/pre&gt;

&lt;h3&gt;Adding Tests&lt;/h3&gt;

&lt;p&gt;We’re now ready to start adding additional tests. Based on what we know now, we can start each test with a proper name and then fill in the details.&lt;/p&gt;

&lt;p&gt;With each test, we learn a little bit more about our model and the expected behaviour of the parser. The NDepend file contains a list of assemblies, where each assembly contains a list of assemblies that it references and a list of assemblies that it depends on. The subsequent tests we wrote:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;WhenParsingAStream_ThatContainsAssemblies_ShouldProduceContent &lt;/li&gt;

  &lt;li&gt;WhenParsingAStream_ThatContainsAssembliesWithReferences_EnsureReferenceInformationIsAvailable &lt;/li&gt;

  &lt;li&gt;WhenParsingAStream_ThatContainsAssembliesWithDependencies_EnsureDependencyInformationIsAvailable &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s important to note that these tests aren’t just building the implementation details of the parser, we’re building our model object as well. Properties are added to the model as needed.&lt;/p&gt;

&lt;h3&gt;Refactoring&lt;/h3&gt;

&lt;p&gt;Under the TDD mantra “Red, Green, Refactor”, “Refactor” implies that you should refactor the implementation after you’ve written the tests. However, the scope of the refactor should apply to both tests and implementation. &lt;/p&gt;

&lt;p&gt;Within the implementation, you should be able to optimize the code freely assuming that you aren’t adding additional functionality. (My original implementation details of using the XmlParser was embarrassing, and I ended up experimenting with the reader syntax later that night until I found a clean elegant solution. The tests were invaluable for discovering what was possible.)&lt;/p&gt;

&lt;p&gt;Within the tests, refactoring means removing as much duplication as possible without obscuring the intent of the test. By the time we started the third test, the string-concatenation to assemble our xml and plumbing code to create our XmlReader was copied and pasted several times. This plumbing logic slowly evolved into a utility class that used an XmlWriter to construct our test data.&lt;/p&gt;

&lt;p&gt;Next: &lt;a href="http://www.bryancook.net/2011/09/guided-by-testsday-three.html"&gt;Day Three&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8942599-5819878781880088049?l=www.bryancook.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/DlPiCtGLREGQMmMvfT3NseMgxlc/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/DlPiCtGLREGQMmMvfT3NseMgxlc/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/DlPiCtGLREGQMmMvfT3NseMgxlc/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/DlPiCtGLREGQMmMvfT3NseMgxlc/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=Rsd2p5frCF8:f8F2gFQV1oA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=Rsd2p5frCF8:f8F2gFQV1oA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=Rsd2p5frCF8:f8F2gFQV1oA:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=Rsd2p5frCF8:f8F2gFQV1oA:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?i=Rsd2p5frCF8:f8F2gFQV1oA:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bryanbcook/~4/Rsd2p5frCF8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.bryancook.net/feeds/5819878781880088049/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8942599&amp;postID=5819878781880088049" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/5819878781880088049?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/5819878781880088049?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/bryanbcook/~3/Rsd2p5frCF8/guided-by-testsday-two.html" title="Guided by Tests–Day Two" /><author><name>bryan</name><uri>http://www.blogger.com/profile/01332614158223702009</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh3.ggpht.com/-3DWnGwTRKpA/TmhPkG-CBQI/AAAAAAAAAg4/6LbOCtLc4pk/s72-c/LogicalFlowDiagram_thumb%25255B119%25255D.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.bryancook.net/2011/09/guided-by-testsday-two.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkYCR34zeSp7ImA9WhdWFEU.&quot;"><id>tag:blogger.com,1999:blog-8942599.post-3280836272981609523</id><published>2011-09-07T09:14:00.001-04:00</published><updated>2011-09-08T09:22:46.081-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-08T09:22:46.081-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".net" /><category scheme="http://www.blogger.com/atom/ns#" term="TDD" /><category scheme="http://www.blogger.com/atom/ns#" term="guided by tests" /><title>Guided by Tests–Day One</title><content type="html">&lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;This post is second in a series about a group TDD experiment to build an application in 5 days using only tests.&amp;#160; Read the &lt;a href="http://www.bryancook.net/2011/09/guided-by-tests.html" target="_blank"&gt;beginning here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Today is the pitch. We'll talk about what we're going to build and how we're going to do it, but first we need to understand the motivation behind our methodology. We need to understand why we test.&lt;/p&gt;  &lt;h3&gt;Methodology&lt;/h3&gt;  &lt;p&gt;&lt;a href="http://www.threeriversinstitute.org/Kent%20Beck.htm" target="_blank"&gt;Kent Beck&lt;/a&gt;'s &lt;a href="http://www.chapters.indigo.ca/books/Test-Driven-Development-By-Example-Kent-Beck/9780321146533-item.html" target="_blank"&gt;TDD by Example&lt;/a&gt; was one of the first books I read about TDD and to this day it's still one of my favourites. I know many prefer &lt;a href="http://osherove.com/about/" target="_blank"&gt;Roy Osherove&lt;/a&gt;'s &lt;a href="http://www.chapters.indigo.ca/books/Art-Unit-Testing-Examples-Net-Roy-Osherove-Osherove-Roy/9781933988276-item.html" target="_blank"&gt;Art of Unit Testing&lt;/a&gt; (which I also highly recommend) because it's newer and has .net examples, but in comparison they are very different books.&amp;#160; Roy's book represents the evolved practice of Unit Testing and it provides a solid path to understand testing and the modern testing frameworks that have taken shape since Kent's book was written in 2002. Kent's book is raw, the primordial ooze that walked upon land and declared itself sentient, it defines the methodology as an offshoot of extreme programming and is the basis for the frameworks Roy explains how to use. If you're looking for a book on how to start and the mechanics of TDD, this is it.&lt;/p&gt;  &lt;p&gt;As an offshoot of extreme programming, the core philosophy of TDD is:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Demonstrate working software at all times &lt;/li&gt;    &lt;li&gt;Improve confidence while making changes &lt;/li&gt;    &lt;li&gt;Build only the software you need &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;My experiment is based on the strategies defined in Kent's book – the premise is to demonstrate working software and get early feedback – but in a nutshell, you make incredibly small incremental changes and compile and run tests a lot (30-50 times per hour). I sometimes refer to this rapid code/test cycle as the &lt;em&gt;Kent Beck Method&lt;/em&gt; or &lt;em&gt;Proper TDD&lt;/em&gt;. I don't necessarily follow this technique when I code, but it's a great way to start until you learn how to find your balance. Eventually, running tests becomes instinct or muscle memory – you just know when you should.&lt;/p&gt;  &lt;h3&gt;The Rules&lt;/h3&gt;  &lt;p&gt;For our experiment, we followed these rules:&lt;/p&gt;  &lt;h4&gt;1. Tests must be written first.&lt;/h4&gt;  &lt;p&gt;This means that before we do anything, we start by writing a test. If we need to create classes in order to get the test to compile, that is a secondary concern: create the test first, even if it doesn’t compile, then introduce what you need.&lt;/p&gt;  &lt;h4&gt;2. Code only gets written to satisfy a test.&lt;/h4&gt;  &lt;p&gt;This means that we write only the code that is needed to make a test pass. If while writing the code you're tempted to add additional functionality that you might need, don't succumb to writing that code now. Instead, focus on the current test and make a note for additional tests. This ensures that we only write the code that is needed.&lt;/p&gt;  &lt;h4&gt;3. Code must always compile (at least within 30 seconds of making a change)&lt;/h4&gt;  &lt;p&gt;This may seem like a difficult practice to adopt, but it is extremely valuable. To follow this rule, make small changes that can be corrected easily and compile frequently to provide early feedback. If you find yourself breaking a contract that takes twenty minutes to fix, you're doing it wrong.&lt;/p&gt;  &lt;h4&gt;4. Time between red/green must be very short (&amp;lt;1 minute, meaning rollback if you're not sure.)&lt;/h4&gt;  &lt;p&gt;This is also a very difficult rule to keep, but it forces you to recognize the consequences of your changes. You should know before you run the test whether it's going to pass or fail. Your brain will explode when you're wrong (and that’s a good thing).&lt;/p&gt;  &lt;h3&gt;The Problem&lt;/h3&gt;  &lt;p&gt;As mentioned in the &lt;a href="http://www.bryancook.net/2011/09/guided-by-tests.html" target="_blank"&gt;first post&lt;/a&gt;, my current project uses NDepend to perform static analysis as part of our build process. The build generates a static image. As our solution analyzes over 80 assemblies, the text becomes illegible, and its somewhat difficult to read (image text has been blurred to hide assembly names).&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/-49AeKcHEDsI/TmduTMQq1fI/AAAAAAAAAgo/kJK7LxcrTK8/s1600-h/ComponentDependenciesDiagram%25255B2%25255D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="ComponentDependenciesDiagram" border="0" alt="Geez!" src="http://lh4.ggpht.com/-CpUVfvj5QPk/TmduTjICXNI/AAAAAAAAAgs/k1C6AkMh7HM/ComponentDependenciesDiagram_thumb.png?imgmax=800" width="226" height="197" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;The two primary use cases I wanted the application to have:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Allow the user to select an NDepend &lt;em&gt;AssembliesDependencies.xml&lt;/em&gt; file and display it as a graph &lt;/li&gt;    &lt;li&gt;Once the graph has been rendered, provide an option to choose which assemblies should be displayed &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;The graph would be implemented using &lt;a href="http://graphsharp.codeplex.com" target="_blank"&gt;Graph#,&lt;/a&gt; and we could borrow much of the presentation details from &lt;a href="http://sachabarber.net/?p=815" target="_blank"&gt;Sacha Barber’s post&lt;/a&gt;. Using Graph# would provide a rich user-experience, all we’d need to do is implement the surrounding project framework.&amp;#160; &lt;em&gt;Piece of cake!&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;I asked the team if there were any additional considerations that they would like to see. We would take some of these considerations into account when designing the solution. Some suggestions were made:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Multi-tab support so that more than one graph can be open at a time &lt;/li&gt;    &lt;li&gt;Ability to color code the nodes &lt;/li&gt;    &lt;li&gt;Ability to save a project (and load it presumably) &lt;/li&gt; &lt;/ul&gt;  &lt;h3&gt;Getting Started&lt;/h3&gt;  &lt;p&gt;With the few remaining minutes in the lunch hour, we set up the project:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Create a new WPF Project.&amp;#160; Solution Name: DependencyViewer, Project Name: DependencyViewer. &lt;/li&gt;    &lt;li&gt;Create a new Test Project, DependencyViewer.Tests &lt;/li&gt;    &lt;li&gt;Added a reference from the Test Project to the WPF Project. &lt;/li&gt;    &lt;li&gt;Deleted all automatically generated files:      &lt;ol&gt;       &lt;li&gt;App.xaml &lt;/li&gt;        &lt;li&gt;MainWindow.xaml &lt;/li&gt;        &lt;li&gt;TestClass1. &lt;/li&gt;     &lt;/ol&gt;   &lt;/li&gt;    &lt;li&gt;Renamed the default namespace of the Test Project to match the namespace of the WPF Application. &lt;em&gt;For more info, read &lt;a href="http://www.bryancook.net/2008/05/tdd-tips-unit-test-namespace.html" target="_blank"&gt;this detailed post which explains why you should&lt;/a&gt;.&lt;/em&gt; &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;While I have some preferences on third-party tools, etc – we’ll get to those as they’re needed.&lt;/p&gt;  &lt;p&gt;Next: &lt;a href="http://www.bryancook.net/2011/09/guided-by-testsday-two.html"&gt;Day Two&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8942599-3280836272981609523?l=www.bryancook.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Idn6sCzsb6fUlPmxkZpWlv9KfVw/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Idn6sCzsb6fUlPmxkZpWlv9KfVw/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Idn6sCzsb6fUlPmxkZpWlv9KfVw/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Idn6sCzsb6fUlPmxkZpWlv9KfVw/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=t8SbkXLb1Ws:ynJc7x9SOhY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=t8SbkXLb1Ws:ynJc7x9SOhY:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=t8SbkXLb1Ws:ynJc7x9SOhY:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=t8SbkXLb1Ws:ynJc7x9SOhY:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?i=t8SbkXLb1Ws:ynJc7x9SOhY:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bryanbcook/~4/t8SbkXLb1Ws" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.bryancook.net/feeds/3280836272981609523/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8942599&amp;postID=3280836272981609523" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/3280836272981609523?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/3280836272981609523?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/bryanbcook/~3/t8SbkXLb1Ws/guided-by-testsday-one.html" title="Guided by Tests–Day One" /><author><name>bryan</name><uri>http://www.blogger.com/profile/01332614158223702009</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh4.ggpht.com/-CpUVfvj5QPk/TmduTjICXNI/AAAAAAAAAgs/k1C6AkMh7HM/s72-c/ComponentDependenciesDiagram_thumb.png?imgmax=800" height="72" width="72" /><thr:total>1</thr:total><feedburner:origLink>http://www.bryancook.net/2011/09/guided-by-testsday-one.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0QCRXo9cSp7ImA9WhdaFEs.&quot;"><id>tag:blogger.com,1999:blog-8942599.post-415570280687849538</id><published>2011-09-06T08:30:00.000-04:00</published><updated>2011-10-24T10:09:24.469-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-24T10:09:24.469-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".net" /><category scheme="http://www.blogger.com/atom/ns#" term="TDD" /><category scheme="http://www.blogger.com/atom/ns#" term="guided by tests" /><title>Guided By Tests</title><content type="html">&lt;p&gt;Last week I started a TDD experiment at work. I gathered some interest from management and then sought out participants with a very simple concept: build an application in 5 days, over lunch hour, using nothing but unit tests to drive development.&lt;/p&gt;  &lt;p&gt;My next few posts will be part of a series that shares the details of that experiment.&lt;/p&gt;  &lt;h3&gt;Motivation&lt;/h3&gt;  &lt;p&gt;Over the years, I've had many conversations with colleagues about TDD. One of the most common comments made is that they don't know what to test or where to start. Another common theme is the desire to get into a project at the very beginning where all the project members have bought into the concept. I've always found this comment to be strange. It's a great comment and it makes perfect sense but -- why the beginning? Why not the middle or end of the project after the tests are put into place? I sense they're expressing two things. First they're expressing the obvious, that life for the development team would be much different if they had tests from the beginning. And secondly, they're interested in understanding how the team managed to establish and sustain the process.&lt;/p&gt;  &lt;p&gt;The goal of my experiment would show how to start a project with TDD and to walk through the process of deconstructing requirements into testable components. The process would use tests as the delivery mechanism but would also showcase how to design software for testability using separation of concerns and SOLID OO design principles. Requirements and documentation would be deliberately vague, and the application would need to showcase common real world problems. The tricky part would be finding an application to build.&lt;/p&gt;  &lt;p&gt;Fortunately, I was recently inspired by a &lt;a href="http://sachabarber.net/?p=815" target="_blank"&gt;post by Sacha Barber&lt;/a&gt; that provides a great example of how to use the open source graphing framework &lt;a href="http://graphsharp.codeplex.com/" target="_blank"&gt;Graph#&lt;/a&gt; to build a graph application in WPF. I immediately saw how I could use this. My current project uses &lt;a href="http://www.ndepend.com/" target="_blank"&gt;NDepend&lt;/a&gt; for static analysis and as part of the build process it produces an image of our dependency graph. With over 80 nodes and illegible text, the static image is mostly useless. However, the build process spits out the details for the graph as an XML file. With some simple xml parsing, I could use Sacha's example to build my own graph.&lt;/p&gt;  &lt;p&gt;So rather than spending my weekend working on this application, why not turn this into a teaching exercise? (Ironically, I'm spending my weekends blogging about it)&lt;/p&gt;  &lt;p&gt;Follow up posts:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://www.bryancook.net/2011/09/guided-by-testsday-one.html" target="_blank"&gt;Guided by Tests – Day One&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.bryancook.net/2011/09/guided-by-testsday-two.html"&gt;Guided by Tests – Day Two&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.bryancook.net/2011/09/guided-by-testsday-three.html"&gt;Guided by Tests – Day Three&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.bryancook.net/2011/09/guided-by-testsday-four.html"&gt;Guided by Tests – Day Four&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.bryancook.net/2011/09/guided-by-testsday-five.html"&gt;Guided by Tests – Day Five&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.bryancook.net/2011/10/guided-by-testsday-six.html"&gt;Guided by Tests – Day Six&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.bryancook.net/2011/10/guided-by-testsday-seven.html"&gt;Guided by Tests – Day Seven&lt;/a&gt;&amp;#160; &lt;/li&gt; &lt;/ul&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8942599-415570280687849538?l=www.bryancook.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/WJkFMwePVXCMlZ4uqW4Z0bOtMRY/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/WJkFMwePVXCMlZ4uqW4Z0bOtMRY/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/WJkFMwePVXCMlZ4uqW4Z0bOtMRY/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/WJkFMwePVXCMlZ4uqW4Z0bOtMRY/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=5gYxUfn8WuY:q1WNXzGDbqw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=5gYxUfn8WuY:q1WNXzGDbqw:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=5gYxUfn8WuY:q1WNXzGDbqw:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=5gYxUfn8WuY:q1WNXzGDbqw:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?i=5gYxUfn8WuY:q1WNXzGDbqw:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bryanbcook/~4/5gYxUfn8WuY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.bryancook.net/feeds/415570280687849538/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8942599&amp;postID=415570280687849538" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/415570280687849538?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/415570280687849538?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/bryanbcook/~3/5gYxUfn8WuY/guided-by-tests.html" title="Guided By Tests" /><author><name>bryan</name><uri>http://www.blogger.com/profile/01332614158223702009</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.bryancook.net/2011/09/guided-by-tests.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkQBQ3cyfip7ImA9WhdQEUs.&quot;"><id>tag:blogger.com,1999:blog-8942599.post-6309090016902978150</id><published>2011-08-12T08:58:00.000-04:00</published><updated>2011-08-12T10:45:52.996-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-12T10:45:52.996-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="unity" /><category scheme="http://www.blogger.com/atom/ns#" term=".net" /><category scheme="http://www.blogger.com/atom/ns#" term="TDD" /><category scheme="http://www.blogger.com/atom/ns#" term="Software Design" /><title>On Dependency Injection and Violating Encapsulation Concerns</title><content type="html">&lt;p&gt;For me, life is greatly simplified when dependencies are inverted and constructor injection is used to provide a clean mechanism to introduce dependencies to a class. It's explicit and easy to test. &lt;/p&gt;  &lt;p&gt;Others however argue that some dependencies are private implementation details to the class and external callers shouldn't know about them. The argument is that exposing these dependencies through the constructor violates encapsulation and introduces coupling. This argument is usually coupled with resistance to using interfaces or classes with virtual methods. &lt;/p&gt;  &lt;p&gt;From my experience, there are times when composition in the constructor makes sense but there's a fine line when constructor injection should be used. I want to use this post to elaborate on these arguments and provide my perspective on this debate.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Does Constructor Injection violate Encapsulation?&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Does exposing the internal dependencies of a class in the constructor expose the implementation details of a class? If you are allowing callers to construct the class directly, then you are most certainly breaking encapsulation as the callers must posses the knowledge of how to construct your class.&amp;#160; However, regardless of the constructor arguments if callers know how to construct your class you are also coupling to a direct implementation and will undoubtedly create a test impediment elsewhere. There are some simple fixes for this (including more constructor injection or another inversion of control technique) which I'll outline later.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;So if constructor injection violates encapsulation, when is it safe to use composition in the constructor?&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;It really depends on the complexity and relationship of the subject to its dependencies. If the internal dependencies are simple and contain no external dependencies there is likely no harm in using composition to instantiate them in the constructor (the same argument can be made for small static utility methods). For instance, a utility class that performs some translation or other processing activity with limited outcomes may work as a private implementation detail. Problems arise as soon as these dependencies take on further dependencies or produce output that influences the conditional logic of the subject under test. When this happens the argument to keep these as internally controlled dependencies becomes flawed and it may be necessary to upgrade the &amp;quot;private implementation detail&amp;quot; to an inverted dependency.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Before:&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;This example shows a class that has a private implementation detail that influences logic of the subject under test. The consequence of this design is that the internal details of the validator leak into the test specifications. This leads to very brittle tests as tests must concern themselves with object construction and validation rules -- any change to the object or validation logic will break the tests.&lt;/p&gt;  &lt;pre class="brush: csharp; auto-links: false;"&gt;public class MyModelTranslator
{
    public MyModelTranslator()
    {
       _validator = new MyModelValidator();
    }

    public MyViewModel CreateResult(MyModelObject model)
    {
        var result = new MyViewModel();
        
        if (_validator.Validate( model ));
        {
             result.Id = model.Id;
        }
        else {
            result.State = MyResultState.Invalid;
        }
        return result;
    }
}

[Test]
public void WhenCreatingAResult_FromAVaidModelObejct_ShouldHaveSameId()
{
    var subject = new MyModelTranslator();

    // create model object with deep understanding how Id's
    // and expiry dates are related 
    var model = new MyModelObject()
    {
        Id = &amp;quot;S1402011&amp;quot;
        Expiry = Datetime.Parse(&amp;quot;12/31/2011&amp;quot;);
    };
    var result = subject.CreateResult( model );
    Assert.AreEqual(&amp;quot;S1402011&amp;quot;, result.Id);
}&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This example shows the above example corrected to use a constructor injected dependency that can be mocked. In doing so, the test is not encumbered with object creation or validation details and can easily simulate validate states without introducing brittleness.&lt;/p&gt;

&lt;pre class="brush: csharp; auto-links: false;"&gt;public class MyModelTranslator
{
    public MyModelTranslator(MyModelValidator validator);
    {
       _validator = validator;
    }

    // ...
}

[Test]
public void WhenCreatingAResult_FromAVaidModelObejct_ShouldHaveSameId()
{
    var validatorMock = new Mock&amp;lt;MyModelValidator&amp;gt;();

    var subject = new MyModelTranslator(validatorMock.Object);
    var model = new MyModelObject()
    {
      Id = &amp;quot;Dummy&amp;quot;
    };

    // we no longer care how validation is done, 
    // but we expect validation to occur and can easily control
    // and test outcomes
    ValidatorMock.Setup( x =&amp;gt; x.Validate( model )).Returns( true );

    var result = subject.CreateResult( model );
    Assert.AreEqual(&amp;quot;Dummy&amp;quot;, result.Id);
}&lt;/pre&gt;

&lt;h3&gt;Combatting Coupling with Inversion of Control&lt;/h3&gt;

&lt;p&gt;As the above points out, if we expose the dependencies of a class in the constructor we move the coupling problems out of the class and into the callers. This is not good but it can easily resolved. &lt;/p&gt;

&lt;p&gt;An example that shows that our controller class now knows about the MyModelValidator:&lt;/p&gt;

&lt;pre class="brush: csharp; gutter: false; auto-links: false;"&gt;public class MyController
{
    public MyController()
    {
        _translator = new MyModelTranslator( new MyModelValidator() );
    }
}&lt;/pre&gt;

&lt;h4&gt;More Constructor Injection&lt;/h4&gt;

&lt;p&gt;Ironically, the solution for solving coupling and construction problems is more constructor injection. This creates a &lt;em&gt;Russian Doll&lt;/em&gt; where construction logic is deferred and pushed higher and higher up the stack resulting in a top level component which is responsible for constructing the entire object graph. While this provides an intuitive API that clearly outlines dependencies, it's tedious to instantiate by hand. This is where dependency injection&amp;#160; frameworks like &lt;a href="http://unity.codeplex.com/" target="_blank"&gt;Unity&lt;/a&gt;, &lt;a href="http://structuremap.net/structuremap/" target="_blank"&gt;StructureMap&lt;/a&gt; and others come in: they can do the heavy lifting for you. If done right, your application should only have well defined points where the dependency container is used.&lt;/p&gt;

&lt;pre class="brush: csharp; gutter: false; auto-links: false;"&gt;public class MyController : IController
{
    public MyController(MyModelTranslator translator)
    {
        _translator = translator;
    }
}&lt;/pre&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;Note that this assumes that the constructor arguments are abstractions -- either interfaces, abstract classes or classes with virtual methods. In effect, by exposing the constructor arguments we trade off the highly sealed encapsulated black box for an open for extensibility model.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;Factories / Builders&lt;/h4&gt;

&lt;p&gt;In some cases, using Constructor Injection everywhere might not be a good fit. For example, if you had a very large and complex object graph, creating everything upfront using constructor injection might represent a performance problem. Likewise, not all parts of the object graph will be used immediately and you may need to defer construction until needed.&amp;#160; In these cases, the good ol' Gang of Four Factory pattern is a handy mechanism to lazy load components.&lt;/p&gt;

&lt;p&gt;So rather that construct the entire object graph and pass resolved dependencies as constructor arguments, pass the factory instead and create the lower-level sub-dependencies when needed.&lt;/p&gt;

&lt;pre class="brush: csharp; auto-links: false;"&gt;public class MyControllerFactory : IControllerFactory
{
    private IUnityContainer _container;
    
    public MyControllerFactory(IUnityContainer container)
    {
        _container = container;
    }

    public IController Create()
    {
        _container.Resolve&amp;lt;MyController&amp;gt;();
    }
}&lt;/pre&gt;

&lt;h4&gt;Service Location&lt;/h4&gt;

&lt;p&gt;While Service Location is an effective mechanism for introducing inversion of control, I'm listing it last for a reason. Unlike Constructor Injection, Service Location couples all your code to an intermediate provider. Depending on your application and relative complexity this might be acceptable, but from personal experience it's a very slippery slope -- actually, it would be more appropriate to call it a cliff because removing or replacing the container from an existing codebase can be a massive undertaking.&lt;/p&gt;

&lt;p&gt;I see service location as a useful tool when refactoring legacy code towards Constructor Injection. The lower &amp;quot;leaf-nodes&amp;quot; of the object graph can take advantage of constructor injection and the higher nodes can temporarily use service location to create the &amp;quot;leaves&amp;quot;. As you refactor, the service locator is removed and replaced with constructor injection, which results in an easier to test and discoverable API. This also provides a pragmatic bottom up refactor approach.&lt;/p&gt;

&lt;h3&gt;Summary&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Use &amp;quot;new&amp;quot; when dependencies have no external dependencies or don't influence conditional flow of the subject.&amp;#160; Conversely, use constructor injection when dependencies have additional dependencies. &lt;/li&gt;

  &lt;li&gt;Use an IoC container to construct objects that use constructor injection, but only use the IoC container in high level components that are responsible for construction of the object graph. If constructing the entire object graph is a performance concern, consider encapsulating the container in a Factory that can be used to resolve remaining parts of the object graph when needed. &lt;/li&gt;

  &lt;li&gt;To prevent violating encapsulation concerns, use inversion of control to promote using abstractions instead of concrete dependencies. 
    &lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8942599-6309090016902978150?l=www.bryancook.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/bQwme7F5NNsVfyb9A2eifn1YxTc/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/bQwme7F5NNsVfyb9A2eifn1YxTc/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/bQwme7F5NNsVfyb9A2eifn1YxTc/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/bQwme7F5NNsVfyb9A2eifn1YxTc/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=bCGQDx6rG_g:TS4X5dbXlGA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=bCGQDx6rG_g:TS4X5dbXlGA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=bCGQDx6rG_g:TS4X5dbXlGA:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=bCGQDx6rG_g:TS4X5dbXlGA:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?i=bCGQDx6rG_g:TS4X5dbXlGA:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bryanbcook/~4/bCGQDx6rG_g" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.bryancook.net/feeds/6309090016902978150/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8942599&amp;postID=6309090016902978150" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/6309090016902978150?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/6309090016902978150?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/bryanbcook/~3/bCGQDx6rG_g/on-dependency-injection-and-violating.html" title="On Dependency Injection and Violating Encapsulation Concerns" /><author><name>bryan</name><uri>http://www.blogger.com/profile/01332614158223702009</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.bryancook.net/2011/08/on-dependency-injection-and-violating.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEYFRXk4eyp7ImA9WhdTFkg.&quot;"><id>tag:blogger.com,1999:blog-8942599.post-7116129235922321267</id><published>2011-07-14T10:01:00.000-04:00</published><updated>2011-07-14T10:01:54.733-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-14T10:01:54.733-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".net" /><category scheme="http://www.blogger.com/atom/ns#" term="rants" /><title>So You've Decided To Go "Full Retard"!</title><content type="html">&lt;p&gt;Congratulations! You've done something very clever! Your out of the box thinking has now retarded the development process!&lt;/p&gt;  &lt;p&gt;&lt;a href="http://www.amazon.com/exec/obidos/ASIN/B001H5X7KC/ref=nosim/paramountcom-20"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="you mmm-m-m-m-make me happy" border="0" alt="black-downey-simple-jack" src="http://lh5.ggpht.com/-QxyGm88-op8/Th5aYJtaj0I/AAAAAAAAAgc/4c-xDsFGbg4/black-downey-simple-jack%25255B4%25255D.jpg?imgmax=800" width="434" height="291" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Oh? You're not sure what I'm talking about? Well remember that thing you did? I'm pretty sure you knew that it felt like a hack when you wrote it but then you quickly convinced yourself that you'd invented something insanely brilliant. Well, it wasn't. It &lt;em&gt;was&lt;/em&gt; a hack. And now, somewhere, kittens are dying.&lt;/p&gt;  &lt;p&gt;Yes, I know the compiler didn't complain but that doesn't technically make it valid code. Just because you can use operator overloading to concatenate files doesn't mean you should.&amp;#160; Oh yeah and remember that non-standard event signature you implemented to save time? Well it turns out that we really did need event arguments and proper error handling, so now Jimmy, who is replacing you btw, is going to have to rewrite it. kthxbai.&lt;/p&gt;  &lt;p&gt;It's not clever, or agile or lean or whatever it is you think it is. It's sloppy. I can't think of a profession where cutting corners is okay.&lt;/p&gt;  &lt;p&gt;So before you start bringing the protestors to your aid that &amp;quot;retarded&amp;quot; is an offensive word, I mean it for the true sense, &lt;a href="http://dictionary.reference.com/browse/retard" target="_blank"&gt;for slowing down the development or progress of action, process, etc.&lt;/a&gt;&amp;#160; Anytime a developer squints and wonders what was going through your mind -- you've failed to help others understand your code.&amp;#160; And know what the funny thing is? It doesn't take much more to do it right. It might take an few extra seconds to put xml comments at the top of the method, or a few extra minutes to write a unit test.&amp;#160; If you consider that we spend more time trying to understand code than writing it, it really makes sense to ensure that code remains consistent.&lt;/p&gt;  &lt;p&gt;For me, clever is often synonymous with stupid. Everyone's entitled to a few embarrassing &amp;quot;clever&amp;quot; moments a year as long as the own up to it. Going full in and swearing by it, well, …sometimes you come back empty handed.&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:5737277B-5D6D-4f48-ABFC-DD9C333F4C5D:4d470f89-b698-4a77-8b66-357a9cb4fc89" class="wlWriterEditableSmartContent"&gt;&lt;div id="acf93730-cad8-4e4f-a9c9-a517cdb69091" style="margin: 0px; padding: 0px; display: inline;"&gt;&lt;div&gt;&lt;a href="http://www.youtube.com/watch?v=SgHITc1OL-c&amp;amp;feature=youtube_gdata_player" target="_new"&gt;&lt;img src="http://lh6.ggpht.com/-BBVUb9aM8Tk/Th720SPCpsI/AAAAAAAAAgk/Oz0SQJiID34/video135f499e1c69%25255B2%25255D.jpg?imgmax=800" style="border-style: none" galleryimg="no" onload="var downlevelDiv = document.getElementById('acf93730-cad8-4e4f-a9c9-a517cdb69091'); downlevelDiv.innerHTML = &amp;quot;&amp;lt;div&amp;gt;&amp;lt;object width=\&amp;quot;510\&amp;quot; height=\&amp;quot;286\&amp;quot;&amp;gt;&amp;lt;param name=\&amp;quot;movie\&amp;quot; value=\&amp;quot;http://www.youtube.com/v/SgHITc1OL-c?hl=en&amp;amp;hd=1\&amp;quot;&amp;gt;&amp;lt;\/param&amp;gt;&amp;lt;embed src=\&amp;quot;http://www.youtube.com/v/SgHITc1OL-c?hl=en&amp;amp;hd=1\&amp;quot; type=\&amp;quot;application/x-shockwave-flash\&amp;quot; width=\&amp;quot;510\&amp;quot; height=\&amp;quot;286\&amp;quot;&amp;gt;&amp;lt;\/embed&amp;gt;&amp;lt;\/object&amp;gt;&amp;lt;\/div&amp;gt;&amp;quot;;" alt=""&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8942599-7116129235922321267?l=www.bryancook.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/npmr5APOgQEuJOIG_D35LoQRLwc/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/npmr5APOgQEuJOIG_D35LoQRLwc/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/npmr5APOgQEuJOIG_D35LoQRLwc/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/npmr5APOgQEuJOIG_D35LoQRLwc/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=TueQslwbA4w:IruTPahdqWU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=TueQslwbA4w:IruTPahdqWU:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=TueQslwbA4w:IruTPahdqWU:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=TueQslwbA4w:IruTPahdqWU:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?i=TueQslwbA4w:IruTPahdqWU:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bryanbcook/~4/TueQslwbA4w" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.bryancook.net/feeds/7116129235922321267/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8942599&amp;postID=7116129235922321267" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/7116129235922321267?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/7116129235922321267?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/bryanbcook/~3/TueQslwbA4w/so-you-decided-to-go-retard.html" title="So You&amp;#39;ve Decided To Go &amp;quot;Full Retard&amp;quot;!" /><author><name>bryan</name><uri>http://www.blogger.com/profile/01332614158223702009</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh5.ggpht.com/-QxyGm88-op8/Th5aYJtaj0I/AAAAAAAAAgc/4c-xDsFGbg4/s72-c/black-downey-simple-jack%25255B4%25255D.jpg?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.bryancook.net/2011/07/so-you-decided-to-go-retard.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkcBRnY6fip7ImA9WhdTFEo.&quot;"><id>tag:blogger.com,1999:blog-8942599.post-8220864799977757736</id><published>2011-07-12T08:46:00.000-04:00</published><updated>2011-07-12T09:40:57.816-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-12T09:40:57.816-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Tips" /><category scheme="http://www.blogger.com/atom/ns#" term=".net" /><category scheme="http://www.blogger.com/atom/ns#" term="Visual Studio" /><title>Visual Studio Regular Expressions for Find &amp; Replace</title><content type="html">&lt;p&gt;Visual Studio has had support for regular expressions for Find &amp;amp; Replace for several versions, but I've only really used it for simple searches. I recently had a problem where I needed to introduce a set of changes to a very large object model. It occurred to me that this could be greatly simplified with some pattern matching, but I was genuinely surprised to learn that Visual Studio had their &lt;a href="http://msdn.microsoft.com/en-us/library/2k3te2cs(v=VS.100).aspx" target="_blank"&gt;own brand of Regular Expressions&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;After spending some time learning the new syntax I had a really simple expression to modify all of my property setters:&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Original:&lt;/strong&gt;&lt;/p&gt;  &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;public string PropertyName
{
    get { return _propertyName; }
    set
    {
        _propertyName = value;
        RaisePropertyChanged(&amp;quot;PropertyName&amp;quot;);
    }
}&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Goal:&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;public string PropertyName
{
    get { return _propertyName; }
    set
    {
        if ( value == _propertyName )
             return;            
        _propertyName = value;
        RaisePropertyChanged(&amp;quot;PropertyName&amp;quot;);
    }
}&lt;/pre&gt;

&lt;p&gt;Here’s a quick capture and breakdown of the pattern I used.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh4.ggpht.com/-U1X9P_Y6-wA/ThvIdYaf3GI/AAAAAAAAAgQ/-KHXrFsEalo/s1600-h/image%25255B5%25255D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/-b08z_rZJGtM/ThvIeXgYyKI/AAAAAAAAAgU/xTpuD_gSww8/image_thumb%25255B3%25255D.png?imgmax=800" width="356" height="484" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Find:&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="brush: plain; gutter: false; auto-links: false;"&gt;^{:Wh*}&amp;lt;{_:a+} = value;&lt;/pre&gt;

&lt;ul&gt;
  &lt;li&gt;^ = beginning of line &lt;/li&gt;

  &lt;li&gt;{ = start of capture group #1 &lt;/li&gt;

  &lt;li&gt;:Wh = Any whitespace character &lt;/li&gt;

  &lt;li&gt;* = zero or more occurrences &lt;/li&gt;

  &lt;li&gt;} = end of capture group #1 &lt;/li&gt;

  &lt;li&gt;&amp;lt; = beginning of word &lt;/li&gt;

  &lt;li&gt;{ = start of capture group #2 &lt;/li&gt;

  &lt;li&gt;_ = I want to the text to start with an underscore &lt;/li&gt;

  &lt;li&gt;:a = any alpha numerical character &lt;/li&gt;

  &lt;li&gt;+ = 1 or more alpha numerical characters &lt;/li&gt;

  &lt;li&gt;} end of capture group #2 &lt;/li&gt;

  &lt;li&gt;“ = value;” = exact text match &lt;!--EndFragment--&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Replace:&lt;/strong&gt;&lt;/p&gt;

&lt;pre class="brush: plain; gutter: false; auto-links: false;"&gt;\1(if (\2 == value)\n\1\t\return;\n\1\2 = value;&lt;/pre&gt;

&lt;p&gt;The Replace algorithm is fairly straight forward, where “\1” and “\2” represent capture groups 1 and 2.&amp;#160; Since capture group #1 represents the leading whitespace, I’m using it in the replace pattern to keep the original padding and to base new lines from that point.&amp;#160; For example, “\n\1\t” introduces a newline, the original whitespace and then a new tab.&lt;/p&gt;

&lt;p&gt;It’s &lt;a href="http://www.codinghorror.com/blog/2006/07/the-visual-studio-ide-and-regular-expressions.html" target="_blank"&gt;seems insane&lt;/a&gt; that Microsoft implemented their own regular expression engine, but there’s some interesting things in there, such as being able to match on quoted text, etc.&lt;/p&gt;

&lt;p&gt;I know this ain’t much, but hopefully it will inspire you to write some nifty expressions.&amp;#160; Cheers.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8942599-8220864799977757736?l=www.bryancook.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/zeGpXdtOVi2J1EXlzIQxMIdbNtk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/zeGpXdtOVi2J1EXlzIQxMIdbNtk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/zeGpXdtOVi2J1EXlzIQxMIdbNtk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/zeGpXdtOVi2J1EXlzIQxMIdbNtk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=IfbvhoXJeCY:xlSWLsHLQtQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=IfbvhoXJeCY:xlSWLsHLQtQ:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=IfbvhoXJeCY:xlSWLsHLQtQ:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=IfbvhoXJeCY:xlSWLsHLQtQ:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?i=IfbvhoXJeCY:xlSWLsHLQtQ:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bryanbcook/~4/IfbvhoXJeCY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.bryancook.net/feeds/8220864799977757736/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8942599&amp;postID=8220864799977757736" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/8220864799977757736?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/8220864799977757736?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/bryanbcook/~3/IfbvhoXJeCY/visual-studio-regular-expressions-for.html" title="Visual Studio Regular Expressions for Find &amp;amp; Replace" /><author><name>bryan</name><uri>http://www.blogger.com/profile/01332614158223702009</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh5.ggpht.com/-b08z_rZJGtM/ThvIeXgYyKI/AAAAAAAAAgU/xTpuD_gSww8/s72-c/image_thumb%25255B3%25255D.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.bryancook.net/2011/07/visual-studio-regular-expressions-for.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEACQXg-cCp7ImA9WhZaE0g.&quot;"><id>tag:blogger.com,1999:blog-8942599.post-3168981116451467629</id><published>2011-06-29T09:06:00.000-04:00</published><updated>2011-06-29T09:06:00.658-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-29T09:06:00.658-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="FxCop" /><category scheme="http://www.blogger.com/atom/ns#" term=".net" /><category scheme="http://www.blogger.com/atom/ns#" term="msbuild" /><title>Build Server Code Analysis Settings</title><content type="html">&lt;p&gt;I've been looking at ways to improve the reporting of Code Analysis as part of our Team Build. During my research I found that the RunCodeAnalysis setting as defined in the TFSBuild.proj differs significantly from the local MSBuild project schema options (&lt;a href="http://www.bryancook.net/2011/06/visual-studio-code-analysis-settings.html" target="_blank"&gt;see this post for a detailed break down of project level analysis settings&lt;/a&gt;).&lt;/p&gt;  &lt;p&gt;Specifically, &lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.build.workflow.activities.msbuild.runcodeanalysis.aspx" target="_blank"&gt;TFSBuild defines RunCodeAnalysis&lt;/a&gt; as &amp;quot;&lt;em&gt;Always&lt;/em&gt;&amp;quot;, &amp;quot;&lt;em&gt;Default&lt;/em&gt;&amp;quot; and &amp;quot;&lt;em&gt;Never&lt;/em&gt;&amp;quot; while MSBuild defines this as a simple true/false Boolean.&amp;#160; To make sense of this I hunted this down to this section of the Microsoft.TeamFoundation.Build.targets file:&lt;/p&gt;  &lt;pre class="brush: xml; gutter: false; toolbar: false; auto-links: false;"&gt;&amp;lt;Target Name=&amp;quot;CoreCompileSolution&amp;quot;&amp;gt;

  &amp;lt;PropertyGroup&amp;gt;
    &amp;lt;CodeAnalysisOption Condition=&amp;quot; '$(RunCodeAnalysis)'=='Always'&amp;quot;&amp;gt;RunCodeAnalysis=true&amp;lt;/CodeAnalysisOption&amp;gt;
    &amp;lt;CodeAnalysisOption Condition=&amp;quot; '$(RunCodeAnalysis)'=='Never'&amp;quot;&amp;gt;RunCodeAnalysis=false&amp;lt;/CodeAnalysisOption&amp;gt;
    &amp;lt;!-- ... --&amp;gt;
  &amp;lt;/PropertyGroup&amp;gt;
  &amp;lt;!-- ... --&amp;gt;
&amp;lt;/Target&amp;gt;&lt;/pre&gt;

&lt;p&gt;From this we can infer that &amp;quot;Default&amp;quot; setting does not provide a value to the runtime, while &amp;quot;Always&amp;quot; and &amp;quot;Never&amp;quot; map to True/False respectively.&amp;#160; But this raises the question, what's the difference between Default and Always, and what should I specify to effectively run Code Analysis?&lt;/p&gt;

&lt;p&gt;To answer this question, let's take an example of a small project with two projects.&amp;#160; Both projects are configured in the csproj with default settings.&amp;#160; For the purposes of the demo, I've altered the output folder to be at a folder called Output at the root of the solution:&lt;/p&gt;

&lt;pre class="brush: xml; gutter: false; toolbar: false; auto-links: false;"&gt;&amp;lt;PropertyGroup Condition=&amp;quot; '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' &amp;quot;&amp;gt;
  &amp;lt;DebugSymbols&amp;gt;true&amp;lt;/DebugSymbols&amp;gt;
  &amp;lt;DebugType&amp;gt;full&amp;lt;/DebugType&amp;gt;
  &amp;lt;Optimize&amp;gt;false&amp;lt;/Optimize&amp;gt;
  &amp;lt;OutputPath&amp;gt;..\Output&amp;lt;/OutputPath&amp;gt;
  &amp;lt;DefineConstants&amp;gt;DEBUG;TRACE&amp;lt;/DefineConstants&amp;gt;
  &amp;lt;ErrorReport&amp;gt;prompt&amp;lt;/ErrorReport&amp;gt;
  &amp;lt;WarningLevel&amp;gt;4&amp;lt;/WarningLevel&amp;gt;
&amp;lt;/PropertyGroup&amp;gt;&lt;/pre&gt;

&lt;p&gt;When we specify code analysis to run with the &amp;quot;Always&amp;quot; setting:&lt;/p&gt;

&lt;pre class="brush: plain; gutter: false; toolbar: false; auto-links: false;"&gt;Msbuild.exe Example.sln /p:RunCodeAnalysis=True&lt;/pre&gt;

&lt;p&gt;The Output folder contains the following files:&lt;/p&gt;

&lt;pre class="brush: plain; gutter: false; toolbar: false; auto-links: false;"&gt;CodeAnalysisExperiment1.dll 
CodeAnalysisExperiment1.dll.CodeAnalysisLog.xml 
CodeAnalysisExperiment1.dll.lastcodeanalysissucceeded 
CodeAnalysisExperiment1.pdb 
CodeAnalysisExperiment2.dll 
CodeAnalysisExperiment2.dll.CodeAnalysisLog.xml 
CodeAnalysisExperiment2.dll.lastcodeanalysissucceeded 
CodeAnalysisExperiment2.pdb&lt;/pre&gt;

&lt;p&gt;Close inspection of the console output shows that the Minimal ruleset was applied to my empty projects, despite having not configured either project for code analysis.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh5.ggpht.com/-y34SUZi5C1w/TglTREHjEoI/AAAAAAAAAfw/kCNDogmBO_c/s1600-h/DefaultRuleset%25255B3%25255D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="DefaultRuleset" border="0" alt="DefaultRuleset" src="http://lh3.ggpht.com/-I5Xtnqzudfg/TglTSz0-dBI/AAAAAAAAAf0/Ag6xfBMuqyM/DefaultRuleset_thumb%25255B1%25255D.png?imgmax=800" width="644" height="313" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If I tweak the project settings slightly such that one project explicitly declares RunCodeAnalysis as True and the other as False&lt;/p&gt;

&lt;pre class="brush: xml; gutter: false; toolbar: false; auto-links: false; highlight: [9];"&gt;&amp;lt;PropertyGroup Condition=&amp;quot; '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' &amp;quot;&amp;gt; 
  &amp;lt;DebugSymbols&amp;gt;true&amp;lt;/DebugSymbols&amp;gt; 
  &amp;lt;DebugType&amp;gt;full&amp;lt;/DebugType&amp;gt; 
  &amp;lt;Optimize&amp;gt;false&amp;lt;/Optimize&amp;gt; 
  &amp;lt;OutputPath&amp;gt;..\Output&amp;lt;/OutputPath&amp;gt; 
  &amp;lt;DefineConstants&amp;gt;DEBUG;TRACE&amp;lt;/DefineConstants&amp;gt; 
  &amp;lt;ErrorReport&amp;gt;prompt&amp;lt;/ErrorReport&amp;gt; 
  &amp;lt;WarningLevel&amp;gt;4&amp;lt;/WarningLevel&amp;gt; 
  &amp;lt;RunCodeAnalysis&amp;gt;false&amp;lt;/RunCodeAnalysis&amp;gt; 
&amp;lt;/PropertyGroup&amp;gt;&lt;/pre&gt;

&lt;p&gt;and…&lt;/p&gt;

&lt;pre class="brush: xml; gutter: false; toolbar: false; auto-links: false; highlight: [9];"&gt;&amp;lt;PropertyGroup Condition=&amp;quot; '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' &amp;quot;&amp;gt; 
  &amp;lt;DebugSymbols&amp;gt;true&amp;lt;/DebugSymbols&amp;gt; 
  &amp;lt;DebugType&amp;gt;full&amp;lt;/DebugType&amp;gt; 
  &amp;lt;Optimize&amp;gt;false&amp;lt;/Optimize&amp;gt; 
  &amp;lt;OutputPath&amp;gt;..\Output&amp;lt;/OutputPath&amp;gt; 
  &amp;lt;DefineConstants&amp;gt;DEBUG;TRACE&amp;lt;/DefineConstants&amp;gt; 
  &amp;lt;ErrorReport&amp;gt;prompt&amp;lt;/ErrorReport&amp;gt; 
  &amp;lt;WarningLevel&amp;gt;4&amp;lt;/WarningLevel&amp;gt; 
  &amp;lt;RunCodeAnalysis&amp;gt;true&amp;lt;/RunCodeAnalysis&amp;gt; 
&amp;lt;/PropertyGroup&amp;gt;&lt;/pre&gt;

&lt;p&gt;...and then specify the &amp;quot;Default&amp;quot; setting:&lt;/p&gt;

&lt;pre class="brush: plain; gutter: false; toolbar: false; auto-links: false;"&gt;msbuild Example.sln&lt;/pre&gt;

&lt;p&gt;The Output folder now contains the following files:&lt;/p&gt;

&lt;pre class="brush: plain; gutter: false; toolbar: false; auto-links: false;"&gt;CodeAnalysisExperiment1.dll 
CodeAnalysisExperiment1.dll.CodeAnalysisLog.xml 
CodeAnalysisExperiment1.dll.lastcodeanalysissucceeded 
CodeAnalysisExperiment1.pdb 
CodeAnalysisExperiment2.dll 
CodeAnalysisExperiment2.pdb&lt;/pre&gt;

&lt;p&gt;From this we can infer that the &amp;quot;Default&amp;quot; setting looks to the project settings to determine if analysis should be done, whereas the &amp;quot;Always&amp;quot; setting will override the analysis and &amp;quot;Never&amp;quot; will disable analysis altogether.&lt;/p&gt;

&lt;p&gt;For my purposes, I have some projects (unit tests, etc) that I don't necessarily want to run code analysis on -- for me, &amp;quot;Always&amp;quot; is a bit of a deal breaker.&amp;#160; However, there's an interesting lesson to take away here: command line arguments passed to msbuild are carried to all targets.&amp;#160; Which means we can override most project settings this way:&lt;/p&gt;

&lt;pre class="brush: plain; gutter: false; toolbar: false; auto-links: false;"&gt;// use 'all rules' for projects that have analysis turned on 
msbuild.exe Example.sln /p:CodeAnalysisRuleSet=&amp;quot;Allrules.set&amp;quot;

// use a custom dictionary during code analysis 
msbulid.exe Example.sln /p:CodeAnalysisDictionary=&amp;quot;..\AnalysisDictionary.xml&amp;quot;

// redirect output to a different folder 
msbulid.exe Example.sln /p:OutputPath=&amp;quot;..\Output2&amp;quot;&lt;/pre&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

&lt;p&gt;Happy Coding.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8942599-3168981116451467629?l=www.bryancook.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/-N-wzOpbVkAGMZuZxMf13ceVASk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/-N-wzOpbVkAGMZuZxMf13ceVASk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/-N-wzOpbVkAGMZuZxMf13ceVASk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/-N-wzOpbVkAGMZuZxMf13ceVASk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=anxyPIj-6eI:ngReBaS3UI0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=anxyPIj-6eI:ngReBaS3UI0:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=anxyPIj-6eI:ngReBaS3UI0:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=anxyPIj-6eI:ngReBaS3UI0:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?i=anxyPIj-6eI:ngReBaS3UI0:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bryanbcook/~4/anxyPIj-6eI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.bryancook.net/feeds/3168981116451467629/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8942599&amp;postID=3168981116451467629" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/3168981116451467629?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/3168981116451467629?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/bryanbcook/~3/anxyPIj-6eI/build-server-code-analysis-settings.html" title="Build Server Code Analysis Settings" /><author><name>bryan</name><uri>http://www.blogger.com/profile/01332614158223702009</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh3.ggpht.com/-I5Xtnqzudfg/TglTSz0-dBI/AAAAAAAAAf0/Ag6xfBMuqyM/s72-c/DefaultRuleset_thumb%25255B1%25255D.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.bryancook.net/2011/06/build-server-code-analysis-settings.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CU4ERnkzfSp7ImA9WhZaEkU.&quot;"><id>tag:blogger.com,1999:blog-8942599.post-1011146613630934884</id><published>2011-06-28T08:59:00.000-04:00</published><updated>2011-06-28T13:58:27.785-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-28T13:58:27.785-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="FxCop" /><category scheme="http://www.blogger.com/atom/ns#" term=".net" /><title>The Mystery of Cascading FxCop Errors</title><content type="html">&lt;p&gt;As I mentioned in &lt;a href="http://www.bryancook.net/2011/06/visual-studio-code-analysis-settings.html" target="_blank"&gt;my last post&lt;/a&gt;, I've been working through FxCop concerns on my current project. To provide some context, this is a large project with more than 500K lines of code, and FxCop was added late to the development process. Naturally, out of the gate there were thousands of errors, so we had to ease it into the development process by slowly turning on rules until we had the warnings under control.&lt;/p&gt;  &lt;p&gt;To facilitate this, we had a dedicated team go through the entire code base and address as many of the errors as they could: implementing IDispose correctly, validating arguments, etc. In the end, we had a hand picked set of rules that applied to our scenarios and a code base that adhered to them. Once the existing violations were under control, we flipped the switch to treat new analysis warnings as errors to ensure that the violations were not introduced into source control.&lt;/p&gt;  &lt;p&gt;There were some bumps along the way, but in the end it was manageable (royal pain in the butt, but manageable).&lt;/p&gt;  &lt;p&gt;Recently however, my team started to see serious problems with code analysis throughout parts of the application. They found that if they made a minor change, a series of FxCop violations would appear -- even in areas that they didn't touch or had previously been reviewed and considered &amp;quot;warning free&amp;quot;. The team believed that FxCop was somehow incrementally analyzing files, thereby finding new problems which had previously been skipped. While this theory fit into the symptom of new violations for existing code, it just didn't seem right: FxCop analyzes compiled assemblies, not individual files.&lt;/p&gt;  &lt;p&gt;The problem with code analysis errors is that they're not always obvious what is causing the problem. It's easy to fall into a trap to believe that Code Analysis is only looking at the internal structure or logic of a class for correctness. There are many FxCop rules that look for correctness, such as Methods that can be private or static, arguments that can be null, etc. The really obscure errors are the ones that look at how a class is used by other classes. What may seem like a trivial change can introduce a different execution path that suddenly exposes the class and its dependencies for consideration of new FxCop violations.&lt;/p&gt;  &lt;p&gt;Let's take a look at a contrived example. Let's say I'm using a Service Locator to wire up a ViewModel and like any good Inversion of Control junkie, I'm using an interface for that ViewModel. According to FxCop, the following example is good and life is fine.&lt;/p&gt;  &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;public class CustomApp : Application 
{ 
    public override void OnStartup() 
    { 
        var view = new MainView(); 
        view.DataContext = new MainViewModel(); 
        view.Show(); 
    } 
}

internal class MainViewModel 
{ 
    public ISearchViewModel SearchViewModel { get; set;}

    public MainViewModel() 
    { 
        SearchViewModel = ServiceLocator.Get&amp;lt;ISearchViewModel&amp;gt;(); 
    } 
}&lt;/pre&gt;

&lt;p&gt;As smart developers, we decide that we don't really need the ServiceLocator to get our SearchViewModel. The concrete SearchViewModel doesn't have any complex construction logic and we probably will never swap it out with a different instance at runtime -- this is a little hit against dependency inversion but from a testing perspective, I can always introduce a Mock through property injection. Upon introducing this change we discover several new FxCop violations that weren't present before -- nearly a dozen warnings in unrelated classes about objects not being properly disposed. Out of all the warnings, only one warning is specific to the change we've made in this class but it doesn't seem obvious: &lt;a href="http://msdn.microsoft.com/en-us/library/ms182289(v=VS.100).aspx" target="_blank"&gt;CA2000: Dispose objects before losing scope&lt;/a&gt;.&lt;/p&gt;

&lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;public class MainViewModel 
{ 
    public ISearchViewModel SearchViewModel { get; set;}

    public MainViewModel() 
    { 
        // FxCop: CA2000 - Dispose object before losing scope
        SearchViewModel = new PrimarySearchViewModel();
    } 
}&lt;/pre&gt;

&lt;p&gt;This violation takes a few minutes to sort out because we're assigning the object to a property, and it isn't going out of scope. Upon further inpsection, it seems that the concrete class implements IDisposable, but the interface does not. FxCop is warning us that once the constructor goes out of scope, our concrete class will become polymorphically assigned to an interface that doesn't support IDispose and as such, we won't have an opportunity to call the Dispose method on the concrete class. Clever girl.&lt;/p&gt;

&lt;p&gt;The easy fix is to add IDispose onto the interface and then implement the dispose pattern for the MainViewModel. All of this makes sense, and we've just fixed a memory leak that was there all along. But why did we have violations in all these other classes?&lt;/p&gt;

&lt;p&gt;It turns out that PrimarySearchViewModel implemented IDispose improperly and it also constructed several other IDisposable types with the same problem in its constructor. These violations, like the PrimarySearchViewModel one, are legitimate. Now, if you're following along, you'll realize I haven't answered the question. If all these classes implemented IDispose improperly, why weren't these found earlier?&lt;/p&gt;

&lt;p&gt;The answer is because we changed the usage. No one was calling the constructor previously -- the ServiceLocator used reflection to hunt down and construct our object for us, but by switching to use the constructor directly the analysis engine did it's part to highlight problems. It's hard to say whether the analysis engine should have caught this potential problem or if it's a feature that only inspects currently active code. At any rate, I hope this help you or your team -- before dismissing FxCop violations as fluke, look at how the usage of your objects has changed.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8942599-1011146613630934884?l=www.bryancook.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/wbOTOqZAb8tNk4Fv08TZ0ldjVd4/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/wbOTOqZAb8tNk4Fv08TZ0ldjVd4/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/wbOTOqZAb8tNk4Fv08TZ0ldjVd4/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/wbOTOqZAb8tNk4Fv08TZ0ldjVd4/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=0FEEyrCX9FE:9EoPcfXheRA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=0FEEyrCX9FE:9EoPcfXheRA:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=0FEEyrCX9FE:9EoPcfXheRA:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=0FEEyrCX9FE:9EoPcfXheRA:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?i=0FEEyrCX9FE:9EoPcfXheRA:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bryanbcook/~4/0FEEyrCX9FE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.bryancook.net/feeds/1011146613630934884/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8942599&amp;postID=1011146613630934884" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/1011146613630934884?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/1011146613630934884?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/bryanbcook/~3/0FEEyrCX9FE/mystery-of-cascading-fxcop-errors.html" title="The Mystery of Cascading FxCop Errors" /><author><name>bryan</name><uri>http://www.blogger.com/profile/01332614158223702009</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.bryancook.net/2011/06/mystery-of-cascading-fxcop-errors.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0QEQX0zfip7ImA9WhZaEUo.&quot;"><id>tag:blogger.com,1999:blog-8942599.post-2961924593987307439</id><published>2011-06-27T08:55:00.000-04:00</published><updated>2011-06-27T08:55:00.386-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-27T08:55:00.386-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="FxCop" /><category scheme="http://www.blogger.com/atom/ns#" term=".net" /><category scheme="http://www.blogger.com/atom/ns#" term="Visual Studio" /><title>Visual Studio Code Analysis Settings</title><content type="html">&lt;p&gt;I've just &lt;a href="http://twitter.com/#!/bcook/status/83903911169241088" target="_blank"&gt;spent the last week or so&lt;/a&gt; working with Code Analysis for my Visual Studio 2010 projects.&amp;#160; I still haven't figured out if I'm using Visual Studio's built in &lt;a href="http://blogs.msdn.com/b/codeanalysis/archive/2010/03/22/what-s-new-in-code-analysis-for-visual-studio-2010.aspx" target="_blank"&gt;Code Analysis&lt;/a&gt; tool or &lt;a href="http://www.infoq.com/news/2010/06/FXCop-10" target="_blank"&gt;FxCop 10.0&lt;/a&gt;, because the two tools share a lot of the &lt;a href="http://www.itscodingtime.com/post/Visual-Studio-Code-Analysis-vs-FxCop-vs-StyleCope280a6-whats-the-diff.aspx" target="_blank"&gt;same engine and rulesets&lt;/a&gt;.&amp;#160; At any rate, one of the pain points I had to work through was ensuring that the configuration settings between my Visual Studio configurations were the same.&amp;#160; Strangely enough, I had more confidence in my changes when manually editing the csproj files in Notepad++ than from Visual Studio -- it seemed like each configuration had slightly different settings, and being able to see the msbuild settings seemed to make more sense.&lt;/p&gt;  &lt;p&gt;During this process, I found it quite frustrating that none of the CodeAnalysis settings that are configurable from the csproj schema were documented online.&amp;#160; However, the intellisense for the schema is quite good.&amp;#160; The schema is located at: &lt;em&gt;&amp;lt;Program Files&amp;gt;\Microsoft Visual Studio 10.0\Xml\Schemas\1033\MSBuild\Microsoft.Build.CommonTypes.xsd&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;Most of the settings generated by Visual Studio are often the default values and can be discarded.&lt;/p&gt;  &lt;p&gt;For my reference, here's the documentation, lifted from the schema:&lt;/p&gt;  &lt;table border="0" cellspacing="0" cellpadding="2" width="797"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td class="header" valign="top" width="323"&gt;&lt;strong&gt;Project Element&lt;/strong&gt;&lt;/td&gt;        &lt;td class="header" valign="top" width="472"&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisAdditionalOptions&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Additional options to pass to the Code Analysis command line tool.          &lt;br /&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisApplyLogFileXsl&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Indicates whether to apply the XSL style sheet specified in $(CodeAnalysisLogFileXsl) to the Code Analysis report. This report is specified in $(CodeAnalysisLogFile). The default is false.          &lt;br /&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisConsoleXsl&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Path to the XSL style sheet that will be applied to the Code Analysis console output. The default is an empty string (''), which causes Code Analysis to use its default console output.          &lt;br /&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisCulture&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Culture to use for Code Analysis spelling rules, for example, 'en-US' or 'en-AU'. The default is the current user interface language for Windows.          &lt;br /&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisDependentAssemblyPaths&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Additional reference assembly paths to pass to the Code Analysis command line tool. A fully qualified path to a directory containing reference assemblies to be used by Code Analysis.          &lt;br /&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisDictionary&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Code Analysis custom dictionaries.&amp;#160; Semicolon-separated list of Code Analysis custom dictionaries. Wildcards are allowed.          &lt;br /&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisFailOnMissingRules&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Indicates whether Code Analysis should fail if a rule or rule set is missing. The default is false.          &lt;br /&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisForceOutput&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Indicates whether Code Analysis generates a report file, even when there are no active warnings or errors. The default is true.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisGenerateSuccessFile&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Indicates whether Code Analysis generates a '$(CodeAnalysisInputAssembly).lastcodeanalysissucceeded' file in the output folder when no build-breaking errors occur. The default is true.          &lt;br /&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisIgnoreBuiltInRules&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Indicates whether Code Analysis will ignore the default rule directories when searching for rules. The default is false.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisIgnoreBuiltInRuleSets&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Indicates whether Code Analysis will ignore the default rule set directories when searching for rule sets. The default is false.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisIgnoreInvalidTargets&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Indicates whether Code Analysis should silently fail when analyzing invalid assemblies, such as those without managed code. The default is true.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisIgnoreGeneratedCode&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Indicates whether Code Analysis should fail silently when it analyzes invalid assemblies, such as those without managed code. The default is true.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisImport&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Code Analysis projects (*.fxcop) or reports to import. Semicolon-separated list of Code Analysis projects (*.fxcop) or reports to import. Wildcards are allowed.          &lt;br /&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisInputAssembly&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Path to the assembly to be analyzed by Code Analysis. The default is '$(OutDir)$(TargetName)$(TargetExt)'.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisLogFile&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Path to the output file for the Code Analysis report. The default is '$(CodeAnalysisInputAssembly).CodeAnalysisLog.xml'.          &lt;br /&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisLogFileXsl&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Path to the XSL style sheet to reference in the Code Analysis output report. This report is specified in $(CodeAnalysisLogFile). The default is an empty string ('').&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisModuleSuppressionsFile&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Name of the file, without the path, where Code Analysis project-level suppressions are stored. The default is 'GlobalSuppressions$(DefaultLanguageSourceExtension)'.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisOverrideRuleVisibilities&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Indicates whether to run all overridable Code Analysis rules against all targets. This will cause specific rules, such as those within the Design and Naming categories, to run against both public and internal APIs, instead of only public APIs. The default is false.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisOutputToConsole&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Indicates whether to output Code Analysis warnings and errors to the console. The default is false.          &lt;br /&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisVerbose&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Indicates whether to output verbose Code Analysis diagnostic info to the console. The default is false.          &lt;br /&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisPath&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Path to the Code Analysis installation folder. The default is '$(VSINSTALLDIR)\Team Tools\Static Analysis Tools\FxCop'.          &lt;br /&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisPlatformPath&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Path to the .NET Framework folder that contains platform assemblies, such as mscorlib.dll and System.dll. The default is an empty string ('').          &lt;br /&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisProject&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Path to the Code Analysis project (*.fxcop) to load. The default is an empty string ('').          &lt;br /&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisQuiet&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Indicates whether to suppress all Code Analysis console output other than errors and warnings. This applies when $(CodeAnalysisOutputToConsole) is true. The default is false.          &lt;br /&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisRuleAssemblies&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Semicolon-separated list of paths either to Code Analysis rule assemblies or to folders that contain Code Analysis rule assemblies. The paths are in the form '[+|-][!][file|folder]', where '+' enables all rules in rule assembly, '-' disables all rules in rule assembly, and '!' causes all rules in rule assembly to be treated as errors. For example '+D:\Projects\Rules\NamingRules.dll;+!D:\Projects\Rules\SecurityRules.dll'. The default is '$(CodeAnalysisPath)\Rules'.          &lt;br /&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisRuleDirectories&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Semicolon-separated list of directories in which to search for rules when resolving a rule set. The default is '$(CodeAnalysisPath)\Rules' unless the CodeAnalysisIgnoreBuiltInRules property is set to true.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisRules&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Semicolon-separated list of Code Analysis rules. The rules are in the form '[+|-][!]Category#CheckId', where '+' enables the rule, '-' disables the rule, and '!' causes the rule to be treated as an error. For example, '-Microsoft.Naming#CA1700;+!Microsoft.Naming#CA1701'. The default is an empty string ('') which enables all rules.          &lt;br /&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisRuleSet&lt;/td&gt;        &lt;td valign="top" width="472"&gt;A .ruleset file which contains a list of rules to run during analysis. The string can be a full path, a path relative to the project file, or a file name. If a file name is specified, the CodeAnalysisRuleSetDirectories property will be searched to find the file. The default is an empty string ('').&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisRuleSetDirectories&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Semicolon-separated list of directories in which to search for rule sets. The default is '$(VSINSTALLDIR)\Team Tools\Static Analysis Tools\Rule Sets' unless the CodeAnalysisIgnoreBuiltInRuleSets property is set to true.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisSaveMessagesToReport&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Comma-separated list of the type ('Active', 'Excluded', or 'Absent') of warnings and errors to save to the output report file. The default is 'Active'.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisSearchGlobalAssemblyCache&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Indicates whether Code Analysis should search the Global Assembly Cache (GAC) for missing references that are encountered during analysis. The default is true.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisSummary&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Indicates whether to output a Code Analysis summary to the console after analysis. The default is false.          &lt;br /&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisTimeout&lt;/td&gt;        &lt;td valign="top" width="472"&gt;The time, in seconds, that Code Analysis should wait for analysis of a single item to complete before it aborts analysis. Specify 0 to cause Code Analysis to wait indefinitely. The default is 120.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisTreatWarningsAsErrors&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Indicates whether to treat all Code Analysis warnings as errors. The default is false.          &lt;br /&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisUpdateProject&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Indicates whether to update the Code Analysis project (*.fxcop) specified in $(CodeAnalysisProject). This applies when there are changes during analysis. The default is false.          &lt;br /&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;CodeAnalysisUseTypeNameInSuppression&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Indicates whether to include the name of the rule when Code Analysis emits a suppression. The default is true.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="323"&gt;RunCodeAnalysis&lt;/td&gt;        &lt;td valign="top" width="472"&gt;Indicates whether to run Code Analysis during the build.&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;As this has been a fun week dealing with FxCop, expect to see a few more posts related to the above settings.&amp;#160; Stay right here and click refresh endlessly, or subscribe to the rss feed.&lt;/p&gt;  &lt;p&gt;Happy coding.   &lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8942599-2961924593987307439?l=www.bryancook.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/wpaMpKAkQuM9yyPVjW-op3XynJM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/wpaMpKAkQuM9yyPVjW-op3XynJM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/wpaMpKAkQuM9yyPVjW-op3XynJM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/wpaMpKAkQuM9yyPVjW-op3XynJM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=NRleJ0ORFGA:tWDHDkGtRj8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=NRleJ0ORFGA:tWDHDkGtRj8:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=NRleJ0ORFGA:tWDHDkGtRj8:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=NRleJ0ORFGA:tWDHDkGtRj8:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?i=NRleJ0ORFGA:tWDHDkGtRj8:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bryanbcook/~4/NRleJ0ORFGA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.bryancook.net/feeds/2961924593987307439/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8942599&amp;postID=2961924593987307439" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/2961924593987307439?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/2961924593987307439?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/bryanbcook/~3/NRleJ0ORFGA/visual-studio-code-analysis-settings.html" title="Visual Studio Code Analysis Settings" /><author><name>bryan</name><uri>http://www.blogger.com/profile/01332614158223702009</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.bryancook.net/2011/06/visual-studio-code-analysis-settings.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUMARnc-fCp7ImA9WhZVGEQ.&quot;"><id>tag:blogger.com,1999:blog-8942599.post-3791678162648365702</id><published>2011-05-31T23:04:00.001-04:00</published><updated>2011-05-31T23:04:07.954-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-31T23:04:07.954-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".net" /><category scheme="http://www.blogger.com/atom/ns#" term="Visual Studio" /><category scheme="http://www.blogger.com/atom/ns#" term="TDD" /><title>The Tests are Broken, Now What?</title><content type="html">&lt;p&gt;Despite our best intentions to write durable tests, it seems inevitable that tests will break at some point. In some cases, breaking a test can be seen as a very positive thing: we've introduced a side-effect that has broken existing functionality, and our tests have helped prevent a bug. However, in some cases, tests break because of external factors -- maybe the tests weren't isolated enough, maybe a developer went rogue and forgot to run the tests, or some other poorly justified or lousy excuse. While identifying what went wrong in your development process is important, the immediate concern is that these broken tests represent a failed build and developer productivity is at risk -- what should you do with the broken tests?&lt;/p&gt;  &lt;p&gt;If the developer looking at the tests knows a bit about the code, they should have enough information in the tests to help sort things out.&amp;#160; The developer should drop what they're doing, slow down and research the code and the tests and fix the broken tests. If caught early, it's very manageable. Unfortunately, this isn't the common case -- the developer introducing the breaking changes doesn't understand the tests and is ultimately left with one of two approaches:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Comment out or remove the test &lt;/li&gt;    &lt;li&gt;Mark the test as Ignored &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&lt;strong&gt;Neither of these approaches &amp;quot;&lt;em&gt;fix&lt;/em&gt;&amp;quot; anything&lt;/strong&gt;.&amp;#160; The first approach, to comment the test out, is equivalent to pissing on the requirements. The test supposedly represents a piece of functional behaviour of the application, the fact that it's broken suggests a feature is also broken. The only reason to comment out a test is if that functionality has ceased to exist or the test was invalid in the first place. (Take a look at my checklist for unit test code reviews to help qualify invalid tests)&lt;/p&gt;  &lt;p&gt;The second alternative to mark the tests as &lt;em&gt;Ignored&lt;/em&gt; can be dangerous, depending on whether you're able to track why the test has been disabled and able to monitor when it enters this state.&amp;#160; This is one part developer process, one part testing framework, one part reporting.&lt;/p&gt;  &lt;p&gt;Within NUnit, the Ignore attribute fits the bill nicely.&amp;#160; The attribute accepts a string message which is used to report why the test has been disabled. It should be standard developer process to only allow use of Ignore if a message is provided. (Come to think of it, I should put in a feature request so that it is required.)&amp;#160; When NUnit runs, the Ignored tests are not executed but the number of ignored tests are included in the xml output, meaning that your build server can track ignored tests over time. You can also bypass the Ignored attribute within the NUnit user-interface by simply selecting the Ignored test and running it manually.&lt;/p&gt;  &lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;[Ignore(&amp;quot;The xml for this test isn't serializing correctly. Please fix!&amp;quot;)]
[Test]
public void SuperImportantTest()
{
    // snip
}&lt;/pre&gt;

&lt;p&gt;Within MSTest however, &lt;em&gt;Ignore&lt;/em&gt; is essentially the same as commenting out the tests.&amp;#160; There's no ability to record why the test has been excluded (developers must leave comments), and when MSTest runs the test suite the Ignored tests are simply excluded from the test run.&amp;#160; Looking at the MSTest output, the TRX file does not define a status for ignored, meaning that it can't be tracked in your build reports. &lt;/p&gt;

&lt;pre class="brush: xml; gutter: false; toolbar: false; auto-links: false;"&gt;&amp;lt;ResultSummary outcome=&amp;quot;Completed&amp;quot;&amp;gt;
  &amp;lt;Counters 
    total=&amp;quot;1&amp;quot; 
    executed=&amp;quot;1&amp;quot; 
    passed=&amp;quot;1&amp;quot; 
    error=&amp;quot;0&amp;quot; 
    failed=&amp;quot;0&amp;quot; 
    timeout=&amp;quot;0&amp;quot; 
    aborted=&amp;quot;0&amp;quot; 
    inconclusive=&amp;quot;0&amp;quot; 
    passedButRunAborted=&amp;quot;0&amp;quot; 
    notRunnable=&amp;quot;0&amp;quot; 
    notExecuted=&amp;quot;0&amp;quot; 
    disconnected=&amp;quot;0&amp;quot; 
    warning=&amp;quot;0&amp;quot; 
    completed=&amp;quot;0&amp;quot; 
    inProgress=&amp;quot;0&amp;quot; 
    pending=&amp;quot;0&amp;quot; /&amp;gt;
&amp;lt;/ResultSummary&amp;gt;&lt;/pre&gt;

&lt;p&gt;Though I'm not a big fan of this, I'll spare you the complaining and move on to working solutions.&lt;/p&gt;

&lt;p&gt;The best approach within MSTest isn't to disable the test but to indicate that it isn't reliable and needs attention. In addition, we need these tests to stand out without breaking the build. This is exactly what Inconclusive is for.&lt;/p&gt;

&lt;pre class="brush: csharp; gutter: false; toolbar: false; auto-links: false;"&gt;[TestMethod] 
public void SuperImportantTest() 
{ 
    Assert.Inconclusive(&amp;quot;The xml for this test isn't serializing correctly. Please fix!&amp;quot;); 
    
    // snip 
}&lt;/pre&gt;

&lt;p&gt;The key to using &lt;em&gt;Assert.Inconclusive&lt;/em&gt; is to put the statement as the first code-expression in your test. When MSTest encounters the &lt;em&gt;Assert.Inconclusive&lt;/em&gt; statement, execution of the test is immediately halted, and the test is recorded as &amp;quot;Inconclusive&amp;quot;. The TRX reports this status separately, and the message appears in the xml output.&lt;/p&gt;

&lt;h3&gt;Next Steps&lt;/h3&gt;

&lt;p&gt;With the tests marked as problematic, it’s possible to check-in the tests and unblock developers from a failed build while you and the original test author figure out how to fix the problem. It’s a temporary patch and is not intended for all breaking tests, just small fires that happen during critical developer crunches.&amp;#160; Once the fire has been put out and the tests corrected, you really should go back and investigate why the test broke in the first place:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Should the developer’s changes have broken this test?&amp;#160; If not, could the code/test have been written differently to be more durable? &lt;/li&gt;

  &lt;li&gt;What could the developer have done differently? Is this a one time occurrence or a disconnect in process?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s all for now.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8942599-3791678162648365702?l=www.bryancook.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/N073FC-n9Rg8eJDn9gnj7JhTTxo/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/N073FC-n9Rg8eJDn9gnj7JhTTxo/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/N073FC-n9Rg8eJDn9gnj7JhTTxo/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/N073FC-n9Rg8eJDn9gnj7JhTTxo/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=dOGVHDXxP8o:y4psqscxZkk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=dOGVHDXxP8o:y4psqscxZkk:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=dOGVHDXxP8o:y4psqscxZkk:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=dOGVHDXxP8o:y4psqscxZkk:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?i=dOGVHDXxP8o:y4psqscxZkk:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bryanbcook/~4/dOGVHDXxP8o" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.bryancook.net/feeds/3791678162648365702/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8942599&amp;postID=3791678162648365702" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/3791678162648365702?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/3791678162648365702?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/bryanbcook/~3/dOGVHDXxP8o/tests-are-broken-now-what.html" title="The Tests are Broken, Now What?" /><author><name>bryan</name><uri>http://www.blogger.com/profile/01332614158223702009</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.bryancook.net/2011/05/tests-are-broken-now-what.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0cCSX06eCp7ImA9WhZQEUk.&quot;"><id>tag:blogger.com,1999:blog-8942599.post-5732310887291065735</id><published>2011-04-18T08:58:00.000-04:00</published><updated>2011-04-18T11:37:48.310-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-18T11:37:48.310-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".net" /><category scheme="http://www.blogger.com/atom/ns#" term="AOP" /><category scheme="http://www.blogger.com/atom/ns#" term="TDD" /><title>Testing Asynchronous Logic</title><content type="html">&lt;p&gt;I've been doing a fair bit of asynchronous logic recently where I'm designing objects to raise events after long-running operations have completed, and naturally this creates a few challenges during testing. When a method uses the asynchronous pattern, the work is executed on a separate thread and execution returns immediately to the caller. This is a problem for the a unit test as they are by design a series of standalone sequential steps -- the test may finish or execute assertions before the event is called.&lt;/p&gt;  &lt;p&gt;The immediate workaround is to add delays into the tests using a &lt;em&gt;&lt;em&gt;Thread.Sleep&lt;/em&gt; &lt;/em&gt;statement.&lt;/p&gt;  &lt;pre class="brush: csharp; gutter: false; auto-links: false;"&gt;[Test]
public void AsynchronousTestsDontAlwaysWork()
{
    bool eventCalled = false;
    
    var subject = new MyClass();
    subject.OnComplete += (o,e) =&amp;gt; eventCalled = true;
    
    subject.DoWorkAsync();
    
    Thread.Sleep(100);
    
    Assert.AreTrue( eventCalled ); // can fail because the event might raise after this assertion
}&lt;/pre&gt;

&lt;p&gt;This strategy will work, but it's dangerous in the long-term because the duration of the asynchronous operation is dependent on the complexity of the implementation and the environment the test is executing in.&amp;#160; In other words, you may need to increase sleep interval if the implementation needs to do more work or if the tests fail on slower machines. In the end, the sleep interval reflects the lowest common denominator in your environment (that slow laptop that intern uses) and the entire test run becomes painfully (and unnecessarily) slow.&lt;/p&gt;

&lt;p&gt;The solution is to add a little extra plumbing to block execution until the event is fired.&lt;/p&gt;

&lt;pre class="brush: csharp; gutter: false; auto-links: false;"&gt;[Test]
public void AsynchronousTestWithBlockingAlwaysWorks()
{
    var reset = new System.Threading.ManualResetEvent(false);
    
    var subject = new MyClass();
    subject.OnComplete += (o,e) =&amp;gt; reset.Set();
    
    subject.DoWorkAsync();
    
    if (!reset.WaitOne(1000)) // block for at most 1 second
    {
        Assert.Fail(&amp;quot;The test timed out waiting for the OnComplete event.&amp;quot;);
    }
}&lt;/pre&gt;

&lt;p&gt;The above example uses the &lt;em&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/system.threading.manualresetevent.aspx" target="_blank"&gt;ManualResetEvent&lt;/a&gt;&lt;/em&gt;, which in short is a signalling mechanism. The &lt;em&gt;WaitOne&lt;/em&gt; method blocks execution until another thread calls the &lt;em&gt;Set&lt;/em&gt; method or the timeout value is exceeded. In the above example, I've set up an anonymous delegate for my event so that the test finishes as soon as the asynchronous logic completes.&lt;/p&gt;

&lt;h3&gt;Cleaning it up...&lt;/h3&gt;

&lt;p&gt;As I mentioned earlier, I've been doing a lot of this type of testing so the above pattern has appeared in more than one test. It would be nice to encapsulate this a bit and streamline it into a reusable utility. &lt;a href="http://stackoverflow.com/questions/35211/identify-an-event-via-a-linq-expression-tree" target="_blank"&gt;This post on StackOverflow&lt;/a&gt; had an interesting concept to wrap the blocking logic into an object that supports &lt;em&gt;IDisposable&lt;/em&gt;. The original poster was attempting to use Expressions to access events, which sadly isn't possible from outside the class, but here's an updated example that uses reflection and a named parameter for the event:&lt;/p&gt;

&lt;pre class="brush: csharp; auto-links: false;"&gt;public sealed class EventWatcher : IDisposable
{
    private readonly object _target;
    private readonly EventInfo _eventInfo;
    private readonly Delegate _listener;
    private readonly ManualResetEvent _reset;
    private readonly int _timeout;

    public static EventWatcher Create&amp;lt;T&amp;gt;(T target, string eventName, int timeout = 1000)
    {
        EventInfo eventInfo = typeof (T).GetEvent(eventName);
        if (eventInfo == null)
            throw new ArgumentException(&amp;quot;Event not found.&amp;quot;, &amp;quot;eventName&amp;quot;);

        return new EventWatcher(target, eventInfo, timeout);
    }

    private EventWatcher(object target, EventInfo eventInfo, int timeout)
    {
        _target = target;
        _eventInfo = eventInfo;
        _timeout = timeout;

        _reset = new ManualResetEvent(false);

        // Create our event listener
        _listener = CreateEventListenerDelegate(eventInfo.EventHandlerType);

        _eventInfo.AddEventHandler(target, _listener);
    }

    public void SetEventWasRaised()
    {
        _reset.Set();
    }

    private Delegate CreateEventListenerDelegate(Type eventType)
    {
        // Create the event listener's body, setting the 'eventWasRaised_' field.
        var setMethod = typeof(EventWatcher).GetMethod(&amp;quot;SetEventWasRaised&amp;quot;);
        var body = Expression.Call(Expression.Constant(this), setMethod);

        // Get the event delegate's parameters from its 'Invoke' method.
        MethodInfo invokeMethod = eventType.GetMethod(&amp;quot;Invoke&amp;quot;);
        var parameters = invokeMethod.GetParameters()
            .Select((p) =&amp;gt; Expression.Parameter(p.ParameterType, p.Name));

        // Create the listener.
        var listener = Expression.Lambda(eventType, body, parameters);
        return listener.Compile();
    }

    public void Dispose()
    {
        bool eventWasFired = _reset.WaitOne(_timeout);
        // Remove the event listener.
        _eventInfo.RemoveEventHandler(_target,_listener);

        if (!eventWasFired)
        {
            string message = String.Format(&amp;quot;Test timed-out waiting for event \&amp;quot;{0}\&amp;quot; to be raised.&amp;quot;, _eventInfo.Name);
            Assert.Fail(message);
        }
    }
}

[Test]
public void DemonstrateEventWatcherWithUsingBlockAndDisposePattern()
{
    var subject = new MyClass();
    
    using(EventWatcher.Create(subject, &amp;quot;OnComplete&amp;quot;))
    {
        subject.DoWorkAsync();
        
    } // throws Assert.Fail() if event wasn't called.
}&lt;/pre&gt;

&lt;h3&gt;Some Refinements...&lt;/h3&gt;

&lt;p&gt;This solution works, but there are a few drawbacks:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The using block is a very succinct mechanism for controlling scope, but unfortunately if an exception occurs in the body of the using statement it will get swallowed by the exception in our EventWatcher's Dispose method. &lt;/li&gt;

  &lt;li&gt;This only validates that the event was called, and it doesn't give us access to the event argument, which might be of interest to the test. &lt;/li&gt;

  &lt;li&gt;The event name is a literal string value which isn't very refactor friendly. &lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;Preventing Hidden Exceptions from the Finally block&lt;/h4&gt;

&lt;p&gt;To address the first problem where exceptions aren't properly handled inside the using statement, we change the signature slightly to perform the test logic in an Action.&lt;/p&gt;

&lt;pre class="brush: csharp; auto-links: false;"&gt;// snip...
public static void WaitForEvent&amp;lt;T&amp;gt;(T target, string eventName, Action action) 
{ 
    var watcher = Create(target, eventName);

    try 
    { 
        action(); 
    } 
    catch (Exception) 
    { 
        watcher.Clear(); 
        throw; 
    } 
    finally 
    { 
        watcher.Dispose(); 
    } 
}
// ...end snip

[Test] 
public void DemonstrateEventWatcherWithAnActionInsteadOfUsingBlock() 
{ 
    EventWatcher.WaitForEvent(subject, &amp;quot;OnComplete&amp;quot;, () =&amp;gt; subject.DoWorkAsync()); 
}&lt;/pre&gt;

&lt;h4&gt;Gaining Access to the EventArgs&lt;/h4&gt;

&lt;p&gt;Addressing the second problem requires some changes to the CreateEventListenerDelegate so that the arguments of the event are recorded.&lt;/p&gt;

&lt;pre class="brush: csharp; auto-links: false;highlight: [2, 19]"&gt;//snip
public void SetEventWasRaised(EventArgs e) 
{ 
    EventArg = e; 
    _reset.Set(); 
}

public EventArgs EventArg { get; private set; }

private Delegate CreateEventListenerDelegate(Type eventType) 
{ 
    // Get the event delegate's parameters from its 'Invoke' method. 
    MethodInfo invokeMethod = eventType.GetMethod(&amp;quot;Invoke&amp;quot;); 
    var parameters = invokeMethod.GetParameters() 
        .Select((p) =&amp;gt; Expression.Parameter(p.ParameterType, p.Name)).ToList();

    // Setup the callback to pass in the EventArgs 
    var setMethod = typeof(EventWatcher).GetMethod(&amp;quot;SetEventWasRaised&amp;quot;); 
    var body = Expression.Call(Expression.Constant(this), setMethod, parameters[1]);

    // Create the listener. 
    var listener = Expression.Lambda(eventType, body, parameters); 
    return listener.Compile(); 
} // end snip

[Test] 
public void DemonstrateEventWatcherCanCaptureEventArgs() 
{ 
    EventArgs e; 
    EventWatcher.WaitForEvent(subject, &amp;quot;OnComplete&amp;quot;, out e, t =&amp;gt; t.DoWorkAsync()); 
    
    Assert.IsNotNull(e); 
} &lt;/pre&gt;

&lt;h4&gt;Making it Refactor-Friendly...&lt;/h4&gt;

&lt;p&gt;Tackling the last problem where we don't have type-safety for our event, we need a special workaround because we're unable to use an Expression to capture our event. From a language perspective, C# will only allow external callers to add or remove event handler assignments, so we can't write a lamda expression that points to an event reference. Hopefully this is something that will be added to the language in a future version, but until then accessing the event requires some special hackery.&lt;/p&gt;

&lt;p&gt;Taking a play from the &lt;a href="http://code.google.com/p/moq/source/browse/trunk/Source/Extensions.cs" target="_blank"&gt;Moq source code&lt;/a&gt;, we can infer the event name by using a dynamic proxy and intercepting the method invocation when we perform an event assignment. It's a long and awkward way around, but it works, albeit it comes with all the caveats of using a dynamic proxy: non-sealed classes with virtual events, &lt;em&gt;MarshalByRefObject&lt;/em&gt;, or interfaces.&lt;/p&gt;

&lt;p&gt;A note about virtual events: I’m personally not a big fan of virtual events (Resharper warnings, etc), but if you’re comfortable putting the event declarations on an interface, you can explicitly specify the interface in the generic type argument.&amp;#160; &lt;em&gt;EventWatcher.Create&amp;lt;IMyInterface&amp;gt;(…)&lt;/em&gt;&lt;/p&gt;

&lt;pre class="brush: csharp; auto-links: false;"&gt;public class EventAssignmentInterceptor : Castle.DynamicProxy.IInterceptor
{
    private Castle.DynamicProxy.IInvocation _lastInvocation;

    #region IInterceptor implementation

    public void Intercept(IInvocation invocation)
    {
        _lastInvocation = invocation;
    }

    #endregion

    public string GetEventName()
    {
        string methodName = _lastInvocation.Method.Name;
        return methodName.Replace(&amp;quot;add_&amp;quot;, &amp;quot;&amp;quot;).Replace(&amp;quot;remove_&amp;quot;, &amp;quot;&amp;quot;);
    }
}

public class EventHelper
{
    public static string GetEventName&amp;lt;T&amp;gt;(T target, Action&amp;lt;T&amp;gt; action) where T : class
    {
        var generator = new Castle.DynamicProxy.ProxyGenerator();
        var interceptor = new EventAssignmentInterceptor();

        T proxy;

        if (typeof(T).IsInterface)
        {
            proxy = generator.CreateInterfaceProxyWithoutTarget&amp;lt;T&amp;gt;(interceptor);
        }
        else
        {
            proxy = generator.CreateClassProxy&amp;lt;T&amp;gt;(interceptor);
        }

        action(proxy);

        return interceptor.GetEventName();
    }
}&lt;/pre&gt;

&lt;h3&gt;Examples&lt;/h3&gt;

&lt;p&gt;Here’s a few examples that illustrate the various syntax.&amp;#160; Note, for sake a brevity (this post is crazy large) the overloads that define events as literals are not shown.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Basic usage in a using block.&lt;/strong&gt; Note that exceptions inside the using may be swallowed by the dispose, and there's no access to the event args.&lt;/p&gt;

&lt;pre class="brush: csharp; auto-links: false;gutter: false;"&gt;using(EventWatcher.Create(subject, t =&amp;gt; t.OnComplete += null)) 
{ 
    subject.PerformWork(); 
} 

using(EventWatcher.Create(subject, t =&amp;gt; t.OnComplete += null, timeout:1000) 
{ 
    subject.PerformWork(); 
}&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Condensed usage.&lt;/strong&gt; Provides access to the EventArgs and avoids the dispose problem.&lt;/p&gt;

&lt;pre class="brush: csharp; auto-links: false;gutter: false;"&gt;EventArgs e = EventWatcher.Create(subject, t=&amp;gt; t.OnComplete +=null, () =&amp;gt; subject.PerformWork() );

EventArgs e; 
EventWatcher.Create(subject, t=&amp;gt; t.OnComplete += null, out e, ()=&amp;gt; subject.PerformWork() ); &lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Fluent usage&lt;/strong&gt;. A cleaner syntax that declares the event and the action separately.&lt;/p&gt;

&lt;pre class="brush: csharp; auto-links: false;gutter: false;"&gt;EventArgs e = EventWatcher 
            .For(subject, t =&amp;gt; t.OnComplete += null) 
            .WaitOne(() =&amp;gt; subject.PerformWork()) 

EventArgs e; 
EventWatcher.For(subject, t=&amp;gt; t.OnComplete += null) 
            .WaitOne( () =&amp;gt; subject.PerformWork(), out e);&lt;/pre&gt;

&lt;h3&gt;Full Source&lt;/h3&gt;

&lt;p&gt;The full source is here.&lt;/p&gt;

&lt;pre class="brush: csharp; collapse: true; auto-links: false;"&gt;public sealed class EventWatcher : IDisposable
{
    private readonly object _target;
    private readonly EventInfo _eventInfo;
    private readonly Delegate _listener;
    private readonly ManualResetEvent _reset;
    private readonly int _timeout;

    #region Create
    public static EventWatcher Create&amp;lt;T&amp;gt;(T target, string eventName, int timeout = 1000)
    {
        EventInfo eventInfo = typeof(T).GetEvent(eventName);
        if (eventInfo == null)
            throw new ArgumentException(&amp;quot;Event not found.&amp;quot;, &amp;quot;eventName&amp;quot;);

        return new EventWatcher(target, eventInfo, timeout);
    }

    public static EventWatcher Create&amp;lt;T&amp;gt;(T subject, Action&amp;lt;T&amp;gt; eventAssignment, int timeout = 1000) where T : class
    {
        string eventName = EventHelper.GetEventName(subject, eventAssignment);

        return Create(subject, eventName, timeout);
    } 
    #endregion

    #region For
    public static EventWatcherSetup&amp;lt;T&amp;gt; For&amp;lt;T&amp;gt;(T subject, Action&amp;lt;T&amp;gt; eventAssignment) where T : class
    {
        string eventName = EventHelper.GetEventName(subject, eventAssignment);
        return For(subject, eventName);
    }

    public static EventWatcherSetup&amp;lt;T&amp;gt; For&amp;lt;T&amp;gt;(T subject, string eventName)
    {
        return new EventWatcherSetup&amp;lt;T&amp;gt;(subject, eventName);
    } 
    #endregion

    #region WaitForEvent
    public static EventArgs WaitForEvent&amp;lt;T&amp;gt;(T target, Action&amp;lt;T&amp;gt; eventAssignment, Action action) where T : class
    {
        EventArgs e;
        WaitForEvent(target, eventAssignment, out e, action);
        return e;
    }

    public static void WaitForEvent&amp;lt;T&amp;gt;(T target, Action&amp;lt;T&amp;gt; eventAssignment, out EventArgs e, Action action) where T : class
    {
        string eventName = EventHelper.GetEventName(target, eventAssignment);
        WaitForEvent(target, eventName, out e, action);
    }

    public static EventArgs WaitForEvent&amp;lt;T&amp;gt;(T target, string eventName, Action action)
    {
        EventArgs e;
        WaitForEvent(target, eventName, out e, action);
        return e;
    }

    public static void WaitForEvent&amp;lt;T&amp;gt;(T target, string eventName, out EventArgs e, Action action)
    {
        var watcher = Create(target, eventName);

        try
        {
            action();
        }
        catch (Exception)
        {
            watcher.Clear();
            throw;
        }
        finally
        {
            e = watcher.EventArg;
            watcher.Dispose();
        }
    } 
    #endregion

    private EventWatcher(object target, EventInfo eventInfo, int timeout)
    {
        _target = target;
        _eventInfo = eventInfo;
        _timeout = timeout;

        _reset = new ManualResetEvent(false);

        // Create our event listener
        _listener = CreateEventListenerDelegate(eventInfo.EventHandlerType);

        _eventInfo.AddEventHandler(target, _listener);
    }

    public void SetEventWasRaised(EventArgs e)
    {
        EventArg = e;
        _reset.Set();
    }

    public void Clear()
    {
        _reset.Set();
    }

    public EventArgs EventArg { get; private set; }

    private Delegate CreateEventListenerDelegate(Type eventType)
    {
        // Get the event delegate's parameters from its 'Invoke' method.
        MethodInfo invokeMethod = eventType.GetMethod(&amp;quot;Invoke&amp;quot;);
        var parameters = invokeMethod.GetParameters()
            .Select((p) =&amp;gt; Expression.Parameter(p.ParameterType, p.Name)).ToList();

        var setMethod = typeof(EventWatcher).GetMethod(&amp;quot;SetEventWasRaised&amp;quot;);
        var body = Expression.Call(Expression.Constant(this), setMethod, parameters[1]);

        // Create the listener.
        var listener = Expression.Lambda(eventType, body, parameters);
        return listener.Compile();
    }

    public void Dispose()
    {
        bool eventWasFired = _reset.WaitOne(_timeout);
        // Remove the event listener.
        _eventInfo.RemoveEventHandler(_target,_listener);

        if (!eventWasFired)
        {
            string message = String.Format(&amp;quot;Test timed-out waiting for event \&amp;quot;{0}\&amp;quot; to be raised.&amp;quot;, _eventInfo.Name);
            Assert.Fail(message);
        }
    }
}

public class EventWatcherSetup&amp;lt;T&amp;gt;
{
    private readonly T _target;
    private readonly string _eventName;

    public EventWatcherSetup(T target, string eventName)
    {
        _target = target;
        _eventName = eventName;
    }

    public EventArgs WaitOne(Action action)
    {
        EventArgs e;

        WaitOne(action, out e);
        
        return e;
    }
    public void WaitOne(Action action, out EventArgs e)
    {
        EventWatcher.WaitForEvent(_target,_eventName, out e, action);
    }

}

public class EventAssignmentInterceptor : Castle.DynamicProxy.IInterceptor
{
    public Castle.DynamicProxy.IInvocation LastInvocation;

    #region Implementation of IInterceptor

    public void Intercept(IInvocation invocation)
    {
        LastInvocation = invocation;
    }

    #endregion

    public string GetEventName()
    {
        string methodName = LastInvocation.Method.Name;
        return methodName.Replace(&amp;quot;add_&amp;quot;, &amp;quot;&amp;quot;).Replace(&amp;quot;remove_&amp;quot;, &amp;quot;&amp;quot;);
    }
}

public class EventHelper
{
    public static string GetEventName&amp;lt;T&amp;gt;(T target, Action&amp;lt;T&amp;gt; action) where T : class
    {
        var generator = new Castle.DynamicProxy.ProxyGenerator();
        var interceptor = new EventAssignmentInterceptor();

        T proxy;

        if (typeof(T).IsInterface)
        {
            proxy = generator.CreateInterfaceProxyWithoutTarget&amp;lt;T&amp;gt;(interceptor);
        }
        else
        {
            proxy = generator.CreateClassProxy&amp;lt;T&amp;gt;(interceptor);
        }

        action(proxy);

        return interceptor.GetEventName();
    }
}&lt;/pre&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8942599-5732310887291065735?l=www.bryancook.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/WN1fpr4cmQxYXEKkw43EFaI4qwE/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/WN1fpr4cmQxYXEKkw43EFaI4qwE/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/WN1fpr4cmQxYXEKkw43EFaI4qwE/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/WN1fpr4cmQxYXEKkw43EFaI4qwE/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=HSGLrlE_Axo:laNaWFeSDVQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=HSGLrlE_Axo:laNaWFeSDVQ:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=HSGLrlE_Axo:laNaWFeSDVQ:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=HSGLrlE_Axo:laNaWFeSDVQ:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?i=HSGLrlE_Axo:laNaWFeSDVQ:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bryanbcook/~4/HSGLrlE_Axo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.bryancook.net/feeds/5732310887291065735/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8942599&amp;postID=5732310887291065735" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/5732310887291065735?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/5732310887291065735?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/bryanbcook/~3/HSGLrlE_Axo/testing-asynchronous-logic.html" title="Testing Asynchronous Logic" /><author><name>bryan</name><uri>http://www.blogger.com/profile/01332614158223702009</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total><feedburner:origLink>http://www.bryancook.net/2011/04/testing-asynchronous-logic.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0YMSXsycSp7ImA9WhZTFUg.&quot;"><id>tag:blogger.com,1999:blog-8942599.post-5974572363225264567</id><published>2011-03-18T08:58:00.000-04:00</published><updated>2011-03-19T13:19:48.599-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-19T13:19:48.599-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term=".net" /><title>Parsing Nullable Enumerations</title><content type="html">&lt;p&gt;I had an interesting challenge yesterday that involved converting a string to an enumerated value. This seems like it would be really trivial, but I had a few extra considerations that made it harder to deal with.&lt;/p&gt;  &lt;p&gt;We're all familiar with the Enum.Parse method that has existed in the .NET Framework since version 1.1.&amp;#160; It's a somewhat clunky and verbose method:&lt;/p&gt;  &lt;pre class="brush: csharp; gutter: false; auto-links: false;"&gt;MyEnum result = (MyEnum)Enum.Parse(typeof(MyEnum), &amp;quot;First&amp;quot;);&lt;/pre&gt;

&lt;p&gt;Recently, the .NET Framework 4.0 introduced a new static method on the Enum type which uses generics.&amp;#160; It's much cleaner, if you don't mind the out parameters.&lt;/p&gt;

&lt;pre class="brush: csharp; gutter: false; auto-links: false;"&gt;MyEnum result;

if (Enum.TryParse(&amp;quot;First&amp;quot;, out result))
{
    // do something with 'result'
}&lt;/pre&gt;

&lt;p&gt;Unfortunately, the above methods are constrained to work with struct value-types only and won’t work with Nullable types. After some experimenting and fussing with casting between generic types I managed to get a solution that works with both standard and nullable enumerations.&lt;/p&gt;

&lt;p&gt;I’m sure there’s a bit extra boxing in here, so as always your feedback is welcome.&amp;#160; Otherwise, this free-as-in-beer extension method is going on my tool belt.&lt;/p&gt;

&lt;pre class="brush: csharp; gutter: false; auto-links: false;"&gt;public static TResult ConvertToEnum&amp;lt;TResult&amp;gt;(this string source)
{
    // we can't get our values out of a Nullable&lt;t&gt; so we need
    // to get the underlying type
    Type enumType = GetUnderlyingTypeIfNullable(typeof(TResult));
        
    // unfortunatetly, .net 4.0 doesn't have constraints for Enum
    if (!enumType.IsEnum)
        throw new NotSupportedException(&amp;quot;Only enums can be converted here, chum.&amp;quot;);

    if (!String.IsNullOrEmpty(source))
    {        
        object rawValue = GetRawEnumValueFromString(enumType, source);
        
        // if there was a match
        if (rawValue != null)
        {
            // having the value isn't enough, we need to
            // convert this back to an enum so that we can 
            // perform an implicit cast back to the generic type
            object enumValue = Enum.Parse(enumType, rawValue.ToString());
        
            // implicit cast back to generic type
            // if the generic type was nullable, the cast
            // from non-nullable to nullable is also implicit
            return (TResult)enumValue;
        }
    }
    
    // if no original value, or no match use the default value.
    // returns 0 for enum, null for nullable&amp;lt;enum&amp;gt;
    return default(TResult);
}

private static Type GetUnderlyingTypeIfNullable(Type type)
{
    if (type.IsGenericType &amp;amp;&amp;amp; type.GetGenericTypeDefinition() == typeof(Nullable&amp;lt;&amp;gt;))
    {
        // Nullable&amp;lt;T&amp;gt; only has one type argument
        return type.GetGenericArguments().First();
    }
    
    return targetType;
}

private static object GetRawEnumValueFromString(Type enumType, string source)
{
    FieldInfo[] fields = enumType.GetFields(BindingFlags.Public | BindingFlags.Static);

    // attempt to find our string value
    foreach (FieldInfo field in fields)
    {
        object value =  field.GetRawConstantValue();

        // exact match
        if (field.Name == source)
        {
            return value;
        }

        // attempt to locate in attributes
        var attribs = field.GetCustomAttributes(typeof (XmlEnumAttribute), false);
        {
            if (attribs.Cast&amp;lt;XmlEnumAttribute&amp;gt;().Any(attrib =&amp;gt; source == attrib.Name))
            {
                return value;
            }
        }
    }

    return null;
}
&lt;/pre&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;Heh: “Free as in Beer”. Happy St. Patty’s, everybody.&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8942599-5974572363225264567?l=www.bryancook.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/qxlkKghvo4gpj6guNbbwxHfne7E/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/qxlkKghvo4gpj6guNbbwxHfne7E/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/qxlkKghvo4gpj6guNbbwxHfne7E/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/qxlkKghvo4gpj6guNbbwxHfne7E/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=qIcusfgsbBs:9PV1dzQxhR8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=qIcusfgsbBs:9PV1dzQxhR8:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=qIcusfgsbBs:9PV1dzQxhR8:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=qIcusfgsbBs:9PV1dzQxhR8:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?i=qIcusfgsbBs:9PV1dzQxhR8:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bryanbcook/~4/qIcusfgsbBs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.bryancook.net/feeds/5974572363225264567/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8942599&amp;postID=5974572363225264567" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/5974572363225264567?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/5974572363225264567?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/bryanbcook/~3/qIcusfgsbBs/parsing-nullable-enumerations.html" title="Parsing Nullable Enumerations" /><author><name>bryan</name><uri>http://www.blogger.com/profile/01332614158223702009</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.bryancook.net/2011/03/parsing-nullable-enumerations.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkMAQHs-fCp7ImA9Wx9aEkg.&quot;"><id>tag:blogger.com,1999:blog-8942599.post-4555712808938407088</id><published>2011-03-04T12:07:00.001-05:00</published><updated>2011-03-04T12:07:21.554-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-04T12:07:21.554-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Tips" /><category scheme="http://www.blogger.com/atom/ns#" term="Visual Studio" /><title>Add a Custom Toolbar for Source Control</title><content type="html">&lt;p&gt;My current project uses TFS and I spent a lot of time in and out of source control, switching between workspaces to manage defects. I found myself needing access to my workspaces and getting really frustrated with how clunky this operation is within Visual Studio.&amp;#160; There are two ways you can open source control.&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;The Source Control item in the Team System tool window.&amp;#160; I don’t always have the Team Explorer tool window open and when I open it, it takes a few seconds to get details from the server. &lt;/li&gt;    &lt;li&gt;&lt;em&gt;View –&amp;gt; Other Windows –&amp;gt; Source Control Explorer&lt;/em&gt;.&amp;#160; Useful, but there’s too much mouse movement and clicking to be accessible. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;So, rather than creating a custom keyboard shortcut that I would forget I added a toolbar that is always in plain-sight. It’s so convenient that I take it for granted, and when I pair with others they comment on it. So for their convenience (and yours), here’s how it’s done.&lt;/p&gt;  &lt;h3&gt;Add a new Toolbar&lt;/h3&gt;  &lt;p&gt;From the Menubar, select “Tools –&amp;gt; Customize”.&amp;#160; It’ll pop up this dialog.&amp;#160; &lt;/p&gt;  &lt;p&gt;Click on “New” and give your toolbar a name.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_XB6P2gWz--8/TXEcP6xhxyI/AAAAAAAAAfQ/VsFnJlsFAhE/s1600-h/Toolbar_Customize_AddToolbar%5B3%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Toolbar_Customize_AddToolbar" border="0" alt="Toolbar_Customize_AddToolbar" src="http://lh5.ggpht.com/_XB6P2gWz--8/TXEcQbmKHeI/AAAAAAAAAfU/txqGBWBPd-Y/Toolbar_Customize_AddToolbar_thumb%5B1%5D.png?imgmax=800" width="467" height="484" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;h3&gt;Add the Commands&lt;/h3&gt;  &lt;p&gt;Switch to the Commands tab and select the name of your toolbar in the Toolbar dropdown.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_XB6P2gWz--8/TXEcQgheY9I/AAAAAAAAAfY/VetT3NA75dE/s1600-h/Toolbar_Customize_Empty%5B3%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Toolbar_Customize_Empty" border="0" alt="Toolbar_Customize_Empty" src="http://lh3.ggpht.com/_XB6P2gWz--8/TXEcQyPKgZI/AAAAAAAAAfc/Xo6E-mRl3wQ/Toolbar_Customize_Empty_thumb%5B1%5D.png?imgmax=800" width="468" height="484" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Click on the “Add Command” button and select the following commands:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;View : TfsSourceControlExplorer &lt;/li&gt;    &lt;li&gt;View : TfsPendingChanges &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_XB6P2gWz--8/TXEcRX_9toI/AAAAAAAAAfg/al8E9ZliGO8/s1600-h/Toolbar_Customize_AddCommand%5B3%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Toolbar_Customize_AddCommand" border="0" alt="Toolbar_Customize_AddCommand" src="http://lh3.ggpht.com/_XB6P2gWz--8/TXEcR2c2p_I/AAAAAAAAAfk/KoAMRVv6wd0/Toolbar_Customize_AddCommand_thumb%5B1%5D.png?imgmax=800" width="644" height="418" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Now style the button’s accordingly using the “Modify Selection” button.&amp;#160; I’ve set mine to use the &lt;em&gt;Default&lt;/em&gt; styling, which is just the button icon.&lt;/p&gt;  &lt;h3&gt;Enjoy&lt;/h3&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_XB6P2gWz--8/TXEcR6aipyI/AAAAAAAAAfo/-Q5UV5IEUis/s1600-h/CustomToolbar_result%5B4%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="CustomToolbar_result" border="0" alt="CustomToolbar_result" src="http://lh5.ggpht.com/_XB6P2gWz--8/TXEcSMcD8cI/AAAAAAAAAfs/gwOKmGqi6Gw/CustomToolbar_result_thumb%5B2%5D.png?imgmax=800" width="244" height="99" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8942599-4555712808938407088?l=www.bryancook.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/PKHMqmelnQOyIDBHI5NZhwooEWM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/PKHMqmelnQOyIDBHI5NZhwooEWM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/PKHMqmelnQOyIDBHI5NZhwooEWM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/PKHMqmelnQOyIDBHI5NZhwooEWM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=5e5FIFuJFVQ:cDY1JwPwg2g:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=5e5FIFuJFVQ:cDY1JwPwg2g:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=5e5FIFuJFVQ:cDY1JwPwg2g:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=5e5FIFuJFVQ:cDY1JwPwg2g:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?i=5e5FIFuJFVQ:cDY1JwPwg2g:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bryanbcook/~4/5e5FIFuJFVQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.bryancook.net/feeds/4555712808938407088/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8942599&amp;postID=4555712808938407088" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/4555712808938407088?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/4555712808938407088?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/bryanbcook/~3/5e5FIFuJFVQ/add-custom-toolbar-for-source-control.html" title="Add a Custom Toolbar for Source Control" /><author><name>bryan</name><uri>http://www.blogger.com/profile/01332614158223702009</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh5.ggpht.com/_XB6P2gWz--8/TXEcQbmKHeI/AAAAAAAAAfU/txqGBWBPd-Y/s72-c/Toolbar_Customize_AddToolbar_thumb%5B1%5D.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.bryancook.net/2011/03/add-custom-toolbar-for-source-control.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0cAQX8zeSp7ImA9Wx9aEUs.&quot;"><id>tag:blogger.com,1999:blog-8942599.post-3845234235124726946</id><published>2011-03-03T09:04:00.000-05:00</published><updated>2011-03-03T09:04:00.181-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-03T09:04:00.181-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="TDD" /><title>Building Custom Test Frameworks</title><content type="html">&lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;Author’s note: this post focuses on writing test tools to simplify repetitive tasks such as complex assertions and is inspired by colleagues that wrote a tool that nearly evolved beyond their control. I am not encouraging developers to write frameworks that mask symptoms of poorly isolated components or other design problems.&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;For some, evolving code through writing tests is seen as a labour of love. For others, it's just labour. The latter is especially true when you realize that you have to write a lot of repetitious tests that will likely introduce test friction later on. When faced with this dilemma, developers rise to the challenge and write code.&lt;/p&gt;  &lt;p&gt;Fortunately, there's a lot of &lt;a href="http://autopoco.codeplex.com/" target="_blank"&gt;great test framework tools&lt;/a&gt; popping up in the .net community that are designed to plug in to your test code. (I’m running out of battery power on my laptop as I write this, so my list of tools is lacking.&amp;#160; Send me a note and I’ll list your tool here) These tools can certainly make things easier by removing some obstacles or laborious activities, but if you're planning on writing your own tool or framework there a few pitfalls.&lt;/p&gt;  &lt;h3&gt;Common Pitfalls&lt;/h3&gt;  &lt;h4&gt;Obscured Intent&lt;/h4&gt;  &lt;p&gt;One of the goals of well written unit tests is to provide live examples of proper usage so that developers can learn more about the code's intended behaviour. This benefit can be significantly hindered when the usage and clear intent of your code has been abstracted into your framework. &lt;/p&gt;  &lt;h4&gt;Eventual Complexity&lt;/h4&gt;  &lt;p&gt;Applying automation to a problem follows the 80/20 rule where the majority of problems fit nicely into your abstraction. The edge cases however have a tendency to add bloat and it doesn't take much to quickly trash the idea of a simple tool. This is rarely a consequence of poor planning or bad design; additional complexity tends to creep in over time as your code evolves or as more consumers of the tool come on board.&lt;/p&gt;  &lt;p&gt;There's a consequence to this type of complexity: if few developers understand the tool's implementation, you risk limiting these developers to be tool maintainers. Even worse, if these developers leave your team there's a risk that the entire suite of tests will be abandoned if they start failing.&lt;/p&gt;  &lt;h4&gt;Dependence on Tool Quality / False Positives&lt;/h4&gt;  &lt;p&gt;In TDD, application defects hide in the tests you haven't written, so quality is a reflection of the accuracy and completeness of the tests. Likewise, tests that leverage a custom test framework are only as reliable as the completeness and accuracy of the tool. If the framework takes on the lions share of the work, then the outcome of the test is abdicated to the tool. This is dangerous because any change to the tool's logic could unintentionally allow subtle defects in the tested code to go unnoticed. False positives = tests that lie!&lt;/p&gt;  &lt;h3&gt;Recommendations&lt;/h3&gt;  &lt;h4&gt;Tests for Tools&lt;/h4&gt;  &lt;p&gt;Oddly enough, if your goal is to write a tool so that you don't need to write tests, you are going to need to write tests for the tool. Having tests for your custom tool ensures that false positives aren’t introduced as the tool is enhanced over time. From a knowledge transfer perspective, the tests serve as a baseline to describe the tool’s responsibilities and enable others to add new functionality (and new tests) with minimal oversight from the original tool author.&lt;/p&gt;  &lt;h4&gt;Design for Readability&lt;/h4&gt;  &lt;p&gt;Great frameworks fit in and enable you to express intent; so be careful of over-reaching and trying to do too much. Make sure your tool doesn't abstract away clues as to what the test is intended for, and if possible use descriptive method names to improve readability. Documenting your tool with Xml documentation syntax and comments is also very helpful for intent.&lt;/p&gt;  &lt;h4&gt;Evolve Naturally&lt;/h4&gt;  &lt;p&gt;Unless you spend weeks planning out your unit tests, custom test tools are the product of necessity that are realized when you start to write the second or third duplicated test.&amp;#160; I tend to realize my test tools as “found treasures” of my normal TDD development cycle.&lt;/p&gt;  &lt;p&gt;Rather than diving in and writing a framework or tool first, focus on satisfying the requirement of working software by writing the test using normal TDD best practices (red, green, refactor). During the clean up and refactor step, you will find duplication between tests or even different fixtures. When that happens, promote the duplicated code to a helper method, then a helper class. I like to think that great TDD is about refactoring mercilessly while keeping the original intent of the code clear – it’s about balance, know when you’ve gone too far.&lt;/p&gt;  &lt;p&gt;If you a reach a point where you can extract commonalities between a few helper classes into a generic solution, you’ll find yourself standing in the doorway between where your fixtures were self-contained and where they’ve become dependent on shared test logic.&amp;#160; Learn to recognize this moment because this is when you should stop writing tests for production code for a moment and write some tests for the tool. It’s also a good idea to keep a few of the manual tests around so that you can go back into the production code and &lt;a href="http://www.bryancook.net/2010/10/working-with-existing-tests.html" target="_blank"&gt;deliberately break it&lt;/a&gt; to prove that both sets of tests are equivalent.&lt;/p&gt;  &lt;p&gt;…Until next time. Happy coding.&amp;#160; (Now where’s my dang power supply?)&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8942599-3845234235124726946?l=www.bryancook.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/OIhSZQLIWgVwygJ5SLdpjKBaa5o/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/OIhSZQLIWgVwygJ5SLdpjKBaa5o/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/OIhSZQLIWgVwygJ5SLdpjKBaa5o/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/OIhSZQLIWgVwygJ5SLdpjKBaa5o/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=jGiGNA9xh7o:ZX-ufRvAPlY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=jGiGNA9xh7o:ZX-ufRvAPlY:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=jGiGNA9xh7o:ZX-ufRvAPlY:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=jGiGNA9xh7o:ZX-ufRvAPlY:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?i=jGiGNA9xh7o:ZX-ufRvAPlY:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bryanbcook/~4/jGiGNA9xh7o" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.bryancook.net/feeds/3845234235124726946/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8942599&amp;postID=3845234235124726946" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/3845234235124726946?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/3845234235124726946?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/bryanbcook/~3/jGiGNA9xh7o/building-custom-test-frameworks.html" title="Building Custom Test Frameworks" /><author><name>bryan</name><uri>http://www.blogger.com/profile/01332614158223702009</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://www.bryancook.net/2011/03/building-custom-test-frameworks.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Dk4GQXc6eCp7ImA9Wx9UEUo.&quot;"><id>tag:blogger.com,1999:blog-8942599.post-1379632623948549624</id><published>2011-02-08T09:00:00.000-05:00</published><updated>2011-02-08T09:22:00.910-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-02-08T09:22:00.910-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Tips" /><category scheme="http://www.blogger.com/atom/ns#" term="blogging" /><title>Plaintext + Dropbox = Ubiquitous Text</title><content type="html">&lt;p&gt;I am loving this. If you blog or like to jot down notes while on the go then I highly recommend the following setup. &lt;/p&gt;  &lt;h3&gt;Dropbox&lt;/h3&gt;  &lt;p&gt;&lt;a href="http://db.tt/0UPqKfi" target="_blank"&gt;Dropbox&lt;/a&gt; is a small cloud-based utility that synchronizes files between all your devices. It works on PC, Mac, iOS, Android and Blackberry.&amp;#160; It even has a web interface that you can browse from any computer, and even track previous versions of files. Best of all, it's free (for 2Gb of storage).&lt;/p&gt;  &lt;p&gt;There are a &lt;a href="https://www.dropbox.com/apps" target="_blank"&gt;number of applications&lt;/a&gt; that use Dropbox as their storage medium. My favorite so far is &lt;a href="http://www.hogbaysoftware.com/products/plaintext" target="_blank"&gt;PlainText&lt;/a&gt;.&lt;/p&gt;  &lt;h3&gt;PlainText&lt;/h3&gt;  &lt;p&gt;&lt;a href="http://www.hogbaysoftware.com/products/plaintext" target="_blank"&gt;PlainText&lt;/a&gt; is a bare bones text editor with a minimal UI that uses Dropbox as it's file system. Simply download to your iPhone, iPod Touch or iPad, login with your Dropbox account and your data magically syncs each time you touch the contents. Only limitation is that it doesn't have the ability to move files to different folders, but I can do that on my PC.&lt;/p&gt;  &lt;p&gt;Now it's possible for me to sketch down an idea on my iPhone while riding the subway or streetcar, then pickup where I left off and flesh out the details on my iPad while watching TV. I can even switch between devices with almost no wait, so I can proof read or work through an idea whenever I have a free moment. &lt;/p&gt;  &lt;h3&gt;Getting started&lt;/h3&gt;  &lt;p&gt;Setup is easy.&amp;#160; On your PC or Mac, go to &lt;a href="http://db.tt/0UPqKfi" target="_blank"&gt;Dropbox and setup an account&lt;/a&gt;, the software will download on the next page.&amp;#160; Install the application and associate it to your user account. The free version gives you 2 GB of storage (&lt;a href="https://www.dropbox.com/referrals" target="_blank"&gt;more if you&lt;/a&gt; &lt;a href="http://db.tt/0UPqKfi" target="_blank"&gt;enlist your friends&lt;/a&gt;) and they offer more storage through paid upgrades. &lt;/p&gt;  &lt;p&gt;On your iOS device, &lt;a href="http://itunes.apple.com/us/app/plaintext-dropbox-text-editing/id391254385?mt=8&amp;amp;ign-mpt=uo%3D4#" target="_blank"&gt;download PlainText&lt;/a&gt;.&amp;#160; In the settings, link it to your Dropbox account.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_XB6P2gWz--8/TU78fFqcsAI/AAAAAAAAAe0/m7O7IC25YLc/s1600-h/PlainText-Dropbox-signup%5B3%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="PlainText-Dropbox-signup" border="0" alt="PlainText-Dropbox-signup" src="http://lh6.ggpht.com/_XB6P2gWz--8/TU78gYb2RvI/AAAAAAAAAe4/glTp5sRMwhQ/PlainText-Dropbox-signup_thumb%5B5%5D.png?imgmax=800" width="164" height="244" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;PlainText by default will create a folder in your Dropbox called “PlainText”.&amp;#160; This is helpful so that you’re only syncing small files.&amp;#160; Here’s a quick screen-capture of the available settings.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_XB6P2gWz--8/TU78hIw_KfI/AAAAAAAAAe8/xqow3HpLwpw/s1600-h/Photo%20Feb%2006%2C%202%2033%2000%20PM%5B2%5D.jpg"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="Photo Feb 06, 2 33 00 PM" border="0" alt="Photo Feb 06, 2 33 00 PM" src="http://lh3.ggpht.com/_XB6P2gWz--8/TU78hldmZ0I/AAAAAAAAAfA/XOagiadPdig/Photo%20Feb%2006%2C%202%2033%2000%20PM_thumb.jpg?imgmax=800" width="184" height="244" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;You can create files and folders on your iOS device.&amp;#160; Any changes will automatically sync to your PC/Mac.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_XB6P2gWz--8/TU78h0rZxuI/AAAAAAAAAfE/HYuJNjQF3DY/s1600-h/Dropbox-sync%5B2%5D.png"&gt;&lt;img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto; padding-top: 0px" title="Dropbox-sync" border="0" alt="Dropbox-sync" src="http://lh6.ggpht.com/_XB6P2gWz--8/TU78iQPyQ6I/AAAAAAAAAfI/Nbtk7cpMo2E/Dropbox-sync_thumb.png?imgmax=800" width="244" height="69" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;blockquote&gt;&lt;em&gt;Disclosure: This is not a paid advertisement, I just really like this configuration.&amp;#160; I should point out that the links to sign-up are to my referral page.&amp;#160; If you are vehemently opposed to this you can visit the site referral free here: &lt;a href="https://www.dropbox.com/"&gt;https://www.dropbox.com/&lt;/a&gt;&lt;/em&gt;&lt;/blockquote&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8942599-1379632623948549624?l=www.bryancook.net' alt='' /&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/kXTJbK286MeZGtKPDydBlPMRMYc/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/kXTJbK286MeZGtKPDydBlPMRMYc/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/kXTJbK286MeZGtKPDydBlPMRMYc/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/kXTJbK286MeZGtKPDydBlPMRMYc/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=1mfBNbcyMOw:WgP39g-Y5F4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=1mfBNbcyMOw:WgP39g-Y5F4:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=1mfBNbcyMOw:WgP39g-Y5F4:G79ilh31hkQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?d=G79ilh31hkQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/bryanbcook?a=1mfBNbcyMOw:WgP39g-Y5F4:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/bryanbcook?i=1mfBNbcyMOw:WgP39g-Y5F4:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bryanbcook/~4/1mfBNbcyMOw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://www.bryancook.net/feeds/1379632623948549624/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=8942599&amp;postID=1379632623948549624" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/1379632623948549624?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/8942599/posts/default/1379632623948549624?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/bryanbcook/~3/1mfBNbcyMOw/plaintext-dropbox-ubiquitous-text.html" title="Plaintext + Dropbox = Ubiquitous Text" /><author><name>bryan</name><uri>http://www.blogger.com/profile/01332614158223702009</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh6.ggpht.com/_XB6P2gWz--8/TU78gYb2RvI/AAAAAAAAAe4/glTp5sRMwhQ/s72-c/PlainText-Dropbox-signup_thumb%5B5%5D.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://www.bryancook.net/2011/02/plaintext-dropbox-ubiquitous-text.html</feedburner:origLink></entry></feed>

