<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-14744716</id><updated>2011-12-30T17:28:39.845+05:30</updated><category term='Mocks'/><category term='Kata'/><category term='Sorting'/><category term='Automated Builds'/><category term='XP'/><category term='conversations-of-note'/><category term='windows hooks'/><category term='OOD'/><category term='VSX'/><category term='Moq'/><category term='Automated Tests'/><category term='white'/><category term='MSTest'/><category term='GUI'/><category term='C++'/><category term='Jumpstart'/><category term='JQuery'/><category term='TDD'/><category term='Code Coverage'/><category term='Rhino'/><category term='BDD'/><category term='Retrospectives'/><category term='static code analysis'/><category term='.net'/><category term='Agile Planning'/><category term='NUnit'/><category term='sharing'/><category term='Book Review'/><category term='xtreamer'/><category term='Continuous Integration'/><category term='Version Control'/><category term='Rails'/><category term='gadget-grappling'/><category term='Logging'/><category term='wpf datagrid'/><category term='cucumber'/><category term='metaprogramming'/><category term='Timesavers'/><category term='FIT / Fitnesse'/><category term='jMock'/><category term='XPath'/><category term='Agile'/><category term='Ruby'/><category term='wpf'/><category term='OOP'/><category term='SLIM'/><category term='IronRuby'/><category term='MySql'/><category term='ATDD'/><category term='ide'/><category term='vista'/><title type='text'>My conversations with gullible machines...</title><subtitle type='html'>Stuff about computers I wrote down as notes to myself.. 
Feel free to take a look and leave me a note if you found something useful / you know 'a better way of doing that'.
Thanks for reading..</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default?start-index=101&amp;max-results=100'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>126</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-14744716.post-8307024049236684624</id><published>2011-11-14T16:31:00.001+05:30</published><updated>2011-11-18T10:39:03.702+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='.net'/><category scheme='http://www.blogger.com/atom/ns#' term='Automated Tests'/><category scheme='http://www.blogger.com/atom/ns#' term='MSTest'/><category scheme='http://www.blogger.com/atom/ns#' term='NUnit'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>NUnit vs MSTest  - 2011 Edition</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;span style="font-size: small;"&gt;I&lt;/span&gt;&lt;span style="font-size: small;"&gt; have tried to be as objective as possible. Disclaimer: NUnit user since 2005-06.&lt;/span&gt;&lt;/div&gt;&lt;span style="font-size: small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif; font-size: small;"&gt;Legend:&lt;/span&gt;&lt;br /&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif; font-size: small;"&gt;MSTest as an alias for the unit-testing fwk bunded with VS2010 v10.0.30319 throughout this post (although technically it is the just the runner). It's much easier to say than VisualStudio QualityTools UnitTestFramework. For NUnit, I'm using v2.5.9&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif; font-size: small;"&gt;Class-Setup/Teardown - to be executed ONCE before/after ALL tests &lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif; font-size: small;"&gt;Test-Setup/Teardown - to be executed before/after EVERY test&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;div style="color: #660000;"&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif; font-size: large;"&gt;Major Differences&lt;/span&gt;&lt;/div&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Migrating a test suite between the two runners might be non-trivial depending on your test code. MSTest and NUnit are very different in the way they go about running a set of tests. e.g. Consider a set of 2 classes containing tests - Class A with 2 tests, B with just one. If I insert logging at some critical points.. (I am looking at the default behavior - no customization)&lt;/span&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;/div&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-KGozLz2zY4U/TsJE3sh58eI/AAAAAAAABDA/xQKeBZo4dw8/s1600/NUnit-log.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="236" src="http://1.bp.blogspot.com/-KGozLz2zY4U/TsJE3sh58eI/AAAAAAAABDA/xQKeBZo4dw8/s640/NUnit-log.png" width="640" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;NUni&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;t&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&amp;nbsp;Observations:&lt;/span&gt;&lt;br /&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Tests are run in sequence (no overlap)&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Single threaded : &lt;b&gt;one thread&lt;/b&gt; runs all the tests&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;All tests within a test class are run on the &lt;b&gt;SAME instance&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;xUnit order :&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;for each test class &lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Class setup&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;for each test&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;test setup&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;test&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;test teardown&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Class teardown&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;/div&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-zb0jKhPo1kY/TsJE3U-TZ3I/AAAAAAAABC4/eCARj7e81tQ/s1600/MSTest-log.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="242" src="http://2.bp.blogspot.com/-zb0jKhPo1kY/TsJE3U-TZ3I/AAAAAAAABC4/eCARj7e81tQ/s640/MSTest-log.png" width="640" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;MSTest&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Observations:&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Tests are run in sequence&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;b&gt;Multi-threaded&lt;/b&gt; even when tests are run sequentially : We can see 4 threads in this example (1 per test + 1 for class-teardowns)&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;A &lt;b&gt;NEW Instance&lt;/b&gt; of the test class is created &lt;b&gt;PER TEST&lt;/b&gt; (see 3 diff hashcode values)&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;MSTest order :&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;for each test-class&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Class setup&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;for each test&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;test setup&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;test&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;test teardown&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Class cleanup for all test classes visited&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;What does all this mean ?&lt;/span&gt;&lt;br /&gt;&lt;ol style="text-align: left;"&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;MSTest differs from xUnit in its implementation of &lt;span style="background-color: yellow;"&gt;test class setup or teardown&lt;/span&gt;. They &lt;span style="background-color: yellow;"&gt;have to be static methods&lt;/span&gt;, which excludes setting up anything in instance variables to be used by subsequent tests. You can promote them to static (aka global) variables but combined with multiple-threads, be careful! &lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;MSTest &lt;span style="background-color: yellow; color: red;"&gt;does not provide deterministic test-class teardown&lt;/span&gt; i.e. no guarantees about when it will be run; just that it will be executed. So you need to design your tests to account for this - see what happened in the image above. Instead of Start-Close cycles, I see Start-Start-Close-Close!! I haven't yet figured out a workaround for this.. so if you know please post a comment.&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div style="color: #660000;"&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif; font-size: large;"&gt;Test-Class Inheritance&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;xUnit has some patterns that use inheritance to achieve the desired effect. So let's see they fare in this dept.&lt;/span&gt;&lt;/div&gt;&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;ul style="text-align: left;"&gt;&lt;/ul&gt;&lt;/div&gt;&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-ujilArMg5rM/TsSCiGviBQI/AAAAAAAABDo/UfSJqIs0Qac/s1600/NUnit-Inheritance.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="157" src="http://2.bp.blogspot.com/-ujilArMg5rM/TsSCiGviBQI/AAAAAAAABDo/UfSJqIs0Qac/s400/NUnit-Inheritance.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;NUnit : abstract fixture&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-ziIcliVwFRw/TsSCiP3wqLI/AAAAAAAABDk/EKwRTC39KXc/s1600/MSTest-Inheritance.png" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="155" src="http://1.bp.blogspot.com/-ziIcliVwFRw/TsSCiP3wqLI/AAAAAAAABDk/EKwRTC39KXc/s400/MSTest-Inheritance.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;MSTest : abstract fixture&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;div dir="ltr" style="text-align: left;"&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;the &lt;b&gt;abstract fixture pattern&lt;/b&gt; - move common methods (e.g. common setup/teardown into a abstract base fixture)&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;span style="background-color: yellow; color: red;"&gt;MSTest (right) won't execute Class-Setup/Teardown methods defined in base types.&lt;/span&gt; Test-Setup/Teardowns are treated differently. (so you may not be able to layer setup/teardown as shown above ). Also remember Class-Teardown is unpredictable.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt; &lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt; &lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt; &lt;/span&gt;&lt;/div&gt;&lt;div dir="ltr" style="text-align: left;"&gt;&lt;ul style="text-align: left;"&gt;&lt;ul&gt;&lt;/ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;the &lt;b&gt;abstract test pattern&lt;/b&gt; - all the tests are housed in an abstract class. You then subclass and override a method that provides the actual object to be tested. e.g. run 'contract tests' against multiple implementations of an interface.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;NUnit : You can cleanly extract a POCO abstract base type with test methods. &lt;span style="background-color: white; color: blue;"&gt;MSTest:&lt;/span&gt; Additionally, you need to decorate the base type also with a TestClass attribute. (It won't show up in the TestView.)&lt;span style="background-color: #d9ead3;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span style="background-color: black; color: blue; font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;span style="background-color: #d9ead3;"&gt;But can be done!&lt;/span&gt;&lt;/span&gt; &lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-Cy34v4Mvz1A/TsTePP8LOHI/AAAAAAAABEE/jdyT4sshM9c/s1600/AbstractTest.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="228" src="http://4.bp.blogspot.com/-Cy34v4Mvz1A/TsTePP8LOHI/AAAAAAAABEE/jdyT4sshM9c/s640/AbstractTest.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt; &lt;/span&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="color: #660000;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="color: #660000;"&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Parameterized Tests (Data driven)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;I remember reading (when I first heard of TDD) that tests should be self-contained and shouldn't need to take inputs. Well, we've changed our mind. The need to execute the same test logic with different data sets (without duplication) led to RowTests. NUnit integrated a contributed extension and now there are &lt;a href="http://www.nunit.org/index.php?p=testCase&amp;amp;r=2.5"&gt;TestCases&lt;/a&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;So let's test if how our client handles authentication.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre class="brush: csharp"&gt;[TestCase("WrongUser", "Don't care", TestName = "Invalid user")]&lt;br /&gt;[TestCase("Gishu", "Wrong Password", TestName = "Wrong password")]&lt;br /&gt;[TestCase("Gishu", "openSesame", TestName = "Right credentials")]&lt;br /&gt;public void ThrowsExceptionIfCredentialsAreWrong(string username, string password)&lt;br /&gt;{&lt;br /&gt;    var client = new Client();&lt;br /&gt;    var exception = Assert.Throws&amp;lt;ConnectFailedException&amp;gt;(&lt;br /&gt;        () =&amp;gt; client.Connect("129.0.0.1", username, password));&lt;br /&gt;    Assert.That(exception, Has.Message.EqualTo("Invalid Credentials"));&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span id="goog_353621318"&gt;&lt;/span&gt;&lt;span id="goog_353621319"&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-AFgAkhpQk9Y/TsT_IIjwbzI/AAAAAAAABFk/3YuEvrdFfug/s1600/N-RowTests.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-AFgAkhpQk9Y/TsT_IIjwbzI/AAAAAAAABFk/3YuEvrdFfug/s1600/N-RowTests.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;I love &lt;b&gt;TestNames &lt;/b&gt;vs anonymous inline data clumps!!&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Lets switch to&lt;span style="background-color: yellow; color: red;"&gt; MSTest. No RowTests built-in&lt;/span&gt;. There is &lt;a href="http://blogs.msdn.com/b/vstsqualitytools/archive/2009/09/04/extending-the-visual-studio-unit-test-type-part-2.aspx"&gt;a patch&lt;/a&gt; but it is the bare minimum (and requires me to mess with the registry) ; more on that after the jump. You can't slot in inline data values - but you &lt;span style="background-color: #d9ead3; color: blue;"&gt;can pull in data from a CSV/Xml/DB&lt;/span&gt;. Hmm... seems like a Hammer to swat a fly. But I gave that a try too; &lt;a href="http://msdn.microsoft.com/en-us/library/ms182527.aspx"&gt;HOW TO: Create a data driven test&lt;/a&gt;. So I use the wizard, more attributes appear. It works but...&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-uhrYizmc5N8/TsUtzb4DWQI/AAAAAAAABF8/IfGV_xwKGE0/s1600/MS-DDT.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="307" src="http://3.bp.blogspot.com/-uhrYizmc5N8/TsUtzb4DWQI/AAAAAAAABF8/IfGV_xwKGE0/s640/MS-DDT.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Differences:&lt;/span&gt;&lt;br /&gt;&lt;ol style="text-align: left;"&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;span style="background-color: yellow;"&gt;Does not show&lt;/span&gt; me 4 &lt;span style="background-color: yellow;"&gt;distinct tests in the results&lt;/span&gt; (actually the total count circled is wrong..). You &lt;span style="background-color: yellow;"&gt;cannot name your tests&lt;/span&gt;.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;You need to pop up test details (another window) for each group to see which tests failed in the group.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Even then, you can't see which inputs failed. Annoying.&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;The extension mentioned earlier also suffers from the same. So for static inputs, "No great shakes!"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;b&gt;&amp;nbsp;Dynamic Input generation: &lt;/b&gt;But we're still not done, what if we want to compute the inputs using code?? Say hello to NUnit's &lt;a href="http://www.nunit.org/index.php?p=testCaseSource&amp;amp;r=2.5"&gt;TestCaseSource &lt;/a&gt;and &lt;a href="http://www.nunit.org/index.php?p=valueSource&amp;amp;r=2.5"&gt;ValueSource&lt;/a&gt;. You can write methods that generate test cases at run-time based on any arbitrary logic (with all the frills: names, tags/category, expectedResult/Exception).&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Once again &lt;span style="background-color: yellow;"&gt;MSTest - Not Supported&lt;/span&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;div style="color: #660000;"&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Parameterized Test Fixtures&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Next the big guns.. you don't need them everyday. But when you do, NUnit allows you to really cut down duplication via &lt;a href="http://www.nunit.org/index.php?p=testFixture&amp;amp;r=2.5"&gt;Parameterized Fixtures and Generic Fixtures&lt;/a&gt;. e.g. consider the following convoluted example &lt;/span&gt;&lt;br /&gt;&lt;pre class="brush: csharp"&gt;[TestFixture(typeof(PhoneX), "Sam", Description = "Model X")]&lt;br /&gt;[TestFixture(typeof(PhoneY), "Htc", Description = "Model Y")]&lt;br /&gt;public class TestAPhone&amp;lt;TPhone&amp;gt; where TPhone : Phone, new()&lt;br /&gt;{&lt;br /&gt;    private TPhone _phoneToBeTested;&lt;br /&gt;&lt;br /&gt;    public TestAPhone(string name)&lt;br /&gt;    {&lt;br /&gt;        _phoneToBeTested = new TPhone { Name = name };&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    [Test]&lt;br /&gt;    public void TestDialing()&lt;br /&gt;    {&lt;br /&gt;        Console.Out.WriteLine("a phone of type {0} with name {1}", typeof(TPhone), _phoneToBeTested.Name);&lt;br /&gt;    }&lt;br /&gt;    [Test]&lt;br /&gt;    public void TestBatteryLife()...&lt;br /&gt;    &lt;br /&gt;&lt;/pre&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;NUnit interprets that as 2 different test fixtures - It is parameterized.. "Sam" and "Htc" are parameters passed into the suite. It is generic too.. the 2 test fixture attributes caused the entire suite to be run against an object of PhoneX and PhoneY.&lt;/span&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-VPbadkemQ0s/TsTy8-pynRI/AAAAAAAABEc/VAsVvYUZLuM/s1600/N-ParamGenericFixtures.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="147" src="http://4.bp.blogspot.com/-VPbadkemQ0s/TsTy8-pynRI/AAAAAAAABEc/VAsVvYUZLuM/s640/N-ParamGenericFixtures.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;span style="background-color: yellow; color: red;"&gt;MSTest: NOT SUPPORTED (or I haven't found it)&lt;/span&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="color: #660000;"&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;IDE-Integration&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;A big attraction with most MS offerings is integration; in this case, IDE integration. &lt;span style="color: blue;"&gt;MSTest integrates out of the box. NUnit needs some assistance;&lt;/span&gt; but if you have something like Resharper (which you should), this isn't a deal-breaker.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="color: #660000;"&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif; font-size: large;"&gt;Speed of Execution&lt;/span&gt;&lt;/div&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;MSTest: &lt;/span&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;This is peculiar. I used Ctrl+R, A to run all tests in solution. &lt;span style="color: black;"&gt;It takes 4-5 s to run 3 measly tests.. as compared to NUnit which runs an identical set in 0.1s .&lt;/span&gt; Around 4 secs elapse, before any test method's status changes - it seems it is doing some heavy lifting in "preparing" to run the tests.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;NUnit: I have NUnit setup to run all my tests when the binaries change. So a successful build triggers a test run. The faster I receive the test results, the less the possibility that I pursue a distraction.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Even in console mode, NUnit was faster. The cold start case takes much longer. However in subsequent runs too, NUnit took 3.5s as compared to 6s for MSTest&lt;/span&gt;&lt;br /&gt;&lt;span style="color: blue; font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;NUnit wins the speed test.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;div style="color: #660000;"&gt;&lt;span style="font-size: large;"&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Assertion Library&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;NUnit has a much more evolved assertion library than MSTest. &lt;/span&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Don't have a detailed comparison here.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Personally, I miss the &lt;b style="background-color: yellow;"&gt;constraint based Assert Model&lt;/b&gt; present in &lt;a href="http://www.nunit.org/index.php?p=constraintModel&amp;amp;r=2.4"&gt;NUnit&lt;/a&gt;, &lt;a href="http://code.google.com/p/hamcrest/wiki/Tutorial"&gt;Hamcrest&lt;/a&gt;, et.all, which I find more readable.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;e.g. &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Assert.That(actualObject, meets_some_constraint)&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: yellow;"&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;b&gt;Asserting on exceptions&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-57AJpkGOZMY/TsH_MQp5cFI/AAAAAAAABCk/Fywn7mJRSow/s1600/MSTest-ExpExcep.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="209" src="http://3.bp.blogspot.com/-57AJpkGOZMY/TsH_MQp5cFI/AAAAAAAABCk/Fywn7mJRSow/s640/MSTest-ExpExcep.png" width="640" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;MSTest : Expected Exception not thrown!&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt; MSTest: You can use this to state that the corresponding test should throw an exception of Type X. It also takes a message as a second parameter... which is the failure message (to be shown when the test fails) &lt;b&gt;NOT&lt;/b&gt; the expected exception message. i.e. you can only check the type of exception.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;NUnit: You can check the type, the ExpectedMessage (you can even specify that the actual exception message must contain/start-with/exactly-match/match-a-regex), a custom handler to verify the exception and a failure message. &lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;div&gt;&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-left: 1em; text-align: left;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-vx2dFj2e3mI/TsH_MZY4sUI/AAAAAAAABCg/j3HcP5-ySGg/s1600/NUnit-ExpExcep.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="273" src="http://3.bp.blogspot.com/-vx2dFj2e3mI/TsH_MZY4sUI/AAAAAAAABCg/j3HcP5-ySGg/s640/NUnit-ExpExcep.png" width="640" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;NUnit : Expected Exception thrown but with incorrect message&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;However even this approach has been deprecated because you're not sure of the source of the exception, any line in the test could throw the exception and pass the test. So enter Assert.Throws where you narrow the scope down to the Connect call in the following example.&lt;/span&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-_PX9Jb4JrgM/TsH_Mf8fMdI/AAAAAAAABCw/0p9DyTnvdZk/s1600/NUnit-Throws.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="179" src="http://4.bp.blogspot.com/-_PX9Jb4JrgM/TsH_Mf8fMdI/AAAAAAAABCw/0p9DyTnvdZk/s640/NUnit-Throws.png" width="640" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;NUnit&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;span style="background-color: yellow;"&gt;MSTest does not have Assert.Throws&lt;/span&gt; or an equivalent. This was actually &lt;a href="http://connect.microsoft.com/VisualStudio/feedback/details/381288"&gt;a user-request in 2008&lt;/a&gt;. Still pending in 2011. It isn't too hard to write your own version.. but then you shouldn't have to.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt; &lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;pre class="brush: csharp"&gt;public static T Throws&amp;lt;T&amp;gt;(Action codeblock) where T : Exception&lt;br /&gt;{&lt;br /&gt;    try&lt;br /&gt;    {&lt;br /&gt;        codeblock();&lt;br /&gt;    }&lt;br /&gt;    catch(T exception)&lt;br /&gt;    {&lt;br /&gt;        return exception;&lt;br /&gt;    }&lt;br /&gt;    Assert.Fail("Did not throw an exception of type " + typeof(T));&lt;br /&gt;    return null;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Another nitpicky example would be &lt;span style="background-color: yellow;"&gt;the &lt;/span&gt;&lt;b style="background-color: yellow;"&gt;CollectionAssert implementation&lt;/b&gt;.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;MSTest accepts ICollection for parameters instead of the more general IEnumerable. When you're comparing objects of IEnumerable&lt;t&gt;&lt;t&gt;&amp;lt;T&amp;gt; (LINQ anyone) or IList&amp;lt;T&amp;gt;&lt;t&gt;&lt;t&gt; (another core collection type), you need to create copies so that you can compare. An avoidable design choice. Also note the error messages - it's important to ***&lt;span style="background-color: yellow;"&gt;fail informatively&lt;/span&gt;***. Chalk this one too to NUnit.&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/t&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre class="brush: csharp"&gt;IEnumerable&amp;lt;int&amp;gt; enumerableX = new[] {1, 2, 3};&lt;br /&gt;IEnumerable&amp;lt;int&amp;gt; enumerableY = new[] {1, 2, 4}.Concat(new[]{5});&lt;br /&gt;CollectionAssert.AreEqual(enumerableX.ToList(), enumerableY.ToList(), "myError Message");&lt;br /&gt;// Output:&lt;br /&gt;// CollectionAssert.AreEqual failed. myError Message(Different number of elements.)&lt;br /&gt;&lt;br /&gt;/*----------Equivalent NUnit error ---------*/&lt;br /&gt;CollectionAssert.AreEqual(enumerableX, enumerableY, "myError Message");&lt;br /&gt;&lt;br /&gt;//Output:&lt;br /&gt;//NUnitTestsClient.ConnectTests.TestCollections:&lt;br /&gt;//  myError Message&lt;br /&gt;//  Expected is &amp;lt;...List`1[System.Int32]&amp;gt; with 3 elements, actual is &amp;lt;....List`1[System.Int32]&amp;gt; with 4 elements&lt;br /&gt;//  Values differ at index [2]&lt;br /&gt;//  Expected: 3&lt;br /&gt;//  But was:  4&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div style="color: #660000;"&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif; font-size: large;"&gt;Code Coverage&lt;/span&gt;&lt;/div&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Yup. With MSTest, &lt;span style="background-color: #d9ead3;"&gt;setting up code coverage is a snap&lt;/span&gt;. This is &lt;a href="http://msdn.microsoft.com/en-us/library/dd504821.aspx"&gt;how you do it&lt;/a&gt; ; the trick is in locating the Configure button :)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;That said, getting code coverage for NUnit tests is just a bit more of effort. Create a batch file&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span style="font-size: small;"&gt;vsinstr /coverage MyProduction.dll&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;wbr&gt;&lt;/wbr&gt;&lt;span style="font-size: small;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #instrument binaries&lt;br /&gt;vsperfcmd -start:coverage -output:WhatsThe.coverage&amp;nbsp; #start profiler&lt;br /&gt;[path to &lt;b&gt;nunit-console-x86&lt;/b&gt;.exe] MyNUnitTests.dll&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #run tests&lt;br /&gt;vsperfcmd -shutdown&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; #stop profiler&lt;/span&gt;&lt;/div&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;That creates a coverage file that you can just open up in the IDE and you get the stats and the line highlighting et. all.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="color: #660000;"&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif; font-size: large;"&gt;Test Impact&lt;/span&gt;&lt;/div&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;MSTest &lt;span style="background-color: #d9ead3;"&gt;can point out &lt;/span&gt;&lt;b style="background-color: #d9ead3;"&gt;unit&lt;/b&gt;&lt;span style="background-color: #d9ead3;"&gt; tests that are impacted by a code change&lt;/span&gt;, on the basis of function call chains. There is some additional work to avail this benefit (configuration and collecting baselines)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;span style="background-color: yellow;"&gt;NUnit : not supported&lt;/span&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;That said: it works only for unit tests; Personally I'd run all the unit tests but YMMV.. especially if it takes over 10-15 mins to run all of them.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;It would have been a HUGE time-saver if it worked for acceptance tests. However at the system level, modules interact via DB, files, networks, etc even though there are no direct function calls ; so doesn't work.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;div style="color: #660000;"&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif; font-size: large;"&gt;Parallel execution&lt;/span&gt;&lt;/div&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;span style="background-color: #d9ead3;"&gt;MSTest seems to be designed to enable executing unit tests in parallel&lt;/span&gt;. Here's &lt;a href="http://msdn.microsoft.com/en-us/library/ee921484.aspx"&gt;the how-to&lt;/a&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Note:&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;ol style="text-align: left;"&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;I had to open-and-close my solution for the change to take effect.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Also you can have either coverage or parallel execution (not both).&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Of course your tests need to be designed accordingly too - eliminate interference. Also would be helpful to verify that the tests are isolated/independent.&lt;/span&gt;&lt;br /&gt;&lt;div&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;div&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;span style="background-color: yellow;"&gt;NUnit : not supported..yet&lt;/span&gt;. However there is PNUnit, an open-source mod. Also it seems likely that parallel execution would be built into the next big release of NUnit. Another approach would be running segments of your tests in parallel on multiple cores/machines.&lt;/span&gt;&lt;br /&gt;&lt;div style="color: #660000;"&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif; font-size: large;"&gt;Misc. Peeves&lt;/span&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt; &lt;/span&gt;&lt;/div&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Some more tiny things that irked me with MSTest &lt;/span&gt;&lt;br /&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;No hierarchical view of test cases. Flat lists everywhere.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Have to open a new "test details" window to see details of every test failure. e.g. console output.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Adds supporting files to the solution (.vsmdi, .testsettings) etc.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Cannot see console output for all tests in one place. (Useful for debugging).&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt; Categories can only be applied to tests. Tedious - applying the attribute in 15 places instead of once on top of the test-class. (Duplication). Filtering on categories is non-intuitive in the IDE. Try doing it without looking at &lt;a href="http://msdn.microsoft.com/en-us/library/dd286683.aspx"&gt;the answer&lt;/a&gt;. &lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div style="color: #660000;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="color: #660000;"&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif; font-size: large;"&gt;Summary (IMHO):&lt;/span&gt;&lt;/div&gt;&lt;div style="color: #660000;"&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;So NUnit is clearly ahead on Speed, Simplicity, Assertion library, Flexibility e.g. Parameterized (data-driven) tests and informative failures. It has had the benefit of time and shows it. If you're already using it, there is no compelling reason to switch. &lt;/span&gt;&lt;/div&gt;&lt;div style="color: #660000;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="color: #660000;"&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;MSTest has parallel execution &amp;amp; Test Impact as differentiators. However that is not enough to make up for its shortcomings as a unit testing framework. Less frequent releases (tied up with VS editions) and slower pace of evolution. It just has got a lot of small things wrong that make it difficult to like. If you're using TFS, then MSTest would be easier to work with than other unit testing frameworks for obvious reasons. (But then this is your smaller problem.. Sorry couldn't resist that one.)&lt;/span&gt;&lt;/div&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/14744716-8307024049236684624?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/8307024049236684624/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2011/11/nunit-vs-mstest-2011-edition.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/8307024049236684624'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/8307024049236684624'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2011/11/nunit-vs-mstest-2011-edition.html' title='NUnit vs MSTest  - 2011 Edition'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-KGozLz2zY4U/TsJE3sh58eI/AAAAAAAABDA/xQKeBZo4dw8/s72-c/NUnit-log.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-5141617304304097082</id><published>2011-11-09T13:02:00.000+05:30</published><updated>2011-11-09T13:02:08.581+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='Timesavers'/><title type='text'>PSR : Free Windows Screen Recording tool</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;An unsung hero in the MS Toolkit. &lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;It has a weird name - &lt;b&gt;Problem Steps Recorder&lt;/b&gt; that is not obvious as a search keyword. It doesn't create a video as the output, rather an HTML containing annotated images. (On the flip side, it doesn't eat up a lot of space and doesn't lose much information).&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;This one ships with Windows7. To invoke, Start &amp;gt; Run &amp;gt; psr&amp;nbsp;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;This should pop the very intuitive UI. Here's a &lt;a href="http://www.microsoft.com/download/en/details.aspx?id=22292"&gt;3 min video walkthrough&lt;/a&gt;. I just learnt you can annotate issues as well.&amp;nbsp;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;b&gt;Brilliant!&lt;/b&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&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/14744716-5141617304304097082?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/5141617304304097082/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2011/11/psr-free-windows-screen-recording-tool.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/5141617304304097082'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/5141617304304097082'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2011/11/psr-free-windows-screen-recording-tool.html' title='PSR : Free Windows Screen Recording tool'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><thr:total>0</thr:total><georss:featurename>Thane, Maharashtra, India</georss:featurename><georss:point>19.23184 72.967178</georss:point><georss:box>19.17187 72.888214 19.291809999999998 73.046142</georss:box></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-977103693222030125</id><published>2011-11-08T18:12:00.002+05:30</published><updated>2011-11-08T18:23:35.099+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='.net'/><category scheme='http://www.blogger.com/atom/ns#' term='static code analysis'/><title type='text'>Review : Parasoft DotTest Static Code Analysis</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Everyone agrees that static code analysis is good. However it isn't in widespread use. It has become easier with FXCop / Code Analysis built into VS2010. Personally I'm for "educating developers" over SCA.&amp;nbsp;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;b&gt;Focus on &lt;/b&gt;&lt;b&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Prevention over Post-facto Inspection, just like Bugs.&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;&lt;b&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Make sure that the number of warnings reduce over time.&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Make sure that the code isn't being engulfed by green suppression markups. &lt;/span&gt;&lt;/b&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Refine the set of rules&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;/span&gt;&lt;/b&gt;as needed.&lt;/li&gt;&lt;/ul&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Cannot stress this enough, To avoid SCA pain (drowning in a stormy sea of SCA warnings) START EARLY.&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;I was asked to come up with a good set of SCA rules for acceptance test code. Here's the specific tool I'm looking at -&amp;nbsp; &lt;a href="http://www.parasoft.com/jsp/products/dottest.jsp?itemId=135"&gt;Parasoft dotTest&lt;/a&gt; (I'm using v9.1). &lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Setup is easy.. Liked the following aspects.&lt;/div&gt;&lt;ul style="text-align: left;"&gt;&lt;li style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;You can install into a separate profile i.e. avoid messing up your default VS2010 setup.&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;You can get a floating network license that can be shared across users. You need to check "Release automatically when idle" in the License options.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;So I created mine by creating a new configuration.&lt;/span&gt;&lt;br /&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Main Menu - Parasoft - Test Configurations... Click New&lt;/div&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Adding categories one at a time by cross-verifying it with a medium sized codebase ~80 files / ~8K LOC. Took about 2 mins. The rules can be found under the "Static" tab on the right, when your configuration is selected.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;TIP! The search box can be used to filter the hierarchical view below.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;TIP! Right click on a specific rule to bring up its documentation. Or parameterize the rule if that is supported.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;You can export the configuration then to a file that can be shared across your team.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Since I was looking for SCA on test code (which is run within a controlled env), I turned off the following categories&lt;/span&gt;&lt;br /&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;COM Guidelines&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Casting guidelines &lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Implementing Finalize and Dispose&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Security Inspection&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Serialization Guidelines&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Security Policy Rules&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;WPF&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;That accounts for 96 / 444 rules. Next the rules that didn't make the cut (Rule Id in brackets, use search/filter to find a rule.)&lt;/span&gt;&lt;br /&gt;&lt;ul style="text-align: left;"&gt;&lt;li style="color: blue;"&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Keep line length within predefined parameters (80) [BRM.MLL-3] &lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Includes whitespaces on the left - in short indentation causes rules to cause noise warnings. Unusable.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li style="color: purple;"&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;span style="color: blue;"&gt;Avoid class, struct, or interface names which are more than 14 characters long [BRM.LONGNAMES-4]&lt;/span&gt; &lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Default limit too short. Cannot customize. I prefer long readable names over this warning.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li style="color: blue;"&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Always provide appropriate file header (copyright information, etc.) [BRM.FILEHEADER-3]&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Needs a comment to be the first line in the file - even before the using statements. &lt;b&gt;Does not recognize standard XML comments.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;b&gt;Does not exclude non-public classes.&lt;/b&gt; Noise&lt;b&gt;&amp;nbsp;&lt;/b&gt; &lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li style="color: blue;"&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Avoid unused private methods [CMUG.MU.AUPM-2]&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Noise warnings. Flagged methods that were being called.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;span style="color: blue;"&gt;Avoid using get accessor with side effects [CMUG.PRU.AGAS-3]&lt;/span&gt; &lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Flagged all properties that were internally calling String.Format. Noise.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li style="color: blue;"&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Use an array instead of many parameters [CMUG.MU.AIMP-5]&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Noise again. Recommends turning get(string elementId, string keyPropertyName, string valuePropertyName) to take a string array instead of well named parameters. Counter-productive.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li style="color: blue;"&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Make events public [CMUG.EVU.MEP-5] &lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;No explanation given. Doesn't seem to be necessary - &lt;a href="http://msdn.microsoft.com/en-us/library/ms229011.aspx"&gt;Event Design Page MSDN&lt;/a&gt;.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li style="color: blue;"&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Put using statements in alphabetical order [CS.USO-4]&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;VS2010 sorts usings such that &lt;a href="http://msdn.microsoft.com/en-us/library/bb514113.aspx"&gt;System.* namespaces are grouped above the rest&lt;/a&gt;.&lt;br /&gt;This rule doesn't seem to know about this. A workaround is to override this behavior in VS2010 but then that's something that each developer would have to change.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;NAMING&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;span style="color: blue;"&gt;Avoid language-specific names for members [NG.ATNC.ALSN.MEMBER-5]&lt;/span&gt; : flags up "_constaints" for containing "int"&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;span style="color: blue;"&gt;Avoid method names that conflict with keywords [NG.WC.KEYWORD.METHOD-3]&lt;/span&gt;&amp;nbsp; : Will not let you have methods called Get, Stop, Select - which are sometimes the most intuitive names.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;span style="color: blue;"&gt;Use Pascal case for class names [NG.CAPSTY.PASCAL.CLASS-5]&lt;/span&gt; : UIDriverBase is a valid name as per Design guidelines but flagged up by this rule. See&amp;nbsp; &lt;a href="http://msdn.microsoft.com/en-us/library/ms229043.aspx"&gt;Capitalization Rules for Acronyms&lt;/a&gt;.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;span style="color: blue;"&gt;Use the property's type name as part of the property name [NG.PRN.APNCTN-4]&lt;/span&gt; : This is a "Consider" not a "Do" in the guidelines. Embedding type name in the property is risky w.r.t. future refactorings (e.g. if you change the type of the property with name MonitorIPString from String to StringBuilder. Misleading.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;span style="color: blue;"&gt;Use the suffix 'EventHandler' for event handler names [NG.EVN.EHNEEH-3]&lt;/span&gt; : Broken. Here's a sample - Message: Change type of event 'X.Driver+AppLaunchedEventHander AppLaunched' or add 'EventHandler' suffix to type 'Driver+AppLaunchedEventHander'.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;span style="color: blue;"&gt;Use flags attribute for bit field enum [NG.ETN.UFABFE-3]&lt;/span&gt; : Flagged simple 1 member enum with non-plural name as bit-field enums. Broken.&lt;/span&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li style="color: blue;"&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Avoid too many function calls from a single function [OOM.FCSF-4]&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Limit of 10 is easily breached. Non-customizable. Includes property access within the method.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;span style="color: blue;"&gt;Use 'GetType()' in the 'Equals()' method implementation [PB.EQL-3]&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Does not exclude overloads of Equals. e.g. Equals(MyType t) does not need to check type of t. &lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;span style="color: blue;"&gt;Use upper case for method name with name length &amp;lt;=2 [NG.CAPSTY.UPPER.MN-5], [NG.CAPSTY.UPPER.PROP-5]&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Asks me to rename a method called At(params) to AT(params). Was not able to find any design guideline to support this.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;span style="color: blue;"&gt;Avoid public default constructor when a non-default constructor is present [CMUG.CU.PUBDEFAULTCTOR-3]&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Contradicts&amp;nbsp; &lt;span style="color: blue;"&gt;Exceptions should implement common constructors [ERR.EICC-4]&lt;/span&gt;. The exception rule won.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;span style="color: blue;"&gt;Follow the limit for Number Of Static Methods [METRICS.NOSM-1]&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;This one flagged a false +ve. Static Class had 1 static var, 3 public and 3 private methods. Rule violated: 10 is not less than 10. Refactoring often leads to lots of small private methods.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Then there was a bunch that&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;was auto-enforced by C# e.g. Name indexer 'item' or Name event accessors 'add' and 'remove'.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Some were guidelines not rules.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Some were plain out of date e.g. &lt;span style="color: blue;"&gt;Provide the same accessibility for the property and its accessors [CLS.ACAC-3]&amp;nbsp;&lt;span style="color: black;"&gt;&lt;/span&gt;&lt;/span&gt;This flags up a common pattern of properties whose setters are private. The explanation points to an outdated (.Net 1.1) version. We've have come a long way since then...&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Turned off another 80-100 too. Finally ended up with &lt;b&gt;196 / 444&lt;/b&gt; rules enabled.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;There is also a report out and code-metrics at the end too. But to summarize, &lt;/span&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;I found Parasoft dotTest to be a bit unpolished.. the infrastructure is there. &lt;/span&gt;&lt;b&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Analysis is quick enough but t&lt;/span&gt;&lt;/b&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;b&gt;he rules need to be improved. &lt;/b&gt;Not enough documentation online - except from Parasoft itself.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif; font-size: large;"&gt;Verdict: Passable, but for now prefer Code Analysis that comes bundled with Visual Studio 2010.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-977103693222030125?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/977103693222030125/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2011/11/review-parasoft-dottest-static-code.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/977103693222030125'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/977103693222030125'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2011/11/review-parasoft-dottest-static-code.html' title='Review : Parasoft DotTest Static Code Analysis'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><thr:total>0</thr:total><georss:featurename>Thane, Maharashtra, India</georss:featurename><georss:point>19.23184 72.967178</georss:point><georss:box>19.17187 72.888214 19.291809999999998 73.046142</georss:box></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-3567929067869703658</id><published>2011-09-15T12:59:00.001+05:30</published><updated>2011-09-19T15:01:35.039+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='Kata'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>String Calculator Kata : My first screencast trilogy</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;This is my attempt at Roy Osherove's popular String Calculator Katas.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;iframe allowfullscreen="" frameborder="0" height="169" src="http://player.vimeo.com/video/27977192?title=0&amp;amp;byline=0&amp;amp;portrait=0" webkitallowfullscreen="" width="300"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;a href="http://vimeo.com/27977192"&gt;TDD StringCalculator Kata - Part1&lt;/a&gt; from &lt;a href="http://vimeo.com/gishu"&gt;Gishu Pillai&lt;/a&gt; on &lt;a href="http://vimeo.com/"&gt;Vimeo&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif; font-size: large;"&gt;&lt;a href="http://vimeo.com/album/1693891"&gt;The Vimeo Album containing all 3 parts.&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;I'm using C# (VS2010+Resharper), NUnit and an IDE extension called &lt;a href="https://code.google.com/p/gishu-util/wiki/Beacons"&gt;Beacons&lt;/a&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;(the wiki might be a bit behind the downloads tab :))&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;The videos look best when you have the HD option turned on and Scaling (hover on the video - top-right) turned off.&lt;/span&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;intermediate practitioners&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;For best results : download the videos and &lt;a href="http://goo.gl/JShDQ"&gt;the subtitles&lt;/a&gt;. Use your media player with audio turned off and subtitles enabled at 2-4X.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;I don't do this (ever) so wasn't equipped with the proper audio gear (and coupled with the fact that I do not have an internet voice and can't code and speak at the same time, the audio is passable.)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;beginners&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Practice it a couple of times before watching. You'll get more out of it.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;What I learned from it:&lt;/span&gt;&lt;br /&gt;&lt;ul style="text-align: left;"&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;I need to practice more :)&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;2 modes of learning in a Kata&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;muscle memory - goal: Speed.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;exploration - goal: Possible solutions. Take different choices and see how it ends up.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Automated refactoring (e.g. Resharper for C#) rules. Knowing your IDE and keyboard shortcuts goes a long way w.r.t. productivity&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Streamline all routine work and bind them to keyboard shortcuts - like building, running tests, reusable code snippets/templates, etc&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif; font-size: x-small;"&gt;For people looking for screencasting tools on windows, I'd recommend&lt;/span&gt;&lt;br /&gt;&lt;ol style="text-align: left;"&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif; font-size: x-small;"&gt;&lt;a href="http://www.bbsoftware.co.uk/BBFlashBack_FreePlayer.aspx"&gt;BB Flashback Express&lt;/a&gt; - the free edition for screencasting. Export to AVI using ffdshow worked great for me.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif; font-size: x-small;"&gt;&lt;a href="http://www.donationcoder.com/Software/Skrommel/index.html#ShowOff"&gt;ShowOff&lt;/a&gt; - for highlighting keystrokes and chords. Keyboard Jedi wasn't too great with 64bit &amp;amp; keyboard chords (before my patience ran out).&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt; &lt;/span&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/14744716-3567929067869703658?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/3567929067869703658/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2011/09/string-calculator-kata-my-first.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/3567929067869703658'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/3567929067869703658'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2011/09/string-calculator-kata-my-first.html' title='String Calculator Kata : My first screencast trilogy'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-1039326485603346008</id><published>2011-07-30T19:49:00.006+05:30</published><updated>2011-07-31T17:06:15.962+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='Automated Tests'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><title type='text'>The A Team</title><content type='html'>&lt;span style="font-family:trebuchet ms;"&gt;Contd from &lt;/span&gt;&lt;a style="font-family: trebuchet ms;" href="http://madcoderspeak.blogspot.com/2011/07/towards-better-acceptance-test.html"&gt;the previous post&lt;/a&gt;&lt;span style="font-family:trebuchet ms;"&gt;..&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;So how do we succeed?&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-family:trebuchet ms;"&gt;Lock up Enemy #1 - Accidental Complexity&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0); font-family:trebuchet ms;font-size:130%;"  &gt;Empower teams to choose&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;All projects / teams are not the same. Different needs, different tools. This may be difficult in BigCo especially if the tools have already been bought. But make some noise - stand up for your tools, the "users" need to channel some feedback upstream to the "purchasers". &lt;/span&gt;&lt;br /&gt;&lt;ul style="font-family: trebuchet ms;"&gt;&lt;li&gt;Explore options instead of resigning to the golden hammer. Prefer tools that don't get in your way. Ones that don't require you to learn yet another proprietary language. Ability to write extensions in your team's native language is a +. This also opens avenues for developers to assist with automation work, if required.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Use existing tools instead of writing your own - they're likely to be functional, tried and tested&lt;/li&gt;&lt;li&gt;Avoid putting all eggs in one basket. Keep tools/test-runners swappable by defining layers. To migrate to a  different test runner, you should only need to migrate your thin tests  layer which calls into an automation layer below it, which does most of  the heavy lifting. More on this soon..&lt;/li&gt;&lt;/ul&gt;&lt;span style="color: rgb(0, 102, 0); font-family:trebuchet ms;font-size:130%;"  &gt;Collaboration&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;forms a reinforcing loop against Silos/Specialists. Increasing collaboration  decreases opportunities for specialization, which in turn facilitates more collaboration. Of course, the reverse is also true - Silos can finish off collaboration. Only one shall survive, you just have to choose.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-size:130%;" &gt;&lt;span style="font-family:trebuchet ms;"&gt;Outside-in / Test-first  + Wishful Thinking&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;If you've tried the XP Practice of TDD, you'd know the liberating feeling of letting the unit tests drive the design of the production code. You fix the end-goal, you make it work, make it clean and repeat.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Starting with the test prevents any bias (arising from implementation details, existing tools at your disposal, etc.) &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;ATDD is the corresponding practice at the system level. However it is not an easy practice to quickly latch on to. So work towards it in baby steps&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;For starters, concentrate on a DONE definition + writing tests first (before implementation) from the &lt;/span&gt;&lt;span style="font-weight: bold; font-family:trebuchet ms;" &gt;users' perspective&lt;/span&gt;&lt;span style="font-family:trebuchet ms;"&gt; on a piece of paper. Make sure everyone has the same idea of DONE before you start the iteration.&lt;br /&gt;As the team matures, you can even move up to ATDP (from the BDD world) where you write test before or during iteration planning &amp;amp; use them for estimation.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-size:130%;" &gt;&lt;span style="font-family:trebuchet ms;"&gt;WHAT over HOW&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Ensures that the test is at the right level of abstraction  (the ol' forest over trees adage). It makes the tests shorter and readable. It also works beautifully to bring out the intent (as opposed to the implementation) of the test.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Specify the bare minimum ; things that are relevant to the test at hand.. all other details need to be out of sight.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-size:130%;" &gt;&lt;span style="font-family:trebuchet ms;"&gt;Stable DSL for testing&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;You employ wishful thinking to imagine the ideal interface you'd like the system to expose for testing. Since the tests are another client to the system, they can also drive beneficial design changes. The tests stand-in for real users, so if the system is difficult to consume for the tests it follows that it might be for the users too. You could start with a plain C# interface to begin with and then work your way up to a custom DSL. It&lt;/span&gt;&lt;br /&gt;&lt;ul style="font-family: trebuchet ms;"&gt;&lt;li&gt;abstracts away incidental details like the GUI, underlying technology and other implementation details.&lt;/li&gt;&lt;li&gt;abstracts away the tools used for automation from the tests.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;decouples the people interested in writing tests from the automation personnel. This allows both to play to their strengths and offers the best of both worlds. e.g. the testers could define the automation interface changes for the sprint and the developers could implement them with production-code like quality.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;makes it easy to write new tests with relatively little boot-up time. Writing a test then is just combining the reusable building blocks offered by the test DSL. The tests layer is a good training ground for new hires.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:trebuchet ms;"&gt;Imagine (wishful) a robot that will operate the system for you and think of the commands that you'd issue to the robot. The set of commands are your starting point.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;e.g. robot.DoX(params) or robot.GetY()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-size:130%;" &gt;&lt;span style="font-family:trebuchet ms;"&gt;Programming Skills&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Automation is programming.  Without good programming techniques and discipline, sustainable pace would be difficult.&lt;br /&gt;This means you need to raise the bar for automation personnel and/or leverage devs. If the team lacks the skill-set required, take countermeasures... Training, get some experts onboard, etc. The average skill level of the team can also be increased by frequent pairing. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-size:130%;" &gt;&lt;span style="font-family:trebuchet ms;"&gt;Refactoring&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Your #1 weapon against complexity. Beck's 4 rules for simple design, the techniques from the Refactoring book (Martin Fowler) + the SOLID principles are a must-read. Top that off with an introductory text on programming (e.g.  Clean Code - Robert Martin) and you should be good to go.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(0, 102, 0);font-size:130%;" &gt;&lt;span style="font-family:trebuchet ms;"&gt;Good Naming &amp;amp; Discoverable Design&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Taking the time to pick good names goes a long long way. Good names make it easy to find things, facilitate understanding, help zone in on a specific area to change &amp;amp; reduce duplication&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;This also helps in being able to discover the design / API using just the IDE (learn by intellisense) and programmer intuition. Choose names that are likely to be searched. Operate by the principle of least surprise (code that works as expected the first time around); Avoid hidden side-effects. Document and use team conventions to preserve consistency.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-size:130%;" &gt;&lt;span style="font-family:trebuchet ms;"&gt;Communicate Intent / Distill the essence&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;This takes WhatOverHow to the next level. Explaining Why e.g. by extracting another "coarse" method to move up one level OR differentiating sets of inputs by using explanatory names. This reduces the test further to the essence - where the tests turn into readable system documentation... the kind that never gets out of date.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-size:130%;" &gt;&lt;span style="font-family:trebuchet ms;"&gt;Learning Curve&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Refactoring well and often keeps accidental complexity down to manageable levels. The supporting cast of Pairing, a discoverable design, intention-revealing code and a good testing DSL make it easy for new team members to learn the ropes.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;This inhibits cargo-cult behavior and the changes made are deliberate/intentional rather than hopeful. Another source of complexity wanes.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;&lt;span style="font-family:trebuchet ms;"&gt;Test Maintenance - the last frontier&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Test Maintenance like complexity can be minimized not eliminated. As complexity decreases, maintenance effort reduces too.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;The testDSL makes it possible to write-and-test the blocks once &amp;amp; use anywhere. Simple designs (no duplication, intention-revealing code, minimal classes) make maintenance much easier.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Transitively, the cost of automation goes down as well.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Let's refactor our diagram to remove the accidental nodes and edges and things get clearer now. Refactoring code is even more rewarding.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="https://picasaweb.google.com/lh/photo/1bFaBnlkrguab-rrPMUmQPcaujkF9KLSFFuJboHAXZ8?feat=embedwebsite"&gt;&lt;img src="https://lh5.googleusercontent.com/-ovrvxiCvlo4/TjU44vNBr6I/AAAAAAAABAU/Vtk45W7SlRA/s800/CostOfAutomation-Refactored.png" height="663" width="800" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-1039326485603346008?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/1039326485603346008/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2011/07/a-team.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/1039326485603346008'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/1039326485603346008'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2011/07/a-team.html' title='The A Team'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='https://lh5.googleusercontent.com/-ovrvxiCvlo4/TjU44vNBr6I/AAAAAAAABAU/Vtk45W7SlRA/s72-c/CostOfAutomation-Refactored.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-7728167958898934182</id><published>2011-07-30T11:24:00.019+05:30</published><updated>2011-07-31T16:48:46.180+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='Automated Tests'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><title type='text'>Towards better acceptance test automation...</title><content type='html'>This started out as a sketch of a &lt;a href="http://en.wikipedia.org/wiki/Causal_loop_diagram"&gt;Causal Loop Diagram&lt;/a&gt; (CLD) for bad acceptance test suites... and then it got away from me :) &lt;span style="font-size:100%;"&gt;The black arrows indicate "+ve links" e.g. Duplication  and Complexity increase/decrease together. The blue arrows ending in  dots indicate "-ve links" e.g. Refactoring and Duplication work against  each other. Increase in Refactoring causes decrease in duplication.&lt;/span&gt;&lt;br /&gt;Click on it to be able to zoom in.&lt;br /&gt;&lt;br /&gt;&lt;a href="https://picasaweb.google.com/lh/photo/jF3yC3k6_C-WybIub7zog_caujkF9KLSFFuJboHAXZ8?feat=embedwebsite"&gt;&lt;img src="https://lh5.googleusercontent.com/-dFZs6aEslz8/TjRiufX3AHI/AAAAAAAABAE/jBOrUfHe1zk/s800/CostOfAutomation.png" height="637" width="800" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;And now the thousand err... few thousand words that correspond to that picture :)&lt;br /&gt;&lt;br /&gt;I'll open with the worst-kept secret: Automation is Code. You're asking the computer to perform a set of steps to check something. That sounds like... programming. (There is also considerable overlap with unit testing.) If you have built a few non-trivial systems, you'd admit that the main challenges are minimizing accidental complexity and maximizing communication (with other humans).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;All roads lead to accidental complexity. &lt;/span&gt;&lt;br /&gt;Complexity is unavoidable for non-trivial programs. Essential complexity is that which is absolutely required to solve the problem at hand. Accidental is everything else (e.g. complexity introduced by the tools or language or algorithm used). The art is in identifying accidental complexity and minimizing it.&lt;br /&gt;&lt;br /&gt;If we just concentrate (really hard enough) at the corresponding node in the center, we see the following inward black arrows (causes).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Wrong choice of Tools&lt;/span&gt;&lt;br /&gt;You shouldn't use a hammer to unscrew a nail although it might work given the right level of persistence and resistance to pain. Sadly there are a lot of expensive 'golden hammers' being forced on QA teams. A bad tool can&lt;br /&gt;&lt;ul&gt;&lt;li&gt;get in your way.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;coerce you to go against your better judgement. e.g. forces you to write repeated boilerplate code with no facility for extracting reusable blocks; even though you know 'Duplication is Evil'.  You own the tools; don't let it be like the other way around.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;lock you in . It is prohibitively expensive to switch. The vendor can also choose to charge for enhancements and fleece you with their well-thought out pricing and support models&lt;br /&gt;&lt;/li&gt;&lt;li&gt;refuse to play with other tools. Often this leads to the need for inventing wheels (in-house) ... which end up kinda square. Meanwhile the other folks using those round existing (open-source?) wheels are racing ahead&lt;/li&gt;&lt;li&gt;can breed specialists (for lack of a better term. &lt;a href="http://testobsessed.com/2010/07/19/why-test-automation-costs-too-much/"&gt;Thanks Elizabeth H.&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;drag in other relatives (tools from the same vendor). Go to bullet 1.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size:130%;"&gt;Emergence of the "Elite" / specialists / silos&lt;/span&gt;&lt;br /&gt;Cumbersome tools can raise certain specialists to an elite status. These are the only people who dare to touch the codebase ; no one else understands it / knows how to use the tools or run the tests. All the automation work funnels through them. They become a difficult bottleneck limiting team throughput. Imaginary walls pop up, they may have illusions of grandeur and work in isolation unquestioned. Now you have a knowledge silo in the team (god forbid they leave or fall sick or take a vacation :).&lt;br /&gt;Worse as the diagram shows, they form a &lt;span style="font-weight: bold;"&gt;reinforcing loop&lt;/span&gt; with accidental complexity. The complexity precludes the non-elite from making changes reinforcing the specialist status. The specialists continue to add complexity unchecked... widening the gap further.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Cargo-Cults&lt;/span&gt;&lt;br /&gt;If this is the first time you've come across this term, read &lt;a href="http://blogs.msdn.com/b/ericlippert/archive/2004/03/01/82168.aspx"&gt;Eric Lippert's excellent post&lt;/a&gt;.&lt;br /&gt;They form another &lt;span style="font-weight: bold;"&gt;reinforcing loop&lt;/span&gt; with complexity. Lots of cult members furiously spot-fixing without understanding the design or "Why did that work?"  leads to the design turning opaque. Loss of structure leads to &lt;a href="http://www.laputan.org/mud/mud.html"&gt;BBOMs&lt;/a&gt;, which breed the next generation of clueless fixers.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Speculative Architecture&lt;/span&gt;&lt;br /&gt;Over-engineering is a leading cause of accidental complexity. Designing for future needs isn't as rampant as on the development side of the fence where the architects live.&lt;br /&gt;Reuse is best when extracted out of 2 or more functioning clients - designing for reuse inside-out usually leads to abstractions that make all clients mad.&lt;br /&gt;Intricate interfaces/classes/abstractions  with non-intuitive names all add to the complexity and lead to a steep learning curve for new team members. Not sure who I am quoting here but - "you really can't use what you do not understand" so make sure that the code is within the grasp of the team supposed to work on it.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Duplication&lt;/span&gt;&lt;br /&gt;It is the easiest problem to fix and somehow the most widespread code smell. Changing something in one place is a breeze.. changing it in 47 places identically is a mistake-prone chore. Doing this every few weeks is ...  inviting bugs over.&lt;br /&gt;Duplication forms another &lt;span style="font-weight: bold;"&gt;reinforcing loop&lt;/span&gt; with accidental complexity. Greater the duplication, greater the confusion / complexity. As the complexity goes up, it can be harder to find the right way/spot reusable pieces. People write their own copy  - duplication goes up!&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;Test-After&lt;/span&gt;&lt;br /&gt;This is a throw-back from the way things used to be. Programmers code till they are happy or time runs out. Throw it over the wall to QA. QA finds bugs, throws it back over. This continues for a while.&lt;br /&gt;&lt;br /&gt;Cut to year 2011. The wall has been torn down. We can't wait till the development team is done to begin with automation. There won't be enough time. Even if you manage with some end-of-sprint heroics, you're likely to miss out on exploratory / attribute testing. The automation isn't likely to be the best either - in fact it is most probably going to be "the first thing that worked" (TM) considering the pressure and not wanting to be the ones that let the team down. The bugs - they live! (and yes, they're all out of bubblegum)&lt;br /&gt;&lt;br /&gt;Test-after tests are usually long granular only-machine-readable scripts that over-specify and coupled to the GUI to boot! After about 4 sprints of heroics, the team is tired and complexity is taking the elevator to the top! Stop and change something.. the next sprint is NOT going to be better.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;The heavies  : Wrong Tests, Rework, Bad tests, Maintenance, $$$.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Wrong tests&lt;/span&gt;&lt;br /&gt;They're usually a symptom of lack of communication/collaboration.&lt;br /&gt;It's bad enough that the team built and wrong thing, you also expended a significant amount time &amp;amp; money in automating it &amp;amp; other testing. Now you got to do it all over again - Rework. That is resources could have been used to give the customer more features. There is no excuse for getting the tests wrong.&lt;br /&gt;Eliminate middle-men &amp;amp; barriers in the communication path. Get the trinity of the customer+tester+developer to start talking! If the customer doesn't have the time to explain things to the team, quantify the implications in monetary terms. You will have someone's attention.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Bad tests&lt;/span&gt;&lt;br /&gt;Write a failing test, how hard can that be? But what if I say write a failing test that is automated, thorough, repeatable, independent, precise and employs the best programming ideas? And did I mention it has to run as FAST as possible.&lt;br /&gt;It takes effort, programming skill and discipline. Expecting historically non-coding testers to jump this chasm on their own in a short-time frame is crazy.&lt;br /&gt;&lt;br /&gt;Getting this wrong can lead to tests that are&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Spotty - the tests aren't thorough. As a result, bugs keep coming through the net of automated tests&lt;/li&gt;&lt;li&gt;Repeatable - the tests give you different results each time you run it. Given enough time, this can irreparably damage trust in the tests &amp;amp; consequently the testers. The tests turn into another hurdle for the development team.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Dependent - the tests have insider information about each other. Run it alone - it fails. Run the whole suite - everything passes. So to check one of them, you need to run and wait for a whole bunch of them.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Fragile - the existing tests keep breaking all the time. A tiny flutter in a remote corner of the system causes loads of tests to break.&lt;/li&gt;&lt;li&gt;Slow - "this thing usually takes 2 mins to comeback. But sometimes it takes upto 3. Let's Thread.Sleep for 5 in the test just to be safe." So "usually" you're twiddling thumbs for 3min/test... and for 100+ tests, that comes to 5 hours of waiting. What's the way out? (Hint: No. The solution is not to run it at night.)&lt;/li&gt;&lt;li&gt;Over-specification - the tests are a cure for insomnia. KLoC after KLoC of prescriptions for the computer. &lt;/li&gt;&lt;li&gt;Messy - It's code. Possibilities are endless... especially if you factor in some constant deadline pressure and no training&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="color: rgb(153, 0, 0); font-weight: bold;"&gt;A bad test always comes back! &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Maintenance and Cost of Automation&lt;/span&gt;&lt;br /&gt;Maintaining a bad codebase is only better than maintaining bad tests. No one wants to babysit a tantrum throwing CI build server every day.&lt;br /&gt;&lt;br /&gt;Automation costs real money. All "accidental maintenance" is money lost. Since the end-goal is to make money, it follows that automation has to have ROI. It has to pull its weight. If not it might take the team down with it.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:180%;"&gt;Is there any good news at all in this post?&lt;/span&gt;&lt;br /&gt;No but &lt;a href="http://madcoderspeak.blogspot.com/2011/07/a-team.html"&gt;the next one&lt;/a&gt; does :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-7728167958898934182?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/7728167958898934182/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2011/07/towards-better-acceptance-test.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/7728167958898934182'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/7728167958898934182'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2011/07/towards-better-acceptance-test.html' title='Towards better acceptance test automation...'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='https://lh5.googleusercontent.com/-dFZs6aEslz8/TjRiufX3AHI/AAAAAAAABAE/jBOrUfHe1zk/s72-c/CostOfAutomation.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-5398431520801103767</id><published>2011-07-01T10:58:00.006+05:30</published><updated>2011-07-30T11:24:06.296+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='Automated Tests'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><title type='text'>Automated tests != Free Lunch</title><content type='html'>&lt;span style=";font-family:verdana;font-size:85%;"  &gt;Disclaimer: I'm a proponent of XP and truly believe it has made me a much better programmer. This post just aims to let readers see through the fog-of-agile caused due to data-transfer loss as it passes from person to person. Please do not misinterpret this as an anti-agile rant. I'm just saying it doesn't work out always unless you're willing to put in the effort to make the change.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Legend&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-family:arial;" &gt;What you hear… (good) the Promised Land&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;What was left unsaid (bad.. or downright ugly)&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-family:arial;" &gt;You have an automated regression-safety net to make future changes. Make a change, Push a button and you will know if you broke anything. CI can provide near instant-feedback. Better confidence. &lt;/span&gt; &lt;ul style="font-family: trebuchet ms;"&gt;&lt;li&gt;You have 2-3X the code to maintain. If you have people who don’t care/are too busy/ not passionate about code quality and writing good tests, the tests are the first to put a chokehold on your productivity. Bad tests are as good as (or possibly worse than) having no tests. You could see yourself in a situation where a section of your team is permanently siphoned to keeping the build/tests green. This turns into a daily bottleneck. &lt;span style="font-weight: bold;"&gt;Tests need to be self-checking, thorough, readable, professionally written, independent, repeatable, concise and FAST. All this takes effort!&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-family:arial;" &gt;Documentation - the tests can be "live specs" of the application - They never get out of date like documentation.&lt;/span&gt;&lt;br /&gt;&lt;ul style="font-family: trebuchet ms;"&gt;&lt;li&gt;It takes a significant level of discipline and skill to write readable spec-tests. An essential skill :to see the What and Why without getting entangled in the How. Most teams get this wrong... without noticing it.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Sidenote: The practice of ignoring failing tests is criminal (but usually not punished accordingly) and can lead to misleading specs.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-family:arial;" &gt;Quality &amp;amp; Productivity: Leads to high-quality production code. Fewer Bugs. More features added / unit time (because you spend less time in debugging and manual testing)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;IF you let the tests drive/shape your design (ATDD and TDD). Client-first design is an unstated requirement.&lt;/li&gt;&lt;li&gt;The quality of the code is usually a direct reflection of the people writing it. This means you need craftsmen (&amp;gt; 30-50% of a team) and NOT armies of cargo-cult programmers.&lt;/li&gt;&lt;li&gt;If you're using automated tests exclusively for regression (or getting your 'agile badge'), you'll slowly grind to a halt. Writing tests for "untestable blobs implemented from a non-negotiable handed-down paper design" is frustrating. People can be stuck on “how do I test this?” – Usually leads to silent trade-offs &amp;amp; non-thorough test which will let in bugs and put you in the net negative w.r.t. productivity.&lt;/li&gt;&lt;/ul&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-family:arial;" &gt;Less rework/thrashing: The dialogue / conversation (that you have with the customer to come up with the acceptance tests) makes it highly likely that you’re building the right thing..&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;ul&gt;&lt;li&gt;Assumes that the customers want to collaborate with the developers and testers. This is not often true.. Real users are sometimes real hard-to-find. Even if you manage to snag one of them,  you can only procure a small slice of their time. Real users rarely want to write tests.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;If the customers give a “vision” and delegate the responsibility of mapping them to executable specs to the technical team (or worse the QA/testers), you still run the risk of “This is not what I asked for” late in the game. Regular demos may help shorten the feedback time..  but you may still waste an iteration.The magic potion here is collaboration and conversation.. the tests are just a beneficial byproduct.&lt;/li&gt;&lt;/ul&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-family:arial;" &gt;Simple: Red-Green-Refactor. How hard can that be?&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;ul&gt;&lt;li&gt;Sounds simple.. but is deceptive. True OO is a minority sport. Refactoring is a skill that you need to work on. Off the job practice is mandatory.&lt;br /&gt;You may need to "hire" a good coach for an extended period (I'd say 6 months-1 release) to get the team rolling. Spot trainings/Just-in-time learning won't work for most teams. &lt;/li&gt;&lt;/ul&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-5398431520801103767?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/5398431520801103767/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2011/07/automated-tests-free-lunch.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/5398431520801103767'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/5398431520801103767'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2011/07/automated-tests-free-lunch.html' title='Automated tests != Free Lunch'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-5064126477307403685</id><published>2011-04-03T10:18:00.008+05:30</published><updated>2011-04-03T14:10:09.537+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='.net'/><category scheme='http://www.blogger.com/atom/ns#' term='Logging'/><category scheme='http://www.blogger.com/atom/ns#' term='Jumpstart'/><title type='text'>Enterprise Library Logging vs Log4Net for a rolling file log : jumpstart and a showdown!</title><content type='html'>I was looking for a rolling file log and couldn't make my mind between the two. So I embarked on a small quest to see which one is easier to learn and work with.&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;First up I'm gonna create a VS2010 Console application.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Enterprise Library&lt;/span&gt;&lt;br /&gt;Ok first up we need to download the latest drop of EnterpriseLibrary which is currently &lt;a href="http://msdn.microsoft.com/en-us/library/ff632023.aspx"&gt;5.0&lt;/a&gt;. Run through the install.&lt;br /&gt;Strafe the web a bit. Okay.. we need an app.config file in our project with some XML muck. Thankfully MS has a GUI tool to help us write it - it's named EntLibConfig.NET4.exe and lies in the EntLib install folder. Open it up and we can either create/load an app.config file.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Main Menu &amp;gt; Blocks &amp;gt; Add Logging Block&lt;/li&gt;&lt;li&gt;An Event logging Listener is added by default (2nd column). Delete it and add a Rolling Flat File Trace Listener - click the Plus sign next to 'Logging Target Listeners' caption.&lt;/li&gt;&lt;li&gt;Next go on a property-setting spree. It should end up like this&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://lh6.googleusercontent.com/_nxgDpneh8yk/TZgNFseTWFI/AAAAAAAAA8A/qvfUkSo2IzE/s800/entLib-Config.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 800px; height: 538px;" src="https://lh6.googleusercontent.com/_nxgDpneh8yk/TZgNFseTWFI/AAAAAAAAA8A/qvfUkSo2IzE/s800/entLib-Config.png" alt="" border="0" /&gt;&lt;/a&gt;We'll work our way right to left.&lt;br /&gt;Third Column : TextFormatter.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Template = {timestamp(local)} :  {severity} - {message}.&lt;/li&gt;&lt;/ul&gt;The ellipses button opens up a editor which has a dropdown with all the special placeholder incantations to insert all sorts of informative bits into your log message. The default template by the way is pretty detailed for a default.&lt;br /&gt;&lt;br /&gt;Second Column : Rolling flat file trace listener&lt;br /&gt;&lt;ul&gt;&lt;li&gt;File Name -&amp;gt; rolling-with-entlib.log&lt;/li&gt;&lt;li&gt;Formatter - choose TextFormatter (which is present by default. Else add one in the third column via the context menu.) and you should see a link between the trace listener and the formatter.&lt;/li&gt;&lt;li&gt;Max Archive Files - set to 2. Older messages will be sent to an archive file.&lt;/li&gt;&lt;li&gt;Message Footer, Header - clear out.&lt;/li&gt;&lt;li&gt;Roll Interval -&amp;gt; None&lt;/li&gt;&lt;li&gt;Roll Size KB -&amp;gt; 200&lt;/li&gt;&lt;/ul&gt;First column : Logging category.&lt;br /&gt;By default, a 'General' logging category is added. I'll stick to that for simplicity (but you could add more of your own). Configure the Listeners property  of the category to point to the rolling flat file listener. You should see another link.&lt;br /&gt;We need one more link (the last I promise) to make the config valid. Open up the 'Logging errors &amp;amp; warnings' and make it point to the same listener. Another link appears and we're done. Save the file.&lt;br /&gt;&lt;br /&gt;Jump back into the IDE. Add a reference to the Microsoft.Practices.EnterpriseLibrary.Logging from the .NET tab. Write ourselves a new PSVM method with&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;Logger.Write(&lt;span class="str"&gt;"Dilshan flings himself for the catch to send Kohli back!"&lt;/span&gt;, &lt;span class="str"&gt;"General"&lt;/span&gt;, 0, 0, TraceEventType.Critical);&lt;br /&gt;Logger.Write(&lt;span class="str"&gt;"MS Dhoni walks in to steady the innings."&lt;/span&gt;, &lt;span class="str"&gt;"General"&lt;/span&gt;, 0, 0, TraceEventType.Information);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Log4Net&lt;/span&gt;&lt;br /&gt;Looks like we need &lt;a href="http://logging.apache.org/log4net/download.html"&gt;the binaries&lt;/a&gt; and ... yup.. some more XML. But there's no GUI to help us this time around. However there is a kind soul on the internet writing tutorials &lt;a href="http://www.beefycode.com/post/Log4Net-Tutorial-pt-1-Getting-Started.aspx"&gt;at BeefyCode.com&lt;/a&gt;. Two thumbs way up! By Part 5 I think I know all I need... for now.&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;configSections&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;section&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="log4net"&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="log4net.Config.Log4NetConfigurationSectionHandler, log4net"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;configSections&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;log4net&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;appender&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="RollingFileAppender"&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="log4net.Appender.RollingFileAppender"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;layout&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="log4net.Layout.PatternLayout"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;conversionPattern&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="%date %-5level- %message%newline"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;layout&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;file&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="rolling-with-log4net.log"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;appendToFile&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="true"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;rollingStyle&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="Size"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;maxSizeRollBackups&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="1"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;maximumFileSize&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="200KB"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;staticLogFileName&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="true"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;appender&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;root&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;level&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="ALL"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;appender-ref&lt;/span&gt; &lt;span class="attr"&gt;ref&lt;/span&gt;&lt;span class="kwrd"&gt;="RollingFileAppender"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;root&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;log4net&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;A quick summary: Log4Net has appenders (instead of EntLib's trace listeners) whose properties need to be set. A root node controls the level of logging + a reference to the appender to use. The PatternLayout node controls how the message is logged (akin to EntLib's formatter template property) with the &lt;a href="http://www.beefycode.com/post/Log4Net-Tutorial-pt-4-Layouts-and-Patterns.aspx"&gt;magic placeholders&lt;/a&gt;. That's it.&lt;br /&gt;&lt;br /&gt;Back to the IDE. Add a reference to log4net.dll.&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;log4net.Config.XmlConfigurator.Configure();&lt;br /&gt;var logger = log4net.LogManager.GetLogger(&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(Program)); // Program is the name of my entry point class&lt;br /&gt;&lt;br /&gt;logger.Error(&lt;span class="str"&gt;"Dilshan flings himself for the catch to send Kohli back!"&lt;/span&gt;);&lt;br /&gt;logger.Info(&lt;span class="str"&gt;"MS Dhoni walks in to steady the innings."&lt;/span&gt;);&lt;br /&gt;&lt;/pre&gt;That's all there is to it. I had to change the project's target framework to ".Net Fwk 4" for the build to succeed. The client profile doesn't have System.Web that log4net needs for some reason.&lt;br /&gt;&lt;br /&gt;Here's how it looks in the log files (I added a running counter into the message)&lt;br /&gt;&lt;pre&gt;REM This is Log4Net *********&lt;br /&gt;2011-04-03 10:30:52,871 ERROR- #499577 Dilshan flings himself to send Kohli back!&lt;br /&gt;2011-04-03 10:30:52,911 INFO - #499577 MS Dhoni walks in to steady the innings.&lt;br /&gt;&lt;br /&gt;REM and here is EntLib *********&lt;br /&gt;4/3/2011 10:29:44 AM :  Information - #499773 MS Dhoni walks in to steady the innings.&lt;br /&gt;4/3/2011 10:29:44 AM :  Critical - #499774 Dilshan flings himself to send Kohli back!&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Showdown!&lt;/span&gt;&lt;br /&gt;Things that I noted from this limited experiment:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;EntLib has a nice config tool. Log4net could have one too but I couldn't find any. To be fair, the xml muck for log4net is simpler to write by hand  and shorter by about 30%.&lt;/li&gt;&lt;li&gt;It's easy to tweak the amount of logging via an xml file edit.  You tweak the 'Minimum Severity property for the Logging category in EntLib5.0 ; the root/level element's value attribute in Log4Net.&lt;/li&gt;&lt;li&gt;Log4Net is 3x-5x faster from the rolling file burst logging tests that I did. Although it probably doesn't matter for most purposes.&lt;/li&gt;&lt;li&gt;Log4Net also has a smaller assembly footprint - you just need one DLL. EntLib will drag in 4 dependencies ; additional EntLib DLLs.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;logger.Info("We just won the ICC World Cup! Yay!! Logging out...")&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-5064126477307403685?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/5064126477307403685/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2011/04/enterprise-library-logging-vs-log4net.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/5064126477307403685'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/5064126477307403685'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2011/04/enterprise-library-logging-vs-log4net.html' title='Enterprise Library Logging vs Log4Net for a rolling file log : jumpstart and a showdown!'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='https://lh6.googleusercontent.com/_nxgDpneh8yk/TZgNFseTWFI/AAAAAAAAA8A/qvfUkSo2IzE/s72-c/entLib-Config.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-2903427654535108654</id><published>2011-02-01T08:25:00.015+05:30</published><updated>2011-02-05T12:13:05.041+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Flash Cards Kata and the transformation priority premise</title><content type='html'>&lt;span style=";font-family:trebuchet ms;font-size:130%;"  &gt;&lt;span style="font-size:100%;"&gt;I began the new year by resolving to complete the &lt;a href="http://www.gigamonkeys.com/book/"&gt;PCL (&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;a href="http://www.gigamonkeys.com/book/"&gt;&lt;span style=";font-size:130%;" &gt;&lt;span style="font-size:100%;"&gt;Peter Siebel's) &lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span style=";font-family:trebuchet ms;font-size:130%;"  &gt;&lt;span style="font-size:100%;"&gt;&lt;a href="http://www.gigamonkeys.com/book/"&gt;book&lt;/a&gt;. Around the same time, another &lt;a href="http://cleancoder.posterous.com/the-transformation-priority-premise"&gt;interesting post by Uncle Bob&lt;/a&gt; appeared on the WWW. A discussion on the TDD yahoogroups spurred me to try a Kata - two-sided Flash Cards.&lt;br /&gt;&lt;br /&gt;Looked easy enough to test my new-found Lisp skills. Although I was not consciously choosing the next test / step based on the transformation priority, I was curious to know if I had been doing it all along without knowing it.&lt;br /&gt;&lt;br /&gt;This innocuous looking kata had me stuck initially - what is the right first step? Trash-canned the first couple of attempts. The third attempt was slow but I succeeded. I did it again in C# just to see if the language had any bearing on my method. This time I was faster because I was familiar with the trail now.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;ol&gt;&lt;li&gt;&lt;span style=";font-family:trebuchet ms;font-size:130%;"  &gt;&lt;span style="font-size:100%;"&gt;I am not wiser with regard to the priority premise - I found I used &lt;span style="font-style: italic;"&gt;a bunch of transformations that were not part&lt;/span&gt;&lt;span&gt; (bold)&lt;/span&gt;&lt;span style="font-style: italic;"&gt; of the original list &lt;/span&gt;&lt;span&gt;(shown in blue below)&lt;/span&gt;&lt;span style="font-style: italic;"&gt;. As a result, their priorities are unknown&lt;/span&gt;. This was the proverbial rain on my parade.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=";font-family:trebuchet ms;font-size:130%;"  &gt;&lt;span style="font-size:100%;"&gt;Also in the C# variant, I found a couple of tests where I needed &lt;span style="font-style: italic;"&gt;multiple transformations to get to the next green&lt;/span&gt; &amp;amp; I could not figure out a smaller test.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;span style=";font-family:trebuchet ms;font-size:130%;"  &gt;&lt;span style="font-size:85%;"&gt;Note: Check the "speaker notes" in case things get dense especially with the Lisp one. Use the menu button at the bottom-right to get to the presentation link&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Attempt#1 Flash Cards Kata in Lisp&lt;/span&gt;&lt;br /&gt;&lt;iframe src="https://docs.google.com/present/embed?id=dcx49m86_81gv5kcnf3&amp;amp;interval=5&amp;amp;size=l" frameborder="0" height="559" width="700"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;    TEST User should be asked a question&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;    &lt;span style="font-weight: bold;"&gt;{} =&gt; statement&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:trebuchet ms;"&gt;TEST &lt;/span&gt;&lt;span style="font-family:trebuchet ms;"&gt;A right ans should be confirmed&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;    &lt;span style="font-style: italic; font-weight: bold;"&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;P5 (statement-&gt;statements) adding more unconditional statements&lt;/span&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:trebuchet ms;"&gt;TEST &lt;/span&gt;&lt;span style="font-family:trebuchet ms;"&gt;A wrong ans should be corrected&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;    &lt;span style="font-weight: bold; font-style: italic; color: rgb(0, 0, 153);"&gt;P6 (unconditional-&gt;if) splitting the execution path&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:trebuchet ms;"&gt;TEST &lt;/span&gt;&lt;span style="font-family:trebuchet ms;"&gt;Diff card and a right ans&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;    &lt;span style="font-weight: bold; font-style: italic; color: rgb(0, 0, 153);"&gt;P4 (constant-&gt;scalar) replacing a constant with a variable or an argument&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:trebuchet ms;"&gt;TEST &lt;/span&gt;&lt;span style="font-family:trebuchet ms;"&gt;Diff card and a wrong ans&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;    &lt;span style="font-weight: bold;"&gt;constant =&gt; expr&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:trebuchet ms;"&gt;TEST &lt;/span&gt;&lt;span style="font-family:trebuchet ms;"&gt;Multiple cards&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;    &lt;span style="font-weight: bold;"&gt;{} =&gt; loop (statement)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:trebuchet ms;"&gt;TEST &lt;/span&gt;&lt;span style="font-family:trebuchet ms;"&gt;Answers are case insensitive&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;    &lt;span style="font-weight: bold;"&gt;exprX =&gt; exprY&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:trebuchet ms;"&gt;TEST &lt;/span&gt;&lt;span style="font-family:trebuchet ms;"&gt;Answers can have leading/trailing whitespace&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;    &lt;span style="font-weight: bold;"&gt;value =&gt; expr&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;  &lt;span style=";font-family:trebuchet ms;font-size:130%;"  &gt;Attempt#2 Flash Cards Kata in C#&lt;/span&gt;&lt;iframe src="https://docs.google.com/present/embed?id=dcx49m86_828sp82df8&amp;amp;interval=5&amp;amp;size=l" frameborder="0" height="559" width="700"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;TEST &lt;/span&gt;&lt;span style="font-family:trebuchet ms;"&gt;User is asked the question&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;    &lt;span style="font-weight: bold; font-style: italic; color: rgb(0, 0, 153);"&gt;P2 nil -&gt; constant&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:trebuchet ms;"&gt;TEST &lt;/span&gt;&lt;span style="font-family:trebuchet ms;"&gt;User is asked another question (triangulate)&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;    &lt;span style="font-weight: bold;"&gt;{} =&gt; statement&lt;/span&gt;  *** Play()&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;    &lt;span style="font-weight: bold;"&gt;constant =&gt; field&lt;/span&gt; *** LastQuestionAsked&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;    &lt;span style="font-weight: bold;"&gt;void =&gt; statement&lt;/span&gt; *** Ask() - is there a smaller step here?&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:trebuchet ms;"&gt;TEST &lt;/span&gt;&lt;span style="font-family:trebuchet ms;"&gt;A correct ans is confirmed&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;    &lt;span style="font-weight: bold; font-style: italic; color: rgb(0, 0, 153);"&gt;P2 nil -&gt; constant&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:trebuchet ms;"&gt;TEST &lt;/span&gt;&lt;span style="font-family:trebuchet ms;"&gt;A wrong ans is corrected&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;    &lt;span style="font-weight: bold; font-style: italic; color: rgb(0, 0, 153);"&gt;P5 (unconditional-&gt;if) splitting the execution path&lt;/span&gt; *** Play()&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;    &lt;span style="font-weight: bold; font-style: italic; color: rgb(0, 0, 153);"&gt;P4 (statement-&gt;statements) adding more unconditional statements&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;    &lt;span style="font-weight: bold;"&gt;nil =&gt; expr&lt;/span&gt; *** User.WhoAnswers&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;    &lt;span style="font-weight: bold;"&gt;field assignment&lt;/span&gt; *** User.ctor&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;    &lt;span style="font-weight: bold;"&gt;constant =&gt; field&lt;/span&gt; *** User.LastConfirmationReceived&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;    &lt;span style="font-weight: bold;"&gt;void =&gt; statement&lt;/span&gt; *** User.Notify&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:trebuchet ms;"&gt;TEST &lt;/span&gt;&lt;span style="font-family:trebuchet ms;"&gt;A diff question and a right answer&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;    &lt;span style="font-weight: bold; font-style: italic; color: rgb(0, 0, 153);"&gt;P4 constant =&gt; scalar arg&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:trebuchet ms;"&gt;TEST &lt;/span&gt;&lt;span style="font-family:trebuchet ms;"&gt;A diff question and a wrong ans&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;    &lt;span style="font-weight: bold;"&gt;constant =&gt; expression&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:trebuchet ms;"&gt;TEST &lt;/span&gt;&lt;span style="font-family:trebuchet ms;"&gt;Two cards&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;    &lt;span style="font-weight: bold;"&gt;{} =&gt; statements&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:trebuchet ms;"&gt;TEST &lt;/span&gt;&lt;span style="font-family:trebuchet ms;"&gt;Multiple cards&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;    &lt;span style="font-weight: bold;"&gt;{} =&gt; loop&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;    &lt;span style="font-weight: bold; font-style: italic; color: rgb(0, 0, 153);"&gt;P4 (statement-&gt;statements) adding more unconditional statements&lt;/span&gt; *** User&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;    &lt;span style="font-weight: bold;"&gt;field assignment&lt;/span&gt; *** User.ctor&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:trebuchet ms;"&gt;TEST &lt;/span&gt;&lt;span style="font-family:trebuchet ms;"&gt;Case insensitive answers&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;    &lt;span style="font-weight: bold;"&gt;exprX =&gt; exprY&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:trebuchet ms;"&gt;TEST &lt;/span&gt;&lt;span style="font-family:trebuchet ms;"&gt;Trim leading/trailing spaces&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;    &lt;span style="font-weight: bold;"&gt;value =&gt; expr&lt;/span&gt;&lt;/span&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/14744716-2903427654535108654?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/2903427654535108654/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2011/02/flash-cards-kata-and-transformation.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/2903427654535108654'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/2903427654535108654'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2011/02/flash-cards-kata-and-transformation.html' title='Flash Cards Kata and the transformation priority premise'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-4099571514871899857</id><published>2010-12-15T12:18:00.004+05:30</published><updated>2010-12-15T12:47:50.091+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='conversations-of-note'/><title type='text'>The way of the unusual architect - Dan North</title><content type='html'>An &lt;a href="http://www.infoq.com/presentations/Simplicity-Architect"&gt;enlightening talk&lt;/a&gt; on 'how the human mind works and its corollaries on how programmers work' from the wise Dan North - founder-leader of the BDD camp..&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;...and so you go from something that was fit for purpose but a little bit ugly to something that never quite delivers. Who here has been involved in what I call a 2-year rewrite anti-pattern ? So we go to the business and we say&lt;br /&gt;&lt;br /&gt;Ok.We will rewrite out entire system for  some period of 2 years and then everything will be good.&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;'Wait hang on. What will we get after 2 years?' &lt;/span&gt;&lt;br /&gt;Exactly what you've got now.&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;'Right... and during that 2 years..' &lt;/span&gt;&lt;br /&gt;Oh we're locked down! We can't do anything else for you.&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;'Ok. So you're telling us that we should pay you for 2 years to go no further than we are now and you won't be able to do anything else'. &lt;/span&gt;&lt;br /&gt;No.. that's pretty much it.&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;'Okay...'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;and we call that enterprise architecture.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;He had me there 3 mins into the talk. Recommended&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-4099571514871899857?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/4099571514871899857/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2010/12/way-of-unusual-architect-dan-north.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/4099571514871899857'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/4099571514871899857'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2010/12/way-of-unusual-architect-dan-north.html' title='The way of the unusual architect - Dan North'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-80506866926421907</id><published>2010-12-04T02:45:00.002+05:30</published><updated>2011-09-15T12:39:22.040+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='VSX'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Beacons - a VS 2010 Extension for TDD</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Just uploaded an early version of a TDD visualization extension that I've been working on in my free time. Get an early version of Beacons from the google code project &lt;a href="http://code.google.com/p/gishu-util/wiki/Beacons"&gt;here&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;The extension only works with NUnit currently. You specify a file path to your NUnit test results file path (which is normally a TestResults.xml file in your .dll/.nunit folder) and you're all set to go.&lt;br /&gt;It can't listen to Resharper test-runner yet. (yet.. if I can figure out how to tap in, should be not an issue.)&lt;/div&gt;&lt;br /&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;To see it in action, check out this video - switch to fullscreen HD&lt;br /&gt;&lt;br /&gt;&lt;iframe allowfullscreen="" frameborder="0" height="450" src="http://player.vimeo.com/video/27977192?title=0&amp;amp;byline=0&amp;amp;portrait=0" webkitallowfullscreen="" width="800"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;a href="http://vimeo.com/27977192"&gt;TDD StringCalculator Kata - Part1&lt;/a&gt; from &lt;a href="http://vimeo.com/gishu"&gt;Gishu Pillai&lt;/a&gt; on &lt;a href="http://vimeo.com/"&gt;Vimeo&lt;/a&gt;.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Shift+Alt+B, H - Change hats (adding behavior hat OR refactoring hat)&lt;/li&gt;&lt;li&gt;Shift+Alt+B, P - Play/Pause (when you need to take a break)&lt;/li&gt;&lt;/ul&gt;If you give it a fair try, I'd love to hear from you. Particularly I'm interested in finding patterns (so share end-of-session screenshots)&lt;br /&gt;More ideas, comments, suggestions - feedback of any kind is welcome.. Post away at &lt;a href="http://groups.google.com/group/beacons-tdd"&gt;http://groups.google.com/group/beacons-tdd&lt;/a&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/14744716-80506866926421907?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/80506866926421907/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2010/12/beacons-vs-2010-extension.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/80506866926421907'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/80506866926421907'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2010/12/beacons-vs-2010-extension.html' title='Beacons - a VS 2010 Extension for TDD'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><thr:total>0</thr:total><georss:featurename>Thane, Maharashtra, India</georss:featurename><georss:point>19.194459565404916 72.98492431640625</georss:point><georss:box>18.870224065404916 72.51800531640625 19.518695065404916 73.45184331640625</georss:box></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-5524939929179693101</id><published>2010-11-23T17:26:00.005+05:30</published><updated>2010-11-23T17:39:47.387+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='FIT / Fitnesse'/><category scheme='http://www.blogger.com/atom/ns#' term='ATDD'/><title type='text'>ScenarioLibrary, LibraryTables with Slim Scenarios : Avoid fixture method explosion !</title><content type='html'>Assuming: working knowledge of Fitnesse.&lt;br /&gt;&lt;br /&gt;I've been recommending &lt;a href="http://fitnesse.org/FitNesse.UserGuide.SliM.ScenarioTable"&gt;Slim Scenarios&lt;/a&gt; for a while (primarily because they are the Fitnesse equivalent of reusable blocks (methods/functions in your favourite programming language) i.e. tables that can be called from other tables. {Actually they are akin to macro expansion.. but that's nitpicking!)&lt;br /&gt;&lt;br /&gt;However soon I ran into a problem, the scenario steps translate into method calls onto the backing fixture class.&lt;br /&gt;e.g.&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;|scenario         |play  movie|pathToMovie|&lt;span class="kwrd"&gt;on&lt;/span&gt; home theatre|&lt;br /&gt;|enter            |HDMI1      |mode &lt;span class="kwrd"&gt;on&lt;/span&gt; tv                 |&lt;br /&gt;|enter            |DTV/CBL    |mode &lt;span class="kwrd"&gt;on&lt;/span&gt; avr                |&lt;br /&gt;|&lt;span class="kwrd"&gt;set&lt;/span&gt; avr volume &lt;span class="kwrd"&gt;to&lt;/span&gt;|-25        |dB                         |&lt;br /&gt;|navigate menu &lt;span class="kwrd"&gt;to&lt;/span&gt; |@pathToMovie                           |&lt;br /&gt;|press            |play       |&lt;span class="kwrd"&gt;on&lt;/span&gt; media player            |&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now whenever I call this scenario, the fixture methods 'enterModeOnTv', 'enterModeOnAvr', etc. need to be present on the fixture class. So if Fixtures A, B, c call this scenario, All of them need these methods on them. Bummer!&lt;br /&gt;&lt;br /&gt;Now the initial response was to extract these methods onto a helper class. Still I'd need to write some delegating methods on each fixture to delegate to the extracted class. So I raise my hand, admit my ignorance and post to the fitnesse forums. The experts answer in a flash!&lt;br /&gt;&lt;br /&gt;The magic answer is the &lt;a href="http://fitnesse.org/FitNesse.UserGuide.SliM.LibraryTable"&gt;Library Table&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;FrontPage.HomeTheatreTests.SetUp&lt;/span&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;|library     |&lt;br /&gt;|television  |&lt;br /&gt;|avr         |&lt;br /&gt;|media player|&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The Library table specifies a list of class that should be checked in case the fixture does not contain the required method. So in this case, the order in which the classes would be checked would be [Fixture &gt; MediaPlayer &gt; Avr &gt; Television]. If a matching method is found in any of these classes, the step is resolved.. No more delegating methods!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;This allows me to have cohesive helper classes that contain related methods which can be mixed into any page.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Another notable mention is &lt;a href="http://fitnesse.org/FitNesse.UserGuide.SpecialPages"&gt;ScenarioLibrary&lt;/a&gt; pages - these are pages which are libraries of usable scenarios.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;FrontPage.HomeTheatreTests.ScenarioLibrary&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;|scenario         |play  movie|pathToMovie|&lt;span class="kwrd"&gt;on&lt;/span&gt; home theatre|&lt;br /&gt;|enter            |HDMI1      |mode &lt;span class="kwrd"&gt;on&lt;/span&gt; tv                 |&lt;br /&gt;|enter            |DTV/CBL    |mode &lt;span class="kwrd"&gt;on&lt;/span&gt; avr                |&lt;br /&gt;|&lt;span class="kwrd"&gt;set&lt;/span&gt; avr volume &lt;span class="kwrd"&gt;to&lt;/span&gt;|-25        |dB                         |&lt;br /&gt;|navigate menu &lt;span class="kwrd"&gt;to&lt;/span&gt; |@pathToMovie                           |&lt;br /&gt;|press            |play       |&lt;span class="kwrd"&gt;on&lt;/span&gt; media player            |&lt;br /&gt;&lt;br /&gt;|scenario|&lt;span class="kwrd"&gt;start&lt;/span&gt; home theatre|&lt;br /&gt;|power   |&lt;span class="kwrd"&gt;on&lt;/span&gt;  |media player |&lt;br /&gt;|power   |&lt;span class="kwrd"&gt;on&lt;/span&gt;  |avr          |&lt;br /&gt;|power   |&lt;span class="kwrd"&gt;on&lt;/span&gt;  |tv           |&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;ScenarioLibrary pages are included if they are a brother/uncle of the current page. Also all ScenarioLibrary pages up the hierarchy are included (allowing the possibility of overriding)&lt;br /&gt;&lt;br /&gt;All this leads to very small test pages and it all works!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;FrontPage.HomeTheatreTests.CanWorkWhileWatchingMovie&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;# ScenarioLibrary page &lt;span class="kwrd"&gt;is&lt;/span&gt; included (helper slim scenario definitions)&lt;br /&gt;# &lt;span class="kwrd"&gt;Next&lt;/span&gt; SetUp page &lt;span class="kwrd"&gt;is&lt;/span&gt; included (imports &lt;span class="kwrd"&gt;and&lt;/span&gt; library tables)&lt;br /&gt;&lt;br /&gt;|script    |me                                                   |&lt;br /&gt;|&lt;span class="kwrd"&gt;start&lt;/span&gt; home theatre                                              |&lt;br /&gt;|play movie|&lt;span class="kwrd"&gt;File&lt;/span&gt; Manager\USB\C\2 Watch\Iron Man 2|&lt;span class="kwrd"&gt;on&lt;/span&gt; home theatre|&lt;br /&gt;|&lt;span class="kwrd"&gt;start&lt;/span&gt; working                                                   |&lt;br /&gt;|&lt;span class="kwrd"&gt;after&lt;/span&gt;     |30                                   |mins           |&lt;br /&gt;|ensure    |&lt;span class="kwrd"&gt;work&lt;/span&gt; &lt;span class="kwrd"&gt;is&lt;/span&gt; done                                         |&lt;br /&gt;|press     |stop                                 |&lt;span class="kwrd"&gt;on&lt;/span&gt; media player|&lt;br /&gt;|shut down home theatre                                          |&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In this example, the fixture Me only needs to have methods that pertain to me working. All methods related to the TV, AVR and MediaPlayer are resolved by the corresponding classes in the Fixture.dll due to the Library table.&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Me&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; _workIsDone ... &lt;br /&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; startWorking() ...&lt;br /&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; afterMins(&lt;span class="kwrd"&gt;int&lt;/span&gt; timeInMinutes) ...&lt;br /&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; workIsDone ...&lt;br /&gt;    }&lt;/pre&gt;&lt;br /&gt;Pretty cool!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-5524939929179693101?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/5524939929179693101/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2010/11/scenariolibrary-librarytables-with-slim.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/5524939929179693101'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/5524939929179693101'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2010/11/scenariolibrary-librarytables-with-slim.html' title='ScenarioLibrary, LibraryTables with Slim Scenarios : Avoid fixture method explosion !'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-524554058917177373</id><published>2010-11-12T14:39:00.005+05:30</published><updated>2010-11-15T10:48:44.034+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='FIT / Fitnesse'/><category scheme='http://www.blogger.com/atom/ns#' term='ATDD'/><category scheme='http://www.blogger.com/atom/ns#' term='NUnit'/><title type='text'>What do I use for acceptance tests (ATDD) : NUnit vs Fitnesse ?</title><content type='html'>Lately I've had some teams in my getting-agile ecosystem debating on which tool to use for acceptance testing. Now my first response is always "It depends" (You really can't go wrong with that. :) ). &lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;Notation: I'm gonna use&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size: x-small;"&gt;NUnit when I actually mean any member of the xUnit family of unit-testing frameworks.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: x-small;"&gt;Fit/Fitnesse stands for itself and now Slim/Fitnesse.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: x-small;"&gt;Customer means the XP's Customer role or Scrum's Product Owner role.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Fit-Fitnesse was the de-facto tool for automated acceptance tests till sometime ago.. Around 2009, there were &lt;a href="http://ericlefevre.net/wordpress/2009/03/06/is-fit-dead-a-debate-on-twitter/"&gt;strong murmurs&lt;/a&gt; that Fitnesse isn't working that well (read as some teams weren't executing very well and Fitnesse was part of their toolkit ).&lt;br /&gt;&lt;br /&gt;So what does it "depend" on ??&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="color: #660000;"&gt;&lt;span style="font-size: large;"&gt;Customer Collaboration: Probability of Non-developers reading/modifying individual tests&lt;/span&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;Is your customer willing/able to collaborate with the team over a piece of paper to extract examples/scenarios for a particular use-case ?&amp;nbsp;&lt;/li&gt;&lt;li&gt;Are customers interested in creating truth-tables/spreadsheets of 'how this rule should work' or story descriptions of 'how the ideal system should work'?&amp;nbsp;&lt;/li&gt;&lt;li&gt;Do Customers / QA-personnel want to add/modify tests (without dev  support) to improve their understanding / the system? Is the team using a  shared medium to come up with more tests?&amp;nbsp;&lt;/li&gt;&lt;/ul&gt;If yes, choose Fit-Fitnesse... that is what it was created for. Collaboration.&lt;br /&gt;Alternate Scenario: Developers are given a bunch of requirements and are responsible for conversion to executable tests. Customers/Proxies are available over email to answer questions during ear-marked hours.&amp;nbsp; Test-list generation is done offline (read without an active customer)  followed by a verbal/email review. The transformation to executable tests has no participation from the customer. Acceptance tests are being used primarily for  closing stories (definition of done) and regression. If a Pass/Fail  result is all you need, NUnit might be a better choice.&lt;br /&gt;&lt;br /&gt;&lt;div style="color: #660000;"&gt;&lt;span style="font-size: large;"&gt;Positive Pressure on Test readability&lt;/span&gt;&lt;/div&gt;As-intended use of Fitnesse, causes test authors to express intent before implementation.. a wiki page is like a blank of paper - wishful thinking ahead! This causes the pages to read like scripts or a sequence of intent-revealing steps with intermediate checks/asserts. If the team is struggling to create readable-n-maintainable tests, use fitnesse as a guardrail.&lt;br /&gt;You could do the exact same thing with NUnit. You just need to see the world from the users' perspective and a professional programmer's instincts for refactoring and simplicity. A blank test is as good as a blank wiki page. Flesh out the step-methods later. A &lt;b&gt;common trait (of developers&lt;/b&gt;) is to &lt;b&gt;jump the gun to implementation &lt;/b&gt;details at great harm to readability. Curb your enthusiasm and no reason why it shouldn't work&lt;br /&gt;&lt;br /&gt;&lt;div style="color: #660000;"&gt;&lt;span style="font-size: large;"&gt;Deployment Footprint&lt;/span&gt;&lt;/div&gt;Fitnesse offers &lt;b&gt;a Web interface to easily view/modify/run tests from the comfort of your favourite browser&lt;/b&gt;. Point to your fitnesse server URL and voila! Zero install. You can even do 'What if' analysis without much assistance. (e.g. What if number of concurrent clients is raised from 100 to 150)&lt;br /&gt;NUnit can't do it on its own. You would need a CI System to offer the web dashboard to execute/view results. Viewing the internals of a test is still difficult. You would need an IDE and 'coding skills' to modify the tests for any what-if analysis. Of course, if the development team is the only one interacting with the tests, this is a moot point.&lt;br /&gt;&lt;br /&gt;&lt;div style="color: #660000;"&gt;&lt;span style="font-size: large;"&gt;Homesickness&lt;/span&gt;&lt;/div&gt;If dev &amp;gt;&amp;gt; testers, then it might be easier to teach the  testers NUnit - in crunch time, free devs can pitch in to help the test  teams get to the finish line. Most developers already know NUnit; Getting all of them to learn another tool for acceptance tests could be a drag (atleast in the short term). Personally (Disclaimer: more dev/NUnit hours than QA/Fitnesse) I find that Fitnesse has &lt;b&gt;a longer learning curve&lt;/b&gt; than NUnit (different table styles, reusing sections of a page, etc) before you can use it effectively. NUnit also wins hands down in the &lt;b&gt;refactoring &lt;/b&gt;department (moving HTML around can get tiresome very soon to a person used to a statically typed language + a good IDE). Stuff like 'attaching a debugger to a failing test', 'how do I get my pages into source control', 'feedback on progress of test execution' with Fitnesse might restrain/annoy speed-addicted xUnit-developers. NUnit also has &lt;b&gt;a richer assertion library&lt;/b&gt;, which I missed during my time in Fitnesse.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; On the other hand, if you have customers and testers who can 'converse in fitnesse' and have a few projects under their belt, don't get in their way. Testers can get homesick too. Go with Fitnesse and pair Devs with Testers to diffuse Fitnesse in the team.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="color: #274e13;"&gt;&lt;span style="font-size: large;"&gt;End-game&lt;/span&gt;&lt;/div&gt;Both are tools - &lt;b&gt;it is how your team executes with these tools&lt;/b&gt;, that makes the difference. To quote Ron Jeffries,&amp;nbsp; "people can screw up everything" ; that doesn't reflect badly on the tool they used. &lt;br /&gt;It is &lt;b&gt;a reversible decision&lt;/b&gt;. If you &lt;b&gt;design your tests to be independent of the test runner&lt;/b&gt;, you can swap out the existing runner at any time. e.g. the idea below (see image) that I've had some success with (for rich desktop clients). Maybe you'd find that none of them work for "your team", look for  something new that works (e.g. maybe &lt;a href="http://cukes.info/"&gt;Cucumber&lt;/a&gt; is a  better fit). Instead of spending hours in analysis paralysis, choose  one, &lt;b&gt;get started, reflect and adapt&lt;/b&gt;. &lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_nxgDpneh8yk/TNyv5j2hOKI/AAAAAAAAA5s/1tj71rW5ZFc/s1600/UIvsAPITesting.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_nxgDpneh8yk/TNyv5j2hOKI/AAAAAAAAA5s/1tj71rW5ZFc/s1600/UIvsAPITesting.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-524554058917177373?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/524554058917177373/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2010/11/what-do-i-use-for-acceptance-tests-atdd.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/524554058917177373'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/524554058917177373'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2010/11/what-do-i-use-for-acceptance-tests-atdd.html' title='What do I use for acceptance tests (ATDD) : NUnit vs Fitnesse ?'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_nxgDpneh8yk/TNyv5j2hOKI/AAAAAAAAA5s/1tj71rW5ZFc/s72-c/UIvsAPITesting.jpg' height='72' width='72'/><thr:total>0</thr:total><georss:featurename>Thane, Maharashtra, India</georss:featurename><georss:point>19.194459565404916 72.96295166015625</georss:point><georss:box>19.032341565404916 72.72949216015625 19.356577565404915 73.19641116015625</georss:box></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-1050633705395425052</id><published>2010-10-27T16:57:00.003+05:30</published><updated>2010-11-11T13:45:39.821+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='white'/><category scheme='http://www.blogger.com/atom/ns#' term='Automated Tests'/><title type='text'>How to get Thoughtworks' White to LogStructure</title><content type='html'>&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Struggled for some time getting it to work. I've been playing with Thoughtworks' open library for UI Testing for a while.&lt;br /&gt;&lt;br /&gt;Sometimes &lt;a href="http://white.codeplex.com/wikipage?title=Third%20Party%20Controls"&gt;UISpy doesn't get you to the UIElement hierarchy&lt;/a&gt; and you need to take out the big guns ala White's window.LogStructure to dump out the UIElement tree.&lt;br /&gt;As always it's simple when you know how.&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;b&gt;Step#1&lt;/b&gt;: Modify the app.config of your executable to include the sections related to White. See a sample file on White's page &lt;a href="http://white.codeplex.com/wikipage?title=Configuration"&gt;here&lt;/a&gt;.&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;b&gt;Step#2&lt;/b&gt;: Add the following line to your AssemblyInfo.cs file&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre class="csharpcode"&gt;[assembly: log4net.Config.XmlConfigurator(ConfigFile = &lt;span class="str"&gt;"Log4Net.config"&lt;/span&gt;, Watch = &lt;span class="kwrd"&gt;true&lt;/span&gt;)]&lt;/pre&gt;&lt;br /&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;b&gt;Step#3&lt;/b&gt;: Add a file called Log4Net.config under your assembly (configure it such that it is always copied to the output folder). This contains the configuration information for Log4Net (e.g. the following config logs to console and to file named example.log in your output folder.). That's it you should now be able to see/capture window.LogStructure output from White. Godspeed !&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;log4net&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;appender&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="Console"&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="log4net.Appender.ConsoleAppender"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;layout&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="log4net.Layout.PatternLayout"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class="rem"&gt;&amp;lt;!-- Pattern to output the caller's file name and line number --&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;conversionPattern&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="%5level [%thread] (%file:%line) - %message%newline"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;layout&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;appender&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;appender&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="RollingFile"&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="log4net.Appender.RollingFileAppender"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;file&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="example.log"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;appendToFile&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="true"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;maximumFileSize&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="100KB"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;maxSizeRollBackups&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="2"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;layout&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="log4net.Layout.PatternLayout"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;conversionPattern&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="%level %thread %logger - %message%newline"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;layout&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;appender&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;root&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;level&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="DEBUG"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;appender-ref&lt;/span&gt; &lt;span class="attr"&gt;ref&lt;/span&gt;&lt;span class="kwrd"&gt;="Console"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;appender-ref&lt;/span&gt; &lt;span class="attr"&gt;ref&lt;/span&gt;&lt;span class="kwrd"&gt;="RollingFile"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;root&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;log4net&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-1050633705395425052?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/1050633705395425052/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2010/10/how-to-get-white-to-logstructure.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/1050633705395425052'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/1050633705395425052'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2010/10/how-to-get-white-to-logstructure.html' title='How to get Thoughtworks&apos; White to LogStructure'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-1846120312924366169</id><published>2010-08-20T14:40:00.004+05:30</published><updated>2010-08-20T15:50:16.387+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='Automated Tests'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><title type='text'>An effective test strategy to grow applications</title><content type='html'>This is a post to summarize my understanding (as of today) of an effective (low ceremony) way to build applications. &lt;br /&gt;Let's take a look at (a slightly modified version) of &lt;a href="http://blog.mountaingoatsoftware.com/the-forgotten-layer-of-the-test-automation-pyramid"&gt;Mike Cohn's layered test pyramid&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://lh4.ggpht.com/_nxgDpneh8yk/TG5HHEqN7WI/AAAAAAAAA5E/5YvZFzH-e2U/s800/Modified%20Cohn%27s%20test%20pyramid_Grad.png"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 612px; height: 434px;" src="http://lh4.ggpht.com/_nxgDpneh8yk/TG5HHEqN7WI/AAAAAAAAA5E/5YvZFzH-e2U/s800/Modified%20Cohn%27s%20test%20pyramid_Grad.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The choice of a pyramid indicates the robustness/stability of a lower layer directly affects the effectiveness of the upper layer. Also the number of tests decreases as you move up. As the &lt;a href="http://www.agiletester.ca/"&gt;agile testing book&lt;/a&gt; says ROI is maximum at the bottom (speed of feedback over time invested) and wanes towards the top.&lt;br /&gt;&lt;span style="font-size:85%;"&gt;e.g. without robust unit-tests, DSL tests or GUI tests would catch a bunch of errors without the essential feedback needed to fix it quickly. More and more errors would make it up to the middle and top layers, where it is more time-consuming/expensive to find-n-fix. Nothing replaces well-written, quick, professional unit tests.&lt;/span&gt;&lt;br /&gt;To prevent ambiguity and misinterpretation, let's go over each layer.&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Layer 0: Unit-Integration-Stress tests&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Unit tests should accumulate over time as a side-effect of test driven development. It's a tough art to master -- writing good unit tests but they are invaluable in the long term. They are essential for 'internal quality'. This layer also contains some integration tests and stress tests.&lt;/li&gt;&lt;li&gt;'Integration tests' in this post means (as in the GOOS Book) : 'Let me see if the real collaborator behaves as I expect it to'.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size:85%;"&gt;e.g. Let's say Car needs to use the Driver database. Since we live in these times, we'd define a Role(Interface) DriverRepository to abstract away the database from ClassA. In my unit-tests, I'd inject a MockDriverRepository  into a Car and test it out. So I know Car is good. Now there are some assumptions implicit in the Role/interface. I need to verify that the real implementation behaves the same - so I'd need to write some 'integration tests' to verify if the real collaborator DriverRepository behaves the same. &lt;span style="font-weight: bold;"&gt;These tests would round-trip a third party / external subsystem in order to produce a result. &lt;/span&gt;TestDriverRepository.GetsSpecifiedDriverInformation() would test if we can get the specified driver information out from a real database. Integration tests are *slower* than unit-tests, so we partition it into a different test-suite that is not run as frequently as the unit-tests. Feedback needs to be as short as possible during development.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;'Stress tests' are for asynchronous code - code that has multiple threads running through them. In this case, you'd have to define some invariants - things that must remain true irrespective of the number and scheduling of multiple threads through the code. (Refer to the last couple of chapters of the GOOS book for details).&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Layer 1: Under the GUI / DSL-API tests&lt;/span&gt;&lt;br /&gt;This is the layer that's rarely given its due and usually missed - its primary reason for existence is scenario testing just under the skin/GUI. These tests are written from the user's perspective. When you get this layer right, its sweet. You will see a DSL emerging. &lt;span style="font-weight: bold;"&gt;Your tests appear as short scripts written in an application specific DSL, where the steps are things that an actual user would do or perceive.&lt;/span&gt; These tests can exercise the whole app similar to a real user, without having to bring up a GUI... as long as you have designed it for testability (use a MVP / MVVM pattern).&lt;br /&gt;These tests &lt;span style="font-weight: bold;"&gt;involve all real collaborators&lt;/span&gt; (no mocks/stubs/fakes). As a result, they are &lt;span style="font-weight: bold;"&gt;slower than Unit tests&lt;/span&gt;. However built on a bedrock of solid unit tests, they can take you to the finish line... almost.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Layer 2: GUI Tests&lt;/span&gt;&lt;br /&gt;Even with anemic views, there is a matter of &lt;span style="font-weight: bold;"&gt;the 'wiring'&lt;/span&gt;. Is the GUI Control wired correctly to the right property/action on the backing object? Irrespective of the strength of the layers beneath it, you need a set of GUI tests that &lt;span style="font-weight: bold;"&gt;go really end-to-end identical to a real user&lt;/span&gt;. They're the slowest we've seen so far - so &lt;span style="font-weight: bold;"&gt;do not test everything through the GUI&lt;/span&gt;. The test duration would grow prohibitively large with time.&lt;br /&gt;An interesting idea here is: to just test the code in the GUI in the GUI Tests. I haven't tried this out myself but sounds like something that is just crazy enough to work.&lt;br /&gt;&lt;br /&gt;We're almost at the end. There are some aspects that we haven't yet tested.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Exploratory tests: Let some good testers go ad-hoc at your app trying to break things. These tests are manual since they rely on the tester's creativity and insight (not mechanical).&lt;/li&gt;&lt;li&gt;Usability tests: Regular demos and getting some real users to use the latest builds would go a long way to ensuring usability. Testers can act as a proxy as long as they are aligned with the customer's profile and needs. These are manual too since machines can't determine usability.&lt;/li&gt;&lt;li&gt;"ility" tests: These are tests that deal with performance, load, security, reliability, scalability, etc. When a feature is picked up for implementation, if it has any of the above 'ility' needs, they should be noted and a corresponding test be written up to validate them. (The point being.. don't wait till the end to start with this.) The tests can be written in a scripting language and &lt;span style="font-weight: bold;"&gt;use specialized tools/libraries if required&lt;/span&gt;. &lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size:130%;"&gt;Who does what ??&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;iframe src="https://spreadsheets.google.com/pub?key=0AqQfN_JAz01mdGlBZEg3Q3JuZjY2R1g0WmUtYmxWQWc&amp;amp;hl=en&amp;amp;single=true&amp;amp;gid=0&amp;amp;output=html&amp;amp;widget=true" frameborder="0" height="300" width="500"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;An effective way to implement features is a Top-Down approach, where you begin by writing a GUI Test/DSL-API test first and then work your way down. This way you only write code that a client needs - which leads to simple usable APIs. Once you have a failing red acceptance test,&lt;br /&gt;&lt;ul&gt;&lt;li&gt;You can either figure out the top-level design to get it to work and test-drive the classes required. Combine them to make the accceptance test pass. &lt;/li&gt;&lt;/ul&gt;OR&lt;br /&gt;&lt;ul&gt;&lt;li&gt;you can begin by writing the code to make the acceptance test pass. Once green, in the refactoring step, you can now figure out the right "house" for the code. TDD the objects that you &lt;span style="font-weight: bold;"&gt;now know you need&lt;/span&gt; and fold them back into the running application (See the GOOS book if you're interested in this approach).&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;That's it. This ties up nicely with &lt;a href="http://www.exampler.com/old-blog/2003/08/21/#agile-testing-project-1"&gt;Brian Marick's test quadrants idea&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 612px; height: 434px;" src="http://lh4.ggpht.com/_nxgDpneh8yk/SUIqh0tGgrI/AAAAAAAAAdQ/X3u5oEe9a7c/s800/Testing.png" alt="" border="0" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-1846120312924366169?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/1846120312924366169/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2010/08/effective-test-strategy-to-grow.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/1846120312924366169'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/1846120312924366169'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2010/08/effective-test-strategy-to-grow.html' title='An effective test strategy to grow applications'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_nxgDpneh8yk/TG5HHEqN7WI/AAAAAAAAA5E/5YvZFzH-e2U/s72-c/Modified%20Cohn%27s%20test%20pyramid_Grad.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-1018999791171329587</id><published>2010-08-07T18:48:00.006+05:30</published><updated>2010-08-07T20:34:46.280+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='Book Review'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Review : Growing Object Oriented Software - Guided by Tests: Freeman, Pryce</title><content type='html'>&lt;span style="font-family:trebuchet ms;"&gt;&lt;span style="font-weight: bold;"&gt;Recommended... best book on TDD in a while.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Just finished this one today... I got to fess up - that I am a "classicist". I've seen some real spaghetti tests involving mocks.. But I've gotten some periodic tension from the people on the other side of this religious fence of TDD. Since this book comes from "the torch-bearers of the mockist camp", I picked up a copy and tried to keep an open mind. And I although I haven't switched camps.. I now see the light. There is no one right path but the authors have placed some industrial strength beacons  on this path and teach you how to use mocks and interaction tests to "grow" applications driven by automated tests. (&lt;/span&gt;&lt;span style="font-style: italic;font-family:trebuchet ms;" &gt;However I still maintain that in untrained hands, Mocks (like C++) can be very dangerous and quickly lead into tarpits. Easy to abuse. However in the right hands, they can be used to write very expressive code &amp;amp; enable rapid and iterative development&lt;/span&gt;. ).&lt;br /&gt;&lt;br /&gt;Some of the key takeaways for me were:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Developing outside-in ATDD: writing a 'walking skeleton' first ,   spotting objects and roles (relationships) between them, TDDing these objects and "folding them back" into a running app was a new method to me.&lt;/span&gt;&lt;/li&gt;&lt;li&gt; &lt;span style="font-family:trebuchet ms;"&gt;Listening to the tests, Focus on readability, tests  with helpful diagnostics / failure messages, eliminating or reducing the  irrelevant part of the test, use of builders + drivers to keep the tests  concise&lt;/span&gt;&lt;/li&gt;&lt;li style="font-family: trebuchet ms;"&gt;&lt;span&gt;The chapters on threads and asynchronous  testing are home-runs. Don't leave for work without it. The last third  of the book was worth the price of the book (It isn't yet available in  India so had to get it from overseas).&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:trebuchet ms;"&gt;There is a lot of real world knowledge that the authors have distilled down to a kind of 'secret sauce'.&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:trebuchet ms;"&gt;As  the book rightly says, TDD that isn't sustainable will slowly choke the  project, tests turn into maintenance headaches and strangles development progress.&lt;/span&gt; &lt;span style="font-family:trebuchet ms;"&gt;This is the part that trips  most people up with TDD - Kent Beck's book on TDD and most of the  literature out there detail the basic technique (with an assumption that  you would figure out the exact steps that you need to take in your  specific context). The skill of "listening to the tests" isn't easy to pickup or practice for most people. Freeman, Pryce et. all have come up with a more  prescriptive method that should keep beginners on the rails.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;I followed along to the AuctionSniper example using my own style (and .net, nUnit, Moq + White instead of java, jUnit, jMock + WindowLicker as in the book) in order to compare and contrast. The example isn't trivial (deals with multiple-threads, third party server and protocol  (XMPP) and was well chosen.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;embed type="application/x-shockwave-flash" src="http://picasaweb.google.com/s/c/bin/slideshow.swf" flashvars="host=picasaweb.google.com&amp;amp;hl=en_US&amp;amp;feat=flashalbum&amp;amp;RGB=0x000000&amp;amp;feed=http%3A%2F%2Fpicasaweb.google.com%2Fdata%2Ffeed%2Fapi%2Fuser%2FGishu.Pillai%2Falbumid%2F5502654231587001233%3Falt%3Drss%26kind%3Dphoto%26hl%3Den_US" pluginspage="http://www.macromedia.com/go/getflashplayer" height="400" width="600"&gt;&lt;/embed&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;The final solution was different from the solution in the book; but still passed all the tests. The authors emphasize test readability, which is a 'Can do better' item for me. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;span style="font-weight: bold;"&gt;Final word&lt;/span&gt;: This book is a must-read for intermediate and advanced programmers interested in gaining mastery over TDD. I'd place it on the top-shelf right next to Beck's XP Book, TDD Book &amp;amp; Fowler's Refactoring book. It doesn't have any radical new ideas however it does teach you the right guiding principles to survive in the real world today. &lt;span style="font-style: italic;"&gt;It says a lot of things that needed to be said at this point of time... for that I'd give it a 9/10.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Note: The book also has a &lt;/span&gt;&lt;a style="font-family: trebuchet ms;" href="http://www.growing-object-oriented-software.com/"&gt;companion site&lt;/a&gt;&lt;span style="font-family:trebuchet ms;"&gt;, with a responsive discussion forum.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-1018999791171329587?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/1018999791171329587/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2010/08/review-growing-object-oriented-software.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/1018999791171329587'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/1018999791171329587'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2010/08/review-growing-object-oriented-software.html' title='Review : Growing Object Oriented Software - Guided by Tests: Freeman, Pryce'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-157253682043287627</id><published>2010-07-27T17:03:00.004+05:30</published><updated>2010-07-30T16:21:59.824+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='SLIM'/><category scheme='http://www.blogger.com/atom/ns#' term='FIT / Fitnesse'/><category scheme='http://www.blogger.com/atom/ns#' term='Automated Tests'/><title type='text'>Contract Tests with Slim/Fitnesse : Running a test suite against multiple implementations of an interface</title><content type='html'>&lt;span style="font-family:trebuchet ms;"&gt;Recently I had a need for something similar to "xUnit contract tests" in Fitnesse (defined as: a test suite, which any object must satisfy so that it can be considered as a valid implementation of a Role.  I got the term from one  of J.B.Rainsberger's talks. ) &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;To illustrate my point, let me cook up an example.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Imagine a contest for BoneyM impersonators. We would quiz each impersonator with a set of questions that they must answer correctly to win the contest.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;i.e. we have a set of tests (questions) for each implementation of an Impersonator (Role). We also have multiple impersonators that I want to validate against the contract tests. The tests need to be dry - since they don't change for each implementation. &lt;/span&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;So here are the questions and the expected answers to them. (the contract tests)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Q:How did rasputin die? A:His enemies shot him till he was dead.&lt;/li&gt;&lt;li&gt;Q:Was yesterday sunny? A: No&lt;/li&gt;&lt;li&gt;Q:Who runs the baker family? A: Ma Baker&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:trebuchet ms;"&gt;So the contract for each impersonator is&lt;/span&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; BoneyMImpersonator&lt;br /&gt; {&lt;br /&gt;     &lt;span class="kwrd"&gt;string&lt;/span&gt; HowDidRasputinDie();&lt;br /&gt;     &lt;span class="kwrd"&gt;bool&lt;/span&gt; WasYesterdaySunny();&lt;br /&gt;     &lt;span class="kwrd"&gt;string&lt;/span&gt; WhoRunsTheBakerFamily();&lt;br /&gt; }&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:trebuchet ms;" &gt;Slim/Fitnesse:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;The new addition to the Fitnesse/Fit family is the SLIM runner. From what I've seen in a couple of days - I'm impressed!&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;For some quick help to get it running, check out this post by Brett Schuchert - &lt;a href="http://schuchert.wikispaces.com/FitNesse.Tutorials.0"&gt;http://schuchert.wikispaces.com/FitNesse.Tutorials.0&lt;/a&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;One of the table-styles that SLIM has introduced is "scenario tables".  The thing that is great about them - is that it brings something similar to C++ macros (expansion via text substitution) to Fitnesse. i.e. you can write up a scenario table once and then call it from multiple places in other tables (script/decision tables). Let's see it in action.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;    &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:trebuchet ms;"&gt;Here's my Fitnesse page:&lt;/span&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/gishu-util/source/browse/trunk/Blog/ContractTests_FitnessePage.txt"&gt;&lt;span style="font-family:trebuchet ms;"&gt;http://code.google.com/p/gishu-util/source/browse/trunk/Blog/ContractTests_FitnessePage.txt&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;And here's the backing fixture and domain code&lt;/span&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/gishu-util/source/browse/trunk/Blog/FixtureCode.cs"&gt;&lt;span style="font-family:trebuchet ms;"&gt;http://code.google.com/p/gishu-util/source/browse/trunk/Blog/FixtureCode.cs&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/gishu-util/source/browse/trunk/Blog/DomainCode.cs"&gt;&lt;span style="font-family:trebuchet ms;"&gt;http://code.google.com/p/gishu-util/source/browse/trunk/Blog/DomainCode.cs&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Refer to this fitnesse doc page for a sample &lt;a href="http://fitnesse.org/FitNesse.UserGuide.SliM.ScenarioTable"&gt;http://fitnesse.org/FitNesse.UserGuide.SliM.ScenarioTable&lt;/a&gt;&lt;/span&gt;.&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:trebuchet ms;"&gt;There's a collapsed section called "No Peeking" - but you should. Without it, SLIM doesn't have an actor or co-ordinator to talk to - and you'd get cryptic errors like 'Method [name] not found in fitSharp.Slim.Operators.ExecuteBase+NullInstance'&lt;/span&gt;&lt;span style="font-family:trebuchet ms;"&gt;. The missing ingredient for me was the &lt;span style="font-weight: bold;"&gt;|script|quiz|&lt;/span&gt; line. With this, you tell Fitnesse that a class named Quiz is who you should talk to.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Next you define the scenario (see the above link for details). In short, a scenario has a name and parameters. Parameters must be used within the scenario prefixed with a @ sign. In our scenario, we use the fully-qualified type name of the implementation as the parameter. In welcome, we create an instance of it via some reflection/activation magic. Next we interrogate the object and compare answers.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;  &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Finally we need the scenario to be run against multiple implementations of the contract. For that we have a decision table (equivalent to Fit's ColumnFixture), which must have the exact same name as the scenario and the column headers must match the scenario parameters.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;So in effect, each row is replaced by a scenario invocation with the parameters specified in the row. This can be seen when you run the tests. You can see new column with cells, which be expanded to see the scenario details as shown below...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="http://lh6.ggpht.com/_nxgDpneh8yk/TE7LLYHuh1I/AAAAAAAAA3s/RLwH0YffkWU/s800/ContractTestsWithSlim.jpg" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;In the future, if you have a new implementation say StonedGuy, just add another row to the Decision table and that's it! The contract tests are DRY-compliant.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Update: &lt;/span&gt;Gregor Gramlich points out that the welcome method doesn't need to be implemented in the fixture, just for an instance of the test subject via reflection. Instead a line &lt;span style="font-weight: bold;"&gt;|start | FullyQualifiedClassName |&lt;/span&gt; works just as well. Nice tip. Code samples updated.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-157253682043287627?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/157253682043287627/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2010/07/contract-tests-with-slimfitnesse.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/157253682043287627'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/157253682043287627'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2010/07/contract-tests-with-slimfitnesse.html' title='Contract Tests with Slim/Fitnesse : Running a test suite against multiple implementations of an interface'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_nxgDpneh8yk/TE7LLYHuh1I/AAAAAAAAA3s/RLwH0YffkWU/s72-c/ContractTestsWithSlim.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-2292950504938564196</id><published>2010-04-22T16:13:00.004+05:30</published><updated>2010-07-27T17:00:37.898+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='.net'/><title type='text'>Implementing case-insensitive lookup tables (Dictionary) with string keys</title><content type='html'>&lt;span style="font-family:trebuchet ms;"&gt;The Dictionary&lt;tkey,&gt; type in .Net takes in a comparer as a constructor parameter. So you could pass in StringComparer.OrdinalIgnoreCase and you're done.&lt;/tkey,&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;I used to upper-case keys while adding it to the lookup table earlier and again when performing a lookup - to achieve case-insensitive string lookups. I remember reading some article about String.ToUpper() being optimized for such scenarios. Now I was unsure - which one is better ?&lt;/span&gt; &lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;So I ran a small experiment.&lt;/span&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="rem"&gt;//void Main()&lt;/span&gt;&lt;br /&gt;         var keys_for_lookup = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; { &lt;span class="str"&gt;"abc"&lt;/span&gt;, &lt;span class="str"&gt;"dEF"&lt;/span&gt;, &lt;span class="str"&gt;"123"&lt;/span&gt;, &lt;span class="str"&gt;"655"&lt;/span&gt;, &lt;span class="str"&gt;"pQr"&lt;/span&gt; };&lt;br /&gt;        &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; 3; i++)&lt;br /&gt;        {&lt;br /&gt;            var dict1 = &lt;span class="kwrd"&gt;new&lt;/span&gt; Dictionary&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;, &lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt;();&lt;br /&gt;            AddSomeKeys(dict1, &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; { &lt;span class="str"&gt;"ABC"&lt;/span&gt;, &lt;span class="str"&gt;"DEF"&lt;/span&gt;, &lt;span class="str"&gt;"GHI"&lt;/span&gt;, &lt;span class="str"&gt;"JKL"&lt;/span&gt;, &lt;span class="str"&gt;"MNO"&lt;/span&gt;, &lt;span class="str"&gt;"PQR"&lt;/span&gt;, &lt;span class="str"&gt;"XYZ"&lt;/span&gt;, &lt;span class="str"&gt;"123"&lt;/span&gt; });&lt;br /&gt;            TimeIt(&lt;span class="kwrd"&gt;delegate&lt;/span&gt; { RunTest_Upper(dict1, keys_for_lookup); });&lt;br /&gt;&lt;br /&gt;            dict1 = &lt;span class="kwrd"&gt;new&lt;/span&gt; Dictionary&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;, &lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt;(StringComparer.OrdinalIgnoreCase);&lt;br /&gt;            AddSomeKeys(dict1, &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; { &lt;span class="str"&gt;"abc"&lt;/span&gt;, &lt;span class="str"&gt;"def"&lt;/span&gt;, &lt;span class="str"&gt;"ghi"&lt;/span&gt;, &lt;span class="str"&gt;"jkl"&lt;/span&gt;, &lt;span class="str"&gt;"mno"&lt;/span&gt;, &lt;span class="str"&gt;"pqr"&lt;/span&gt;, &lt;span class="str"&gt;"XYZ"&lt;/span&gt;, &lt;span class="str"&gt;"123"&lt;/span&gt; });&lt;br /&gt;            TimeIt(&lt;span class="kwrd"&gt;delegate&lt;/span&gt; { RunTest(dict1, keys_for_lookup); });&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// end of main&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;And this is what the results looked like :&lt;br /&gt;It looks like using a Dictionary with a comparer injected is&lt;br /&gt;&lt;/span&gt;&lt;ol&gt;&lt;li  style="font-family:trebuchet ms;"&gt;&lt;span style="font-weight: bold;"&gt;faster &lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li  style="font-family:trebuchet ms;"&gt;&lt;span style="font-weight: bold;"&gt;less hassle&lt;/span&gt;. You specify it once and forget it. You do not have remember to do UpperCase each time you lookup the map. (e.g. from the p.o.v. of future programmers)&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;span style="font-weight: bold;"&gt;less memory pressure&lt;/span&gt;. ToUpper() would create a new String instance per lookup. &lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;table style="width: auto;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://picasaweb.google.com/lh/photo/o5Cmdah_ybOcsjB6Tj6W1_caujkF9KLSFFuJboHAXZ8?feat=embedwebsite"&gt;&lt;img src="http://lh4.ggpht.com/_nxgDpneh8yk/S9AtUMhPWeI/AAAAAAAAA3I/dqVcTdWAm3w/s800/insensitive_case_results.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-family: arial,sans-serif; font-size: 11px; text-align: right;"&gt;From &lt;a href="http://picasaweb.google.com/Gishu.Pillai/MyConversationsWithGullibleMachines?authkey=Gv1sRgCNTm5f7KtOeXBw&amp;amp;feat=embedwebsite"&gt;My conversations with gullible machines...&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;(Setup: .Net 3.5, VS2008, WinXP SP2, Intel T7400 Core 2, 2GB RAM on a normal work afternoon, lots of apps open)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;The rest of the code for scrutiny:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; AddSomeKeys(Dictionary&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;, &lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt; dict1, List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; keys)&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (var key &lt;span class="kwrd"&gt;in&lt;/span&gt; keys)&lt;br /&gt;            dict1.Add(key, &lt;span class="kwrd"&gt;new&lt;/span&gt; Object());&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; RunTest_Upper(Dictionary&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;, &lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt; dict1, List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; keys)&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; 1000000; i++)&lt;br /&gt;            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (var key &lt;span class="kwrd"&gt;in&lt;/span&gt; keys)&lt;br /&gt;            { var v = dict1.ContainsKey(key.ToUpper()); }&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; RunTest(Dictionary&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;, &lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt; dict1, List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; keys)&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; 1000000; i++)&lt;br /&gt;            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (var key &lt;span class="kwrd"&gt;in&lt;/span&gt; keys)&lt;br /&gt;            { var v = dict1.ContainsKey(key); }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; TimeIt(Action action)&lt;br /&gt;    {&lt;br /&gt;        var s = System.Diagnostics.Stopwatch.StartNew();&lt;br /&gt;        action.Invoke();&lt;br /&gt;        s.Stop();&lt;br /&gt;        Console.WriteLine(&lt;span class="str"&gt;"Elapsed msecs = {0}"&lt;/span&gt;, s.ElapsedMilliseconds);&lt;br /&gt;    }&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-2292950504938564196?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/2292950504938564196/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2010/04/implementing-case-insensitive-lookup.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/2292950504938564196'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/2292950504938564196'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2010/04/implementing-case-insensitive-lookup.html' title='Implementing case-insensitive lookup tables (Dictionary) with string keys'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_nxgDpneh8yk/S9AtUMhPWeI/AAAAAAAAA3I/dqVcTdWAm3w/s72-c/insensitive_case_results.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-5228090076954289953</id><published>2010-04-20T12:39:00.007+05:30</published><updated>2010-07-27T17:02:48.226+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='wpf'/><title type='text'>WPF - Find a child control of a specific type or satisfying a given predicate under a parent control</title><content type='html'>&lt;span style="font-family: trebuchet ms;"&gt;Ideally you shouldn't be doing this in WPF and MVVM land. However there is an exception to every rule.. mine was I had to set the focus and put a specific cell in a grid into edit mode when the user clicked a button.&lt;/span&gt; &lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;Now this is one of the corner cases, for which you need to write some code-behind in the view. Next I needed to get a handle on the datagrid, which was nested within a few expanded data-templates. You can't name this grid, because each expanded data-template would have the same name value.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;I did not want to hard code the entire hierarchy path of UI types from the tab to the nested grid. So what I needed was an API like&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;var grid = tab.FindChild&amp;lt;DataGrid&amp;gt;();&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;Unfortunately this isn't built-in functionality ; so I look on Stackoverflow and find a &lt;/span&gt;&lt;a style="font-family: trebuchet ms;" href="http://stackoverflow.com/questions/636383"&gt;relevant question&lt;/a&gt;&lt;span style="font-family: trebuchet ms;"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;However it didn't work for me as is.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;Some more debugging and searching later.. I find this post '&lt;/span&gt;&lt;a style="font-family: trebuchet ms;" href="http://www.blogger.com/Understanding%20the%20Visual%20Tree%20and%20Logical%20Tree%20in%20WPF"&gt;Understanding the Visual and Logical tree in WPF&lt;/a&gt;&lt;span style="font-family: trebuchet ms;"&gt;' by the always-enlightening WPF Guru Josh Smith. Now I'm not sure I can explain it to a third person..&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;but here is what I found by tinkering with a test-app.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;table style="width: auto;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://picasaweb.google.com/lh/photo/Ig-V8ax1Yf-drJlalUMJUfcaujkF9KLSFFuJboHAXZ8?feat=embedwebsite"&gt;&lt;img src="http://lh3.ggpht.com/_nxgDpneh8yk/S81Y_15yteI/AAAAAAAAA2o/kb7Wqrn-owg/s800/LogicalChildren.jpg" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-family: arial,sans-serif; font-size: 11px; text-align: right;"&gt;From &lt;a href="http://picasaweb.google.com/Gishu.Pillai/MyConversationsWithGullibleMachines?authkey=Gv1sRgCNTm5f7KtOeXBw&amp;amp;feat=embedwebsite"&gt;My conversations with gullible machines...&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li style="font-family: trebuchet ms;"&gt;A DependencyObject can have m logical (shown in bold above) and n visual children.&lt;/li&gt;&lt;br /&gt;&lt;li style="font-family: trebuchet ms;"&gt;The visual and logical children can overlap. e.g. a StackPanel can be a logical and a visual child of a parent at the same time&lt;/li&gt;&lt;br /&gt;&lt;li style="font-family: trebuchet ms;"&gt;A logical child can be any object - does not necessarily derive from DependencyObject&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;With this knowledge, I wrote a few overloads of FindChild - source &lt;a href="http://code.google.com/p/gishu-util/source/browse/trunk/WPF/Utilities/DepObjExtn.cs"&gt;available here&lt;/a&gt;. Pretty self-explanatory.&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// find a child textbox with a specific name&lt;/span&gt;&lt;br /&gt;var textBox = tab.FindChild&amp;lt;TextBox&amp;gt;( t =&amp;gt; t.Name == &lt;span class="str"&gt;'txtName'&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// find all child stackpanels meeting a specific criteria (has children)&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;foreach&lt;/span&gt;(var panel &lt;span class="kwrd"&gt;in&lt;/span&gt; tab.FindChildren&amp;lt;StackPanel&amp;gt;( panel =&amp;gt; panel.Children.Count &amp;gt; 0)&lt;br /&gt;{ // &lt;span class="kwrd"&gt;do&lt;/span&gt; something with panel }&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;There is also another class - a &lt;/span&gt;&lt;a style="font-family: trebuchet ms;" href="http://code.google.com/p/gishu-util/source/browse/trunk/WPF/Utilities/UITreeNode.cs"&gt;VM for a Node&lt;/a&gt;&lt;span style="font-family: trebuchet ms;"&gt; in the UI Hierarchy, that I used to create the test app. I found it useful for diagnostics. e.g. if you have a reference _contentBox. You can bring up QuickWatch and add the expression 'new UITreeNode(_contentBox)' and visualize the logical and visual hierarchy under it. (Of course you need to paste the class definition into your project temporarily.)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;table style="width: auto;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;a href="http://picasaweb.google.com/lh/photo/onobwCbEem8n5dmTpocgGPcaujkF9KLSFFuJboHAXZ8?feat=embedwebsite"&gt;&lt;img src="http://lh4.ggpht.com/_nxgDpneh8yk/S81eAx9T4xI/AAAAAAAAA2s/n5ilLj_R28E/s800/UITreeNode_QuickWatch.JPG" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-family: arial,sans-serif; font-size: 11px; text-align: right;"&gt;From &lt;a href="http://picasaweb.google.com/Gishu.Pillai/MyConversationsWithGullibleMachines?authkey=Gv1sRgCNTm5f7KtOeXBw&amp;amp;feat=embedwebsite"&gt;My conversations with gullible machines...&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-5228090076954289953?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/5228090076954289953/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2010/04/wpf-find-child-control-of-specific-type.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/5228090076954289953'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/5228090076954289953'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2010/04/wpf-find-child-control-of-specific-type.html' title='WPF - Find a child control of a specific type or satisfying a given predicate under a parent control'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_nxgDpneh8yk/S81Y_15yteI/AAAAAAAAA2o/kb7Wqrn-owg/s72-c/LogicalChildren.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-1446205322015181541</id><published>2010-04-16T15:44:00.008+05:30</published><updated>2010-07-27T17:02:03.858+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='wpf datagrid'/><title type='text'>Set keyboard focus when the user begins editing a wpf datagrid templatecolumn ?</title><content type='html'>&lt;div style="text-align: left;"&gt;&lt;span style="font-family:trebuchet ms;"&gt;The problem:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;When I begin editing a grid cell, I'd expect the keyboard focus to be set the edit control for the cell. In case of a textbox, I'd also like the existing contents to be selected by default ; so that i can begin typing and set a new value quickly.&lt;/span&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;This works for the default data grid column types... except for a DataGridTemplateColumn ; a column whose display &amp;amp; edit behavior can be customized. You can use a templateselector to dynamically choose the templates to be used for displaying and editing values.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;However if you attempt to tab into a TemplateColumn cell and hit F2 to begin editing, you'd find that you can't start typing in it. You need to click in it once or press Tab once more to do that. Compare the behavior of a TextColumn and TemplateColumn showing the same bound value as shown in the code below. The TextColumn behaves as expected. The edit control receives keyboard focus and all the text in it is selected.&lt;br /&gt;&lt;br /&gt;Highly unintuitive.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; font-family: trebuchet ms;"&gt;The fix for the keyboard focus thing turned out to be setting &lt;span style="font-weight: bold;"&gt;FocusManager.FocusedElement &lt;/span&gt;attached property on the desired control in your Data Template for editing.&lt;/span&gt;&lt;span style="font-family:trebuchet ms;"&gt; Check out the sample below with/without the FocusedElement property setter :&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;           ...&lt;br /&gt;           &amp;lt;DataTemplate x:Key=&lt;span class="str"&gt;"DefaultTitleTemplate"&lt;/span&gt;&amp;gt;&lt;br /&gt;               &amp;lt;TextBlock Text=&lt;span class="str"&gt;"{Binding Title}"&lt;/span&gt;/&amp;gt;&lt;br /&gt;           &amp;lt;/DataTemplate&amp;gt;&lt;br /&gt;           &amp;lt;DataTemplate x:Key=&lt;span class="str"&gt;"EditTitleTemplate"&lt;/span&gt;&amp;gt;&lt;br /&gt;                        &lt;br /&gt;                   &amp;lt;TextBox x:Name=&lt;span class="str"&gt;"Fox"&lt;/span&gt;&lt;br /&gt;                       &lt;br /&gt;                        FocusManager.FocusedElement=&lt;span class="str"&gt;"{Binding RelativeSource={RelativeSource Self}}"&lt;/span&gt; &lt;br /&gt;                        Text=&lt;span class="str"&gt;"{Binding Path=Title, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"&lt;/span&gt;&lt;br /&gt;                        Style=&lt;span class="str"&gt;"{StaticResource HighlightTextBoxStyle}"&lt;/span&gt;&lt;br /&gt;                        &amp;gt;&lt;br /&gt;                   &amp;lt;/TextBox&amp;gt;&lt;br /&gt;           &amp;lt;/DataTemplate&amp;gt;&lt;br /&gt;       &amp;lt;/Grid.Resources&amp;gt;&lt;br /&gt;       &amp;lt;DockPanel&amp;gt;&lt;br /&gt;           &amp;lt;TextBox DockPanel.Dock=&lt;span class="str"&gt;"Top"&lt;/span&gt; x:Name=&lt;span class="str"&gt;"Test"&lt;/span&gt; Text=&lt;span class="str"&gt;"{Binding Path=(FocusManager.FocusedElement).Name, ElementName=MyWindow}"&lt;/span&gt;&lt;br /&gt;                    Style=&lt;span class="str"&gt;"{StaticResource HighlightTextBoxStyle}"&lt;/span&gt;/&amp;gt;&lt;br /&gt;           &amp;lt;toolkit:DataGrid ItemsSource=&lt;span class="str"&gt;"{Binding Items}"&lt;/span&gt; AutoGenerateColumns=&lt;span class="str"&gt;"False"&lt;/span&gt;&amp;gt;&lt;br /&gt;               &amp;lt;toolkit:DataGrid.Columns&amp;gt;&lt;br /&gt;                   &amp;lt;toolkit:DataGridTemplateColumn Header=&lt;span class="str"&gt;"Templated Title"&lt;/span&gt;&lt;br /&gt;                   CellTemplate=&lt;span class="str"&gt;"{StaticResource DefaultTitleTemplate}"&lt;/span&gt;&lt;br /&gt;                   CellEditingTemplate=&lt;span class="str"&gt;"{StaticResource EditTitleTemplate}"&lt;/span&gt;&amp;gt;&lt;br /&gt;&lt;br /&gt;                   &amp;lt;/toolkit:DataGridTemplateColumn&amp;gt;&lt;br /&gt;                   &amp;lt;toolkit:DataGridTextColumn Header=&lt;span class="str"&gt;"Title"&lt;/span&gt; &amp;gt;&lt;br /&gt;                       &amp;lt;toolkit:DataGridTextColumn.Binding&amp;gt;&lt;br /&gt;                           &amp;lt;Binding Path=&lt;span class="str"&gt;"Title"&lt;/span&gt;&amp;gt;&lt;br /&gt;                               &amp;lt;Binding.ValidationRules&amp;gt;&lt;br /&gt;                                   &amp;lt;local:CannotBeginWithX/&amp;gt;&lt;br /&gt;                               &amp;lt;/Binding.ValidationRules&amp;gt;&lt;br /&gt;                           &amp;lt;/Binding&amp;gt;&lt;br /&gt;                       &amp;lt;/toolkit:DataGridTextColumn.Binding&amp;gt;&lt;br /&gt;                   &amp;lt;/toolkit:DataGridTextColumn&amp;gt;&lt;br /&gt;           ...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;Still struggling to find the&lt;br /&gt;fix to auto-select the text in the textbox in the expanded edit cell template. &lt;br /&gt;&lt;br /&gt;Update: Got this to work by subscribing to the PreparingCellForEdit event. The editor is passed in as an event argument. For a templatedcolumn, the grid is unable to guess your editor control type. So you need to cast it to your particular editor type and call Focus()+SelectAll() on it. I subscribed to the event in the ctor and wasn't able to get the editor.. You need to wait till the Loaded event to subscribe. Then it worked.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-1446205322015181541?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/1446205322015181541/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2010/04/set-keyboard-focus-when-user-begins.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/1446205322015181541'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/1446205322015181541'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2010/04/set-keyboard-focus-when-user-begins.html' title='Set keyboard focus when the user begins editing a wpf datagrid templatecolumn ?'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-5371456421645986042</id><published>2010-03-20T15:15:00.010+05:30</published><updated>2010-03-22T11:59:07.364+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='Timesavers'/><title type='text'>Humanized's Enso Launcher : Jumpstart</title><content type='html'>&lt;span style="font-family:trebuchet ms;"&gt;Enso is a good example of the axiom that 'Search is faster than navigation'. Its one of the tools that I was introduced to by the book 'The productive programmer' by Neal Ford. It has been handy ever since.&lt;br /&gt;&lt;br /&gt;The concept of the tool is pretty simple... it redefines the way in which you communicate with your machine. e.g. If I want to install or uninstall a program, I do not want to click through a number of windows and dig through menus (and lose my focus by the time I get there). My intention is 'open add or remove programs' so that I can install that new app. It may be a tiny boost but multiplied by the volume of instances / day, Enso can save you a lot of time. So lets get right to it...&lt;br /&gt;&lt;br /&gt;First you need to install &lt;a href="http://www.humanized.com/enso/launcher/"&gt;Humanized's Enso launcher&lt;/a&gt; (12 MB download)&lt;br /&gt;Next it's easier if you are a keyboard person instead of a mouse person. You need some dexterity with your &lt;a href="http://en.wikipedia.org/wiki/Little_finger"&gt;left pinky finger&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Enso takes over your capslock key once installed. So keep capslock pressed down with your left pinky (you should see a green floating band at the top-left) and continue typing to issue commands....&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Opening/Launching programs&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;With Vista and Windows7, this is not something to write home about. Both of them have a real-time search box when you invoke the Start Menu - where you can enter a substring/part of the app you want to invoke and the start menu narrows down your choices.&lt;br /&gt;&lt;br /&gt;However if you're on WinXP, you're gonna love this. e.g I always had to go hunting for the add/remove programs applet inside the Start Menu. (or pick something else e.g. like a specific version of Visual Studio). Soon I'd be piling on quick launch icons ; and even that required you to reach for the mouse. (I like to be one with the keyboard as long as possible).&lt;br /&gt;&lt;br /&gt;Now with enso, reach out your left pinky to the capslock key. Keep it pressed, while you continue to type a substring e.g '&lt;span style="font-weight: bold; color: rgb(0, 0, 102);font-family:courier new;" &gt;open remove&lt;/span&gt;' or '&lt;span style="font-weight: bold; color: rgb(0, 0, 102);font-family:courier new;" &gt;open 2008&lt;/span&gt;' in the green floating band that just popped up. You'll see a dynamically updating dropdown that you can use to select with the arrow keys. When you lift your finger off the capslock key. The selected program shall be opened. No kidding... try it. It's addictive ; No program is ever more than one open command away.&lt;br /&gt;&lt;span style="color: rgb(0, 0, 102); font-weight: bold;"&gt;Useful: Absolutely&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Associate a file/directory/url/shortcut with a command&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Assume you have a directory that you frequently access e.g.&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;d:\mail\snail\wail\jail&lt;/span&gt;&lt;br /&gt;Ensure that the above path is selected (either in the location bar of windows explorer or write it down in notepad and select it). Next use your pinky and type in&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 0, 102);font-family:courier new;" &gt;learn as open jail&lt;/span&gt;&lt;br /&gt;Enso should get back with &lt;span style="font-weight: bold;font-family:courier new;" &gt;'open jail is now a command'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now try opening like before.&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 0, 102);font-family:courier new;" &gt;Caps + 'open jail'&lt;/span&gt;&lt;br /&gt;and you should see a windows explorer window pointed at the right folder.&lt;br /&gt;&lt;br /&gt;You just taught Enso a new command 'jail'.&lt;br /&gt;You can verify this by looking in your MyDocuments folder. You should see a folder created by Enso with all your commands.&lt;br /&gt;This also means that you can carry your enso commands with you across machine (e.g. in a USB storage device), dump it to the local MyDocuments folder and off you go.&lt;br /&gt;&lt;br /&gt;Of course Enso just takes over your capslock key, to regain that function, Enso has 2 commands. Keep caps pressed and type&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;'capslock on' OR&lt;br /&gt;'capslock off'.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;You can make Enso unlearn a command by saying&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 0, 102);font-family:courier new;" &gt;Caps + 'unlearn open jail'&lt;/span&gt; Enso wipes its memory cells clean.&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 0, 102);"&gt;Useful: Usually.&lt;/span&gt; e.g. you could associate your MRU visual studio solution file with a command 'curproj'&lt;br /&gt;&lt;br /&gt;Now try this on selected files/shortcuts.&lt;br /&gt;e.g. Select any exe or shortcut in your file explorer.&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 0, 102);font-family:courier new;" &gt;Caps + learn as open someexe&lt;/span&gt;&lt;br /&gt;Now you can the exe is at your fingertips with&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 0, 102);font-family:courier new;" &gt;'open somexe'&lt;/span&gt;&lt;br /&gt;Works for shortcuts too. You can even create a "rooted view" e.g. create a shortcut for &lt;span style="font-family:courier new;"&gt;%windir%\explorer.exe /e, /root, D:\tarpit\theNextKillerApp&lt;/span&gt;&lt;br /&gt;Select it and learn it as a command. Try it out&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 0, 102);"&gt;Useful: Sometimes&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Works for urls as well. Enso would open up your a new instance/tab of your default browser pointed at the learned url.&lt;br /&gt;e.g. select &lt;span style="font-weight: bold;font-family:courier new;" &gt;http://www.answers.com/topic/dexterity right here.&lt;/span&gt; Teach enso a new command&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 0, 102);font-family:courier new;" &gt;Caps + 'learn as open dex'&lt;/span&gt;&lt;br /&gt;Now you can open this page at any time using&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 0, 102);font-family:courier new;" &gt;open dex&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 0, 102);font-family:courier new;" &gt;Useful: Occasionally&lt;/span&gt; - since browsers have generally better at this; bookmarks, tags and incremental search in the address bar.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Jump/Switch to an open window or tab in a browser&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;This one is nice.&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 0, 102);font-family:courier new;" &gt;Caps + 'go google'&lt;/span&gt;&lt;br /&gt;or&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 0, 102);font-family:courier new;" &gt;go task&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;jump&lt;/span&gt; directly to an open window which has that substring in the window title.&lt;br /&gt;Its works for browser tabs too - if you had a minimized or buried browser with a tab showing google's homepage, the right browser and child tab would be activated. Its a shame it doesn't work with Firefox3.. seems to be a bug that could be fixed. Works with IE8&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 0, 102);font-family:courier new;" &gt;Useful: Pretty much&lt;/span&gt; ; wish I could unlearn alt+tab-ing as easily as Enso.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Open with ...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This one is supereasy but hasn't become second nature to me yet. You can select any file (e.g. in a file explorer)&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 0, 102);font-family:courier new;" &gt;Caps + 'open with [name of app]'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;and Enso does just that. e.g. &lt;span style="font-weight: bold; color: rgb(0, 0, 102);font-family:courier new;" &gt;'open with notepad'&lt;/span&gt; will open up the selected file in notepad.&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 0, 102);font-family:courier new;" &gt;Useful: Yes. &lt;/span&gt; No more Shift+right click &gt; Open with ... &gt; hunt for the exe if !inList. Freedom!!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt; Close active window/tab&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;the command is close. I like dismissing windows with&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 0, 102);font-family:courier new;" &gt;Caps +'cl'&lt;/span&gt;&lt;br /&gt;Enso can do minimize and maximise too.&lt;br /&gt;&lt;br /&gt;For more inbuilt commands, Use &lt;span style="font-weight: bold; color: rgb(0, 0, 102);font-family:courier new;" &gt;Caps + 'command list'&lt;/span&gt; to have a look at inbuilt commands. I believe you can script custom commands too (e.g. 'mail' instead of 'open Outlook') if you know a bit of Python. However that's outside the scope of this post :)&lt;br /&gt;&lt;br /&gt;That's all folks!&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-5371456421645986042?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/5371456421645986042/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2010/03/humanizeds-enso-launcher-jumpstart.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/5371456421645986042'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/5371456421645986042'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2010/03/humanizeds-enso-launcher-jumpstart.html' title='Humanized&apos;s Enso Launcher : Jumpstart'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-1945662444180577364</id><published>2010-03-17T20:25:00.006+05:30</published><updated>2010-08-07T20:48:49.685+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='xtreamer'/><category scheme='http://www.blogger.com/atom/ns#' term='sharing'/><category scheme='http://www.blogger.com/atom/ns#' term='gadget-grappling'/><title type='text'>HOW TO : Setup your Xtreamer to stream content off Windows (Win7) machines via a wifi network</title><content type='html'>&lt;span style="font-family: trebuchet ms; color: rgb(0, 102, 0);"&gt;Update#2 [Apr 2010]: Sent the wireless USB dongle back to their seller in India since it was within the warranty period. They sent me a new dongle, free of cost. Now the whole setup is functional again. The online forum on the other hand was another deal altogether...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 0, 0);"&gt;Update: My Xtreamer has stopped communicating via wifi after 3 days, without any configuration changes. "Can't get SSID" is the only response I get from the network settings page. The Wifi antenna drivers are proprietary (available for download) and hence I can't isolate the problem to the antenna. 2 subsequent posts to the Xtreamer forum have been mysteriously being deleted without any dialogue/clarification. Verdict as of now: Flaky antenna/connection finder.. wouldn't get this if streaming is your main need.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;This post details my skirmishes in getting my Xtreamer (a streaming media player) to wirelessly stream content off my Windows7 laptop via a DLink N-Router. You could hook it up such that the Xtreamer can also access the internet - but I haven't done that. I intend to use the Xtreamer on a local trusted network and internet access on a diff public wireless network.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;span style="font-weight: bold;"&gt;Step1: Update your Xtreamer firmware.&lt;/span&gt; I have version 2.3.1. You download the firmware zip, unzip it to get an .xtr file. Place the file in the root dir of a USB pendrive and connect it to the Xtreamer. Power it on - Main Menu &gt; Settings &gt; System &gt; Upgrade. Browse and select the .xtr file. It should upgrade and reboot.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;span style="font-weight: bold;"&gt;Step2: Get your network running and get your machine on it.&lt;/span&gt; Get your wireless router connected to your PC. Mine came with a CD with a wizard for basic setup.&lt;br /&gt;&lt;br /&gt;Next enter the Web Config of the router. e.g. http://192.168.0.1&lt;br /&gt;You would be prompted for the credentials to login into the router. Refer to your memory / the manual as necessary. Make sure you change your router password from the defaults.&lt;br /&gt;For my DLink DIR-615, I navigate via Setup &gt; Wireless Settings &gt; Manual Wireless Conn Setup &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;SSID / Wireless N.w name = MySecretNetwork&lt;/li&gt;&lt;li&gt;802.11 mode = use mixed b/g/n if you're not sure&lt;/li&gt;&lt;li&gt;visibility = Visible.&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:trebuchet ms;"&gt;You can hide it / set to Invisible after you've scanned the settings into the xtreamer. &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Set SecurityMode = None initially ; till you are positive that you have the network working first.&lt;br /&gt;If you have the network working, secure it. My settings are as...&lt;br /&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;SecurityMode = WPA Personal&lt;/li&gt;&lt;li&gt;WPA Mode = Auto (WPA / WPA2)&lt;/li&gt;&lt;li&gt;Cipher Type = TKIP&lt;/li&gt;&lt;li&gt;GroupKeyInterval = 3600 sec&lt;/li&gt;&lt;li&gt;Pre-sharedKey = supersecretpwd&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:trebuchet ms;"&gt;Save these settings. This should reboot the router. So you'd have to reconnect again to wireless network - MySecretNetwork.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Click on the wireless icon in the tasktray - choose the network. You will be prompted for the password - key in your supersecretpwd&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;To verify that you're connected. Try getting to your router web config page again in a new browser window. It should work.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:trebuchet ms;" &gt;Step3: Get the Xtreamer on the network. &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;From the main menu, Settings &gt; Network &gt; Wireless Setup.&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Select a connection profile: Choose a free slot e.g. Connection2 and press Right to go to the next screen.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Get Conn mode: Choose Infrastructure (AP) and go Right&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;You should see a drop down containing your network/ssid name. Woohoo! Go Right&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Next it will prompt you for the WPA Key (for a secure network). Use the onscreen keyboard to key in your supersecretpwd and hit OK.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Choose DHCP IP (Auto) at the next screen.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Now you're at the moment of reckoning. You'd be shown a summary of your choices and asked to confirm. Go Right to test your connection.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;If all goes well, you should see Test Ok and Show Net Info (summary of network parameters).&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Press Enter to complete task. &lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:trebuchet ms;"&gt;You should now see &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;On*: [AssignedIP] as the value for the Wireless Setup property in the Settings &gt; Network page.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:trebuchet ms;" &gt;Step4: Gentlemen (n ladies) share your folders&lt;br /&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Select the folder c:\MyShare in Win7 and bring up Properties &gt; Sharing &gt; Advanced Sharing...&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Enter a name for your share, a comment if you wish. &lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Next click on Permissions and add a credential (user/pwd/domain) that you'd use to access the share remotely.&lt;span style="color: rgb(153, 0, 0);"&gt; &lt;/span&gt;&lt;span style="font-weight: bold; color: rgb(153, 0, 0);"&gt;Use a non-guest account. &lt;/span&gt;&lt;span style="color: rgb(153, 0, 0);"&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;I was not able to get it to work with the default guest account.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:trebuchet ms;"&gt;Repeat the above for all shares.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;You also need to turn off at the network connection level&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Click on the Network and Sharing Center link on the Sharing tab. Verify the following settings for the current (home or work) profile&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Set Password protected shares = Off.&lt;/li&gt;&lt;li&gt;Public Folder sharing = On&lt;/li&gt;&lt;li&gt;File and printer sharing = On&lt;/li&gt;&lt;li&gt;Network Discovery = On&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;span style="font-weight: bold;"&gt;Tell your firewall to let in the media:&lt;/span&gt;  Finally, you need to ensure that you're firewall is not gonna play spoilsport. Bring up your firewall.. Kaspersky in my case&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Settings &gt; Protection &gt; Firewall &gt; Settings.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Go to the networks tab. &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Select your network (which is currently showing as Public). Right click and mark it as trusted. Easiest way to get this over with. Of course if you are accessing the internet this isn't the way to do it. You'd need to configure it at a more granular level. Ok out. You can verify by setting up 2 machines on the wifi network and pinging each other ; if packets are received correctly, you're all set.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Step5: Time to stream&lt;/span&gt;&lt;br /&gt;So now you have the PC and Xtreamer on the network, shares created and reachable.&lt;br /&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Press home on your Xtreamer to get to the main menu &gt; Media Library &gt; NET. &lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Select My_Shortcuts.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Press 1 on your remote. Select Add in the popup.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Use down and right to click the detail button.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Now navigate back up and enter the username, pwd, domain, File Server IP (ignore the other params) Press Enter in each field to bring up the onscreen keyboard. Use the numeric keys on the remote for the IP addr. Remember this is the set of credentials that you used on the Permissions dialog when you shared the folders.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Click OK. Save the network setting.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;br /&gt;You should now see a shortcut like &lt;span style="color: rgb(0, 0, 153);"&gt;fileserverIP:username&lt;/span&gt;. Select it by pressing Enter. If you've entered everything correctly. You should see a red "&lt;span style="color: rgb(255, 0, 0);"&gt;Logon successful&lt;/span&gt;" at the top-right; below  a listing of all shares on that machine.&lt;br /&gt;Sometimes you maybe prompted for a user-name/pwd for an individual share. Not sure why this happens - however enter and choose 'OK and save'. Xtreamer will remember it for you from now on.&lt;br /&gt;&lt;br /&gt;You should now see all files in the shared folder. Choose a movie and hit OK to begin the streaming... and yeah it's all set for you to scream in joy!&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-1945662444180577364?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/1945662444180577364/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2010/03/how-to-setup-your-xtreamer-to-stream.html#comment-form' title='16 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/1945662444180577364'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/1945662444180577364'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2010/03/how-to-setup-your-xtreamer-to-stream.html' title='HOW TO : Setup your Xtreamer to stream content off Windows (Win7) machines via a wifi network'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><thr:total>16</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-356550129244990737</id><published>2010-03-10T15:57:00.006+05:30</published><updated>2010-03-10T17:27:32.639+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='NUnit'/><title type='text'>NUnit ExpectedException Bug in 2.4.7</title><content type='html'>&lt;span style="font-family: trebuchet ms;"&gt;"Bug In NUnit ? It can't be!" Exactly my words ; However it turned out that the behavior is due to a &lt;span style="font-weight:bold;"&gt;newer&lt;/span&gt; NUnit runner (Gui v 2.5.3) running a test fixture referencing an &lt;span style="font-weight:bold;"&gt;older&lt;/span&gt; version of NUnit.Framework.dll (v2.4.7)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;Try this in a NUnit test fixture referencing NUnit.Framework v 2.4.7&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="rem"&gt;// 2.4.7 - test passes even if an exception of wrong type is thrown&lt;/span&gt;&lt;br /&gt;        [ExpectedException(ExceptionType=&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(FileNotFoundException))]&lt;br /&gt;        [Test]&lt;br /&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Test_ExpectedException()&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentException();&lt;br /&gt;        }&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;I found that the test passes if "&lt;span style="font-weight:bold;"&gt;any&lt;/span&gt;" exception is thrown. It doesn't have to match the specified type. A false positive! &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;To fix this, upgrade your NUnit version to 2.5.2. You'd also need to fix a compile error. 'ExceptionType' property has now become ExpectedException.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="rem"&gt;//2.5.2 'works as expected'&lt;/span&gt;&lt;br /&gt;        [ExpectedException(ExpectedException=&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(FileNotFoundException))]&lt;br /&gt;        [Test]&lt;br /&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Test_ExpectedException()&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentException();&lt;br /&gt;        }&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;You live... you learn.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-356550129244990737?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/356550129244990737/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2010/03/nunit-expectedexception-bug-in-247.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/356550129244990737'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/356550129244990737'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2010/03/nunit-expectedexception-bug-in-247.html' title='NUnit ExpectedException Bug in 2.4.7'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-4723390702954806892</id><published>2010-03-02T14:30:00.007+05:30</published><updated>2010-03-02T18:18:03.081+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='metaprogramming'/><title type='text'>Method resolution in Ruby : OR how to find Mr. Right method?</title><content type='html'>&lt;span style="font-family:trebuchet ms;"&gt;Before I begin: Some of the stuff below may be incorrect (Corrections welcome.), however it helps me understand ruby method resolution. I have come up with this model based on my reading of the &lt;a href="http://oreilly.com/catalog/9780596516178"&gt;RubyProgrammingLanguage book&lt;/a&gt; (must-read for anyone learning Ruby) by Flanagan &amp;amp; Matz and some tinkering.. it may not be accurate (if that is what you're after)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Basket of Facts&lt;/span&gt;:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;A Ruby type is an object of type 'Class' (henceforth referred to as a class-object)&lt;/li&gt;&lt;li&gt;An object has a class attribute pointing to the right class-object.&lt;/li&gt;&lt;li&gt;An object has an "&lt;span style="font-weight: bold;"&gt;eigenclass&lt;/span&gt;"/"&lt;span style="font-weight: bold;"&gt;metaclass&lt;/span&gt;" that holds singleton methods (methods that are only available to that instance.)&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;class-objects are special in a few ways:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;a class-object has its class attribute pointing to the 'Class' type in Ruby&lt;/li&gt;&lt;li&gt;a class-object has a superclass&lt;/li&gt;&lt;li&gt;the "eigenclass" of a class-object also has a superclass; the eigenclass of its superclass&lt;/li&gt;&lt;li&gt;a class-object has an included modules list&lt;/li&gt;&lt;li&gt;a class-object has a table of methods (instance methods defined in the class definition)&lt;/li&gt;&lt;li&gt;class methods are singleton methods of the class-object&lt;/li&gt;&lt;li&gt;a class-object is generally associated with a constant viz. it's class name.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;So now let's get started. Don't let the following mouse-drawn picture scare you - it'll all make (some?) sense in sometime. In the meantime, right click on it and open it up in a new tab and have the picture handy for reference while you descend into this post. &lt;/span&gt;&lt;br /&gt;&lt;a href="http://picasaweb.google.com/lh/photo/TjNU4MgJqqlycKFIZdxPWA?authkey=Gv1sRgCNTm5f7KtOeXBw&amp;amp;feat=embedwebsite"&gt;&lt;br /&gt;&lt;img src="http://lh4.ggpht.com/_nxgDpneh8yk/S4zggCXH5bI/AAAAAAAAA1w/plpavR1nqrc/s800/RTS_2.PNG" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Next jump right over this big puddle of source code. You can copy it into your editor if you want to try it out with me..&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="keyword"&gt;module &lt;/span&gt;&lt;span class="module"&gt;Kernel&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;breadcrumb&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Kernel#breadcrumb&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class="constant"&gt;Module&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;nesting&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;instance_eval&lt;/span&gt;&lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="ident"&gt;remove_method&lt;/span&gt; &lt;span class="symbol"&gt;:breadcrumb&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Object&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;breadcrumb&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Object#breadcrumb&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class="constant"&gt;Module&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;nesting&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;instance_eval&lt;/span&gt;&lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="ident"&gt;remove_method&lt;/span&gt; &lt;span class="symbol"&gt;:breadcrumb&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;self.breadcrumb&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Object.breadcrumb&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Module&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;nesting&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;&lt;br /&gt;      &lt;span class="ident"&gt;instance_eval&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="ident"&gt;remove_method&lt;/span&gt; &lt;span class="symbol"&gt;:breadcrumb&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;module &lt;/span&gt;&lt;span class="module"&gt;MyModule&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;breadcrumb&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;MyModule#breadcrumb&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class="constant"&gt;Module&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;nesting&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;instance_eval&lt;/span&gt;&lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="ident"&gt;remove_method&lt;/span&gt; &lt;span class="symbol"&gt;:breadcrumb&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Base&lt;/span&gt;&lt;br /&gt;  &lt;span class="constant"&gt;MY_CONST&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="symbol"&gt;:b&lt;/span&gt;&lt;br /&gt;  &lt;span class="ident"&gt;include&lt;/span&gt; &lt;span class="constant"&gt;MyModule&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;breadcrumb&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Base#breadcrumb&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;;&lt;/span&gt;&lt;br /&gt;    &lt;span class="constant"&gt;Base&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;class_eval&lt;/span&gt;&lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="ident"&gt;remove_method&lt;/span&gt; &lt;span class="symbol"&gt;:breadcrumb&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="comment"&gt;#     Base.instance_eval{ remove_method :breadcrumb } UH-OH! why does this remove the inst method&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;self.breadcrumb&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Base.breadcrumb&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Module&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;nesting&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;&lt;br /&gt;      &lt;span class="ident"&gt;instance_eval&lt;/span&gt;&lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="ident"&gt;remove_method&lt;/span&gt; &lt;span class="symbol"&gt;:breadcrumb&lt;/span&gt;&lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Derived&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Base&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;breadcrumb&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Derived#breadcrumb&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;;&lt;/span&gt;&lt;br /&gt;    &lt;span class="constant"&gt;Module&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;nesting&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;instance_eval&lt;/span&gt;&lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="ident"&gt;remove_method&lt;/span&gt; &lt;span class="symbol"&gt;:breadcrumb&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;self.breadcrumb&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Derived.breadcrumb&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt;&lt;br /&gt;      &lt;span class="ident"&gt;instance_eval&lt;/span&gt;&lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="ident"&gt;remove_method&lt;/span&gt; &lt;span class="symbol"&gt;:breadcrumb&lt;/span&gt;&lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Class&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;breadcrumb&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Class#breadcrumb&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;;&lt;/span&gt;&lt;br /&gt;    &lt;span class="constant"&gt;Class&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;class_eval&lt;/span&gt;&lt;span class="punct"&gt;{&lt;/span&gt;    &lt;span class="ident"&gt;remove_method&lt;/span&gt; &lt;span class="symbol"&gt;:breadcrumb&lt;/span&gt;  &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Module&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;breadcrumb&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Module#breadcrumb&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;;&lt;/span&gt;&lt;br /&gt;    &lt;span class="constant"&gt;Module&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;class_eval&lt;/span&gt;&lt;span class="punct"&gt;{&lt;/span&gt;    &lt;span class="ident"&gt;remove_method&lt;/span&gt; &lt;span class="symbol"&gt;:breadcrumb&lt;/span&gt;  &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;****LANDING ZONE****&lt;br /&gt;Nice Jump!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;I have defined a new class called 'Derived' which derives from 'Base' and includes 'MyModule'.&lt;br /&gt;Unless a base type is explicitly specified, all classes derive from Object (which includes Kernel) (and derives from BasicObject - new in Ruby 1.9). e.g. Base derives from Object. This can be verified via&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="ident"&gt;d&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Derived&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;p&lt;/span&gt; &lt;span class="ident"&gt;d&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;class&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;ancestors&lt;/span&gt; &lt;span class="comment"&gt;# =&amp;gt; [Derived, Base, MyModule, Object, Kernel, BasicObject]&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Base and Derived each have defined a class method (self.breadcrumb) and an instance method (breadcrumb). MyModule just defines a module method of the same name.&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Convention: Class/Singleton methods would print &lt;span style="font-weight: bold;"&gt;receiver.breadcrumb&lt;/span&gt;. Instance methods would print &lt;span style="font-weight: bold;"&gt;receiver#breadcrumb&lt;/span&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Take a deep breath and dive in...&lt;br /&gt;&lt;br /&gt;First lets create a new instance of Derived and add a singleton method to it. (i.e. a method that is present only in that instance. Another instance of Derived would not have this method)&lt;br /&gt;Here's how we do that...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="ident"&gt;d&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Derived&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="ident"&gt;d&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;breadcrumb&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;DerivedObj[id:%d].breadcrumb&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt; &lt;span class="punct"&gt;%&lt;/span&gt; &lt;span class="ident"&gt;object_id&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt;&lt;br /&gt; &lt;span class="ident"&gt;instance_eval&lt;/span&gt;&lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="ident"&gt;remove_method&lt;/span&gt; &lt;span class="symbol"&gt;:breadcrumb&lt;/span&gt;&lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;'Call once': once the method is called, the method disappears (is 'undefined'). This will help us uncover the order in Ruby tries to find a method. I have added such methods in all types up the hierarchy (and then some) to help us spot the trail.&lt;br /&gt;(Note: Instance methods use class_eval to remove themselves. Singleton/class methods use instance_eval. Refer to the RPL book)&lt;br /&gt;&lt;br /&gt;And now for the moment of truth &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;Method call on an object&lt;/span&gt;&lt;span class="punct"&gt;".&lt;/span&gt;&lt;span class="ident"&gt;center&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;40&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;*&lt;/span&gt;&lt;span class="punct"&gt;")&lt;/span&gt;&lt;br /&gt;&lt;span class="number"&gt;6&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;times&lt;/span&gt;&lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="ident"&gt;d&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;breadcrumb&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:verdana;font-size:100%;"  &gt;Output:&lt;br /&gt;********Method call on an object********&lt;br /&gt;DerivedObj[id:6186928].breadcrumb&lt;br /&gt;Derived#breadcrumb&lt;br /&gt;Base#breadcrumb&lt;br /&gt;MyModule#breadcrumb&lt;br /&gt;Object#breadcrumb&lt;br /&gt;Kernel#breadcrumb&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Refer to the image  (I was reading Why's Nobody know Shoes; which might explain some of the weird imagery and the helpfulness of it all ;) So here's what happened in the sequence illustrated by our 'call-once' breadcrumbs:&lt;br /&gt;&lt;br /&gt;To the extreme left is our object d,&lt;br /&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Call1: Find the eigenclass of d, look for a singleton method of that name. Found!&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Call2: .. not found in eigenclass, find the class-object of d via the class attribute. Look in the methods defined in class Derived. Found!&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Call3: .. not found in eigenclass/class. Look in included modules of D (most recently included one first).. there are none. Travel via the superclass portal to reach Base. Look for inst method. Found!&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Call4: .. not found in eigen/class/incl module/superclass. Try included modules of superclass e.g. MyModule. Found!&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Call5: .. not found in eigen/class-n-its-modules/superclass-n-its-modules. Go down the superclass portal again to reach Object. Look at instance methods. Found!&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Call6: .. look in incl. modules of Object. Kernel. Found!&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;If you try calling the method again, Ruby would not be able to find a method of that name and would now try looking for a method_missing method (in the same manner as it tried looking for breadcrumb. However this time it is guaranteed to find it because Kernel has a method_missing implementation that raises the NoMethodError. Need to see it to believe it?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:verdana;font-size:100%;"  &gt;temp.rb:84:in `block in &lt;main&gt;': undefined method `breadcrumb' for #&lt;derived:0xbcce40&gt; (NoMethodError)&lt;br /&gt;from temp.rb:84:in `times'&lt;br /&gt;from temp.rb:84:in `&lt;main&gt;'&lt;/main&gt;&lt;/derived:0xbcce40&gt;&lt;/main&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;So lets recap the steps.&lt;br /&gt;1. Look in the eigenclass (golden arrow) for the class&lt;br /&gt;2. If not found, traverse the class attribute (purple arrow) to find the class-object.&lt;br /&gt;3. Look in the instance methods for this class&lt;br /&gt;4. If not found, try included modules of the class (in reverse order of mixin)&lt;br /&gt;5. If not found, check if we have a superclass (pink arrow). If yes, repeat steps 3-5 till we run out of superclasses&lt;br /&gt;6. If still not found, go back to Step1 but this time look for a 'method_missing' method'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;By the way, we just saw how instance methods are inherited. (Snuck that one on you.) If Derived doesn't define an instance method, all its ancestors are looked up in order ; inheritance works.&lt;br /&gt;&lt;br /&gt;Take a break, have some lemonade before we set out again... Ready? Off we go again. This time instead of calling a method on an object, we call a class method. Comment the previous 2 lines...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;Method call on a class-object&lt;/span&gt;&lt;span class="punct"&gt;".&lt;/span&gt;&lt;span class="ident"&gt;center&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;40&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;*&lt;/span&gt;&lt;span class="punct"&gt;")&lt;/span&gt;&lt;br /&gt;&lt;span class="number"&gt;7&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;times&lt;/span&gt;&lt;span class="punct"&gt;{&lt;/span&gt;  &lt;span class="constant"&gt;Derived&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;breadcrumb&lt;/span&gt;  &lt;span class="punct"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);font-family:verdana;font-size:100%;"  &gt;Output:&lt;br /&gt;*****Method call on a class-object******&lt;br /&gt;Derived.breadcrumb&lt;br /&gt;Base.breadcrumb&lt;br /&gt;Object.breadcrumb&lt;br /&gt;Class#breadcrumb&lt;br /&gt;Module#breadcrumb&lt;br /&gt;Object#breadcrumb&lt;br /&gt;Kernel#breadcrumb&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Hey! we see some instance methods being invoked when we call a class method. What the... Deep breaths 1..2..3..pfffhoooo (u got to get the pfffhoooo right)&lt;br /&gt;&lt;br /&gt;Let's see if our image can help us out, find the object pointed to by the constant Derived (3rd box from the left - first row)&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Call1: Start at Derived. Follow the golden arrow to the Derived's eigenclass - Derived". Look for a singleton method. Found!&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Call2: .. not found in eigenclass. But eigenclasses of class-objects have superclasses. Follow the golden arrow to Base's eigenclass. Found!&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Call3: .. not found in Derived" or Base". But we still have a golden arrow to Object". Found!&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Call4: .. not found in Derived"/Base"/Object".Try BasicObject" too. Not found. Now we're out of superclasses. Now we follow the purple arrow to the class-object of Derived i.e. Class. Look for  instance methods defined there. Found!&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Call5: .. not found in the eigenclass hierarchy or class-object. Try included modules in Class. not found. But wait, we have a superclass. Down the pink arrow to Module. Look for an instance method... found!&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Call6: .. not found in eigenclass hierarchy/Class-n-included-modules/Module. Try included modules in Module. Nope. Down the pink arrow to Object. Found an instance method!&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Call7: .. not found in eigenclass hierarchy/Class-n-incl-modules/Module-n-incl-modules/Object. Look in included modules of Object.. aha Kernel. Look for method.. found!&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;If you make one more call, you should now be guessing that a NoMethodError should show up from Kernel#method_missing(similar to the previous example)&lt;br /&gt;&lt;br /&gt;So lets refactor &lt;span style="font-weight: bold;"&gt;the steps&lt;/span&gt;.&lt;br /&gt;&lt;/span&gt;&lt;ol&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;span style="color: rgb(102, 0, 0);font-size:100%;" &gt;Look for the method in the &lt;span style="font-weight: bold;"&gt;eigenclass &lt;/span&gt;(yellow arrow). Until we run out of &lt;span style="font-weight: bold;"&gt;superclasses for the eigenclass&lt;/span&gt;, inspect each eigenclass for the method. &lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;span style="color: rgb(102, 0, 0);font-size:100%;" &gt;If not found, traverse the class attribute (purple arrow) to &lt;span style="font-weight: bold;"&gt;find the class-object&lt;/span&gt;. &lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;span style="color: rgb(102, 0, 0);font-size:100%;" &gt;Look in the &lt;span style="font-weight: bold;"&gt;instance methods&lt;/span&gt; for this class&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;span style="color: rgb(102, 0, 0);font-size:100%;" &gt;If not found, try &lt;span style="font-weight: bold;"&gt;included modules&lt;/span&gt; of the class (&lt;span style="font-weight: bold;"&gt;in reverse order&lt;/span&gt; of mixin)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;span style="color: rgb(102, 0, 0);font-size:100%;" &gt;If not found, &lt;span style="font-weight: bold;"&gt;check if we have a superclass&lt;/span&gt; (pink arrow). If yes, &lt;span style="font-weight: bold;"&gt;repeat steps 3-5&lt;/span&gt; till we run out of superclasses&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;span style="color: rgb(102, 0, 0);font-size:100%;" &gt;If still not found, go back to Step1 but this time &lt;span style="font-weight: bold;"&gt;look for a 'method_missing' method&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;br /&gt;So the only new tidbits were&lt;br /&gt;&lt;ul&gt;&lt;li&gt;class methods are singleton methods of class-objects. They live in the green clouds tied with the yellow arrows to the class.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;eigenclass of a class-object is special. These special 'green clouds' have superclasses. &lt;/li&gt;&lt;/ul&gt;And that is the secret behind class method inheritance... See the first three lines of the output. (Snuck another one.. {snicker} No more I promise.)&lt;br /&gt;&lt;br /&gt;And that also explains how class method calls can result in instance methods being called. (Lines4-7)&lt;br /&gt;&lt;br /&gt;And that's it folks! You will wake up enlightened or confused when I snap my fingers :)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;As an exercise to people who like to stay and flex some meta-programming muscles. Try and explain this predicament.&lt;br /&gt;&lt;br /&gt;Module defines a &lt;span style="font-weight: bold;"&gt;constants &lt;/span&gt;method, which returns the list of all known constants (incl. class names).&lt;br /&gt;Module.constants =&gt; 102&lt;br /&gt;Any user-defined class e.g. Base or Derived inherits this method ; however Base.constants returns only the constants defined inside Base (and its superclasses). e.g. If I add a constant inside Base.&lt;br /&gt;Base.constants =&gt; 1&lt;br /&gt;How does Module's constants behave differently in the Base (which inherits this functionality)?&lt;br /&gt;&lt;br /&gt;Hint: Check Module.singleton_methods and Module.public instance_methods&lt;br /&gt;Hint2: Hit Stackoverflow and search for the answer once you have taken a good crack at it.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-4723390702954806892?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/4723390702954806892/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2010/03/method-resolution-in-ruby-or-how-to.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/4723390702954806892'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/4723390702954806892'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2010/03/method-resolution-in-ruby-or-how-to.html' title='Method resolution in Ruby : OR how to find Mr. Right method?'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_nxgDpneh8yk/S4zggCXH5bI/AAAAAAAAA1w/plpavR1nqrc/s72-c/RTS_2.PNG' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-713581711685659894</id><published>2010-01-26T22:14:00.004+05:30</published><updated>2010-01-26T23:20:20.280+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='Rhino'/><category scheme='http://www.blogger.com/atom/ns#' term='Mocks'/><category scheme='http://www.blogger.com/atom/ns#' term='jMock'/><category scheme='http://www.blogger.com/atom/ns#' term='Moq'/><title type='text'>Meet the frameworks : Rhino v Moq v jMock : Part II</title><content type='html'>&lt;span style="font-family:trebuchet ms;"&gt;&lt;a href="http://madcoderspeak.blogspot.com/2010/01/meet-frameworks-rhino-mocks-v-moq-v.html"&gt;Story so far&lt;/a&gt;&lt;br /&gt;We've seen how to&lt;br /&gt;   * setup expectations for calls on methods/properties.&lt;br /&gt;   * specify the number of times to be called.&lt;br /&gt;   * specify values to be returned&lt;br /&gt;&lt;br /&gt;Now I move onto more involved scenarios.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:130%;"  &gt;&lt;a id="scen6"&gt;#6:&lt;/a&gt;Throw an exception in response to an expected call on mockCollaborator.Method()&lt;/span&gt;&lt;br /&gt;&lt;ul style="color: rgb(204, 0, 0);"&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:100%;"  &gt;Rhino Mocks&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;       [ExpectedException(ExceptionType=&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(UnableToServeException),&lt;br /&gt;            MatchType=MessageMatch.Contains,&lt;br /&gt;            ExpectedMessage=&lt;span class="str"&gt;"Sorry for the inconvenience."&lt;/span&gt;)]&lt;br /&gt;       [Test]&lt;br /&gt;       &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Test_ExpectExceptionToBeThrown()&lt;br /&gt;       {&lt;br /&gt;           _mockChef.Expect(chef =&amp;gt; chef.Bake(CakeFlavors.Pineapple, &lt;span class="kwrd"&gt;false&lt;/span&gt;)).Throw(&lt;span class="kwrd"&gt;new&lt;/span&gt; Exception());&lt;br /&gt;&lt;br /&gt;           _bakery.PlaceOrder(OrderForOnePineappleCakeNoIcing);&lt;br /&gt;       }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;The Throw method tagged onto the end of the Expect does the trick of raising any derivation of Exception (here I've raised a generic Exception)&lt;/span&gt;&lt;br /&gt;&lt;ul style="color: rgb(0, 0, 153);"&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:100%;"  &gt;Moq &lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;       [ExpectedException(ExceptionType=&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(UnableToServeException),&lt;br /&gt;           MatchType=MessageMatch.Contains,&lt;br /&gt;           ExpectedMessage=&lt;span class="str"&gt;"Sorry for the inconvenience."&lt;/span&gt;)]&lt;br /&gt;       [Test]&lt;br /&gt;       &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Test_ExpectExceptionToBeThrown()&lt;br /&gt;       {&lt;br /&gt;           _mockChef.Setup( chef =&amp;gt; chef.Bake(CakeFlavors.Pineapple, &lt;span class="kwrd"&gt;false&lt;/span&gt;)).Throws&amp;lt;Exception&amp;gt;();&lt;br /&gt;           _bakery.PlaceOrder( OrderForOnePineappleCakeNoIcing );&lt;br /&gt;       }&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Moq uses a generic Throws&lt;texception&gt;() to achieve the result&lt;/texception&gt;&lt;/span&gt;&lt;br /&gt;&lt;ul style="color: rgb(0, 102, 0);"&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:100%;"  &gt;jMock &lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt; @Test&lt;br /&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; test_expectAndThrowException() throws OutOfIngredientsException&lt;br /&gt; {&lt;br /&gt;   final Sequence aSequence = context.sequence(&lt;span class="str"&gt;"retryBake"&lt;/span&gt;);&lt;br /&gt;   context.checking( &lt;span class="kwrd"&gt;new&lt;/span&gt; Expectations() {{&lt;br /&gt;     oneOf(_mockChef).bakeRealWorld( CakeFlavors.Pineapple, &lt;span class="kwrd"&gt;false&lt;/span&gt; );&lt;br /&gt;       will(throwException(&lt;span class="kwrd"&gt;new&lt;/span&gt; OutOfIngredientsException() ));&lt;br /&gt;       inSequence(aSequence);&lt;br /&gt;     oneOf(_mockInventory).replenishStocks();&lt;br /&gt;       inSequence(aSequence);&lt;br /&gt;     oneOf(_mockChef).bakeRealWorld( CakeFlavors.Pineapple, &lt;span class="kwrd"&gt;false&lt;/span&gt; );&lt;br /&gt;       inSequence(aSequence);&lt;br /&gt;   }});&lt;br /&gt;  &lt;br /&gt;   _bakery.placeOrderRealWorld( OrderForOnePineappleCakeNoIcing() ); &lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;The will(throwException(exceptionInstance) after an expectation does the trick.  Ignore the lines in Sequence (I'll get to them in Section#9)&lt;br /&gt;&lt;br /&gt;Java's checked exceptions and explicit method specification (all the way up the call-chain) feels a bit too rigid to me (maybe due to my .Net exposure). So I've created an overload of Bake that throws an exception, to avoid adding a throws clause to every test method that has an expectation for Bake(). Worked for me.. although it's not the right thing to do. The joys of coding in a toy example!&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;void bakeRealWorld(CakeFlavors flavor, boolean withIcing) throws OutOfIngredientsException;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:130%;"  &gt;&lt;a id="scen7"&gt;#7:&lt;/a&gt;Custom callbacks or blocks of code to execute when a mockCollaborator.Method() is called&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Let me cook up a use for this. Let's say I want the first call to Chef.Bake throw an OutOfIngredientsException(), so that I can call ReplenishStocks() and retry. This time, the call to Chef.Bake should go through.&lt;br /&gt;&lt;br /&gt;Just the kind of job for... custom Callbacks!&lt;/span&gt;&lt;br /&gt;&lt;ul style="color: rgb(204, 0, 0);"&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:100%;"  &gt;Rhino Mocks&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;       [Test]&lt;br /&gt;       &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Test_ExpectWithCustomCallback()&lt;br /&gt;       {&lt;br /&gt;           &lt;span class="kwrd"&gt;int&lt;/span&gt; callbacks = 0;&lt;br /&gt;           _mockChef.Expect(chef =&amp;gt; chef.Bake(CakeFlavors.Pineapple, &lt;span class="kwrd"&gt;false&lt;/span&gt;))&lt;br /&gt;               .Repeat.Times(2)&lt;br /&gt;               .WhenCalled(&lt;span class="kwrd"&gt;delegate&lt;/span&gt;(MethodInvocation mi) {&lt;br /&gt;                   Console.WriteLine(&lt;span class="str"&gt;"Callback Params: {0}, {1}"&lt;/span&gt;, mi.Arguments[0], mi.Arguments[1]);&lt;br /&gt;                   callbacks += 1;&lt;br /&gt;                   &lt;span class="kwrd"&gt;if&lt;/span&gt; (callbacks == 1)&lt;br /&gt;                       &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; OutOfIngredientsException();&lt;br /&gt;&lt;br /&gt;                   &lt;span class="kwrd"&gt;return&lt;/span&gt;;&lt;br /&gt;               });&lt;br /&gt;           _mockInventory.Expect(inv =&amp;gt; inv.ReplenishStocks()).Return(&lt;span class="kwrd"&gt;true&lt;/span&gt;);&lt;br /&gt;          &lt;br /&gt;           _bakery.PlaceOrder(OrderForOnePineappleCakeNoIcing);&lt;br /&gt;          &lt;br /&gt;           _mockChef.VerifyAllExpectations();&lt;br /&gt;           _mockInventory.VerifyAllExpectations();&lt;br /&gt;       }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Tag on WhenCalled(delegateWithCustomCode) to the expectation. Also note that you have access to the method arguments as shown in the Console trace above.&lt;/span&gt;&lt;br /&gt;&lt;ul style="color: rgb(0, 0, 153);"&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:100%;"  &gt;Moq &lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;       [Test]&lt;br /&gt;       &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Test_ExpectWithCustomCallback()&lt;br /&gt;       {&lt;br /&gt;           var callbacks = 0;&lt;br /&gt;           _mockChef.Setup(chef =&amp;gt; chef.Bake(CakeFlavors.Pineapple, &lt;span class="kwrd"&gt;false&lt;/span&gt;))&lt;br /&gt;               .Callback( &lt;span class="kwrd"&gt;delegate&lt;/span&gt;(CakeFlavors flavor, &lt;span class="kwrd"&gt;bool&lt;/span&gt; withIcing)&lt;br /&gt;                           {   &lt;span class="rem"&gt;// any custom code&lt;/span&gt;&lt;br /&gt;                               Console.WriteLine(&lt;span class="str"&gt;"Callback Params: {0}, {1}"&lt;/span&gt;, flavor, withIcing);&lt;br /&gt;                               callbacks += 1;&lt;br /&gt;                               &lt;span class="kwrd"&gt;if&lt;/span&gt; (callbacks == 1)&lt;br /&gt;                                   &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; OutOfIngredientsException();&lt;br /&gt;&lt;br /&gt;                               &lt;span class="kwrd"&gt;return&lt;/span&gt;;&lt;br /&gt;                           }&lt;br /&gt;               );&lt;br /&gt;          &lt;br /&gt;           _mockInventory.Setup(inv =&amp;gt; inv.ReplenishStocks()).Returns(&lt;span class="kwrd"&gt;true&lt;/span&gt;);&lt;br /&gt;           _bakery.PlaceOrder( OrderForOnePineappleCakeNoIcing );&lt;br /&gt;          &lt;br /&gt;           _mockChef.VerifyAll();&lt;br /&gt;           _mockInventory.VerifyAll();&lt;br /&gt;       }&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Tag on an overload of Callback( customDelegate ) at the end of the Setup to specify custom code to be executed.&lt;br /&gt;Moq gives you strongly typed callbacks with upto 4 parameters (Action&lt;t1,t2,t3,t4&gt; is the biggest Action type in .Net; a restriction that will be lifted with .net 4.0). Argument access is a snap.&lt;/t1,t2,t3,t4&gt;&lt;/span&gt;&lt;br /&gt;&lt;ul style="color: rgb(0, 102, 0);"&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:100%;"  &gt;jMock &lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="rem"&gt;// http://www.jmock.org/custom-actions.html&lt;/span&gt;&lt;br /&gt; @Test&lt;br /&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; test_expectAndInvokeCustomCallback()&lt;br /&gt; {&lt;br /&gt;   context.checking( &lt;span class="kwrd"&gt;new&lt;/span&gt; Expectations() { {&lt;br /&gt;     oneOf(_mockChef).bake(CakeFlavors.Pineapple, &lt;span class="kwrd"&gt;false&lt;/span&gt; );&lt;br /&gt;       will( MyCustomCallback.tracingCallback() );&lt;br /&gt;   } } );&lt;br /&gt;  &lt;br /&gt;   _bakery.placeOrder( &lt;span class="kwrd"&gt;new&lt;/span&gt; Order(CakeFlavors.Pineapple, &lt;span class="kwrd"&gt;false&lt;/span&gt;, 1) );&lt;br /&gt; }&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; MyCustomCallback implements Action&lt;br /&gt;{&lt;br /&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; describeTo(org.hamcrest.Description description)&lt;br /&gt;   {&lt;br /&gt;       description.appendText(&lt;span class="str"&gt;"a custom callback to do what I deem fit! "&lt;/span&gt;);&lt;br /&gt;   }&lt;br /&gt;  &lt;br /&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; Object invoke(Invocation invocation) throws Throwable&lt;br /&gt;   { &lt;span class="rem"&gt;// any custom code&lt;/span&gt;&lt;br /&gt;     System.&lt;span class="kwrd"&gt;out&lt;/span&gt;.println(&lt;span class="str"&gt;"Callback invoked with "&lt;/span&gt;&lt;br /&gt;       + ((CakeFlavors)invocation.getParameter(0))&lt;br /&gt;       + &lt;span class="str"&gt;" and "&lt;/span&gt;&lt;br /&gt;       + (((Boolean) invocation.getParameter(1)).booleanValue() ? &lt;span class="str"&gt;""&lt;/span&gt; : &lt;span class="str"&gt;"no"&lt;/span&gt;)&lt;br /&gt;       + &lt;span class="str"&gt;" icing!"&lt;/span&gt;);&lt;br /&gt;       &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;br /&gt;   }&lt;br /&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; Action tracingCallback()&lt;br /&gt;   {&lt;br /&gt;     &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; MyCustomCallback();&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;It may be due to my rusty Java but it turned out to be a whole lot of classes to achieve this with jMock&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:130%;"  &gt;&lt;a id="scen8"&gt;#8:&lt;/a&gt;Raise an event from a mock collaborator&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;This one is very handy when testing GUIs using a ModelViewPresenter (or related pattern)&lt;br /&gt;&lt;br /&gt;Our inventory raises an event when we're running low on a particular ingredient. The bakery can use this notification to tell the Chef to go easy on that ingredient, while we stock our supplies.&lt;/span&gt;&lt;br /&gt;&lt;ul style="color: rgb(204, 0, 0);"&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:100%;"  &gt;Rhino Mocks&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;       [Test]&lt;br /&gt;       &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Test_RaiseEventFromMock()&lt;br /&gt;       {&lt;br /&gt;           _mockChef.Expect(chef =&amp;gt; chef.GoEasyOn(&lt;span class="str"&gt;"Sugar"&lt;/span&gt;));&lt;br /&gt;&lt;br /&gt;           _mockInventory.Raise(inv =&amp;gt; inv.RunningLowOnIngredient += &lt;span class="kwrd"&gt;null&lt;/span&gt;,&lt;br /&gt;               &lt;span class="kwrd"&gt;this&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt; StockEventArgs(&lt;span class="str"&gt;"Sugar"&lt;/span&gt;));&lt;br /&gt;&lt;br /&gt;           _mockChef.VerifyAllExpectations();&lt;br /&gt;       }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;To raise an event, invoke the Raise method on the mock with a null subscription to the event &amp;amp; the arguments to be passed onto the event handler method.&lt;/span&gt;&lt;br /&gt;&lt;ul style="color: rgb(0, 0, 153);"&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:100%;"  &gt;Moq &lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;       [Test]&lt;br /&gt;       &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Test_RaiseEventFromMock()&lt;br /&gt;       {&lt;br /&gt;           _mockChef.Setup(chef =&amp;gt; chef.GoEasyOn(&lt;span class="str"&gt;"Sugar"&lt;/span&gt;));&lt;br /&gt;&lt;br /&gt;           _mockInventory.Raise(inventory =&amp;gt; inventory.RunningLowOnIngredient += &lt;span class="kwrd"&gt;null&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt; StockEventArgs(&lt;span class="str"&gt;"Sugar"&lt;/span&gt;));&lt;br /&gt;           _mockChef.VerifyAll();&lt;br /&gt;       }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Identical to Rhino except for the fact that you don't have to specify the 'sender' parameter.&lt;/span&gt;&lt;br /&gt;&lt;ul style="color: rgb(0, 102, 0);"&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:100%;"  &gt;jMock &lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Java doesn't support events as first-class citizens. You need to manually implement the publisher-subscriber pattern.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:130%;"  &gt;&lt;a id="scen9"&gt;#9:&lt;/a&gt;Argument Constraints&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Sometimes, we do not want to / cannot specify the exact arguments with which a method on a collaborator will be called as part of the expectation. In such cases, we use constraints on the arguments, which must be met for the expectation to be met.&lt;br /&gt;e.g. from the previous example, lets say we don't know the value of the Low-stock-ingredient at compile-time. We have a variable into which we can fetch the ingredient and which we can use to compare against the actual value.&lt;br /&gt;In short we want to specify a Predicate (a function which returns true/false) for an argument as a constraint.&lt;/span&gt;&lt;br /&gt;&lt;ul style="color: rgb(204, 0, 0);"&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:100%;"  &gt;Rhino Mocks&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;       [Test]&lt;br /&gt;       &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Test_ConstrainingArguments()&lt;br /&gt;       {&lt;br /&gt;           var itemAboutToGoOutOfStock = &lt;span class="str"&gt;"Eggs"&lt;/span&gt;;&lt;br /&gt;           _mockChef.Expect(chef =&amp;gt; chef.GoEasyOn(&lt;br /&gt;               Arg&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt;.Matches (ingredient =&amp;gt; ComplexCheck(itemAboutToGoOutOfStock, ingredient))));&lt;br /&gt;&lt;br /&gt;           _mockInventory.Raise(inventory =&amp;gt; inventory.RunningLowOnIngredient += &lt;span class="kwrd"&gt;null&lt;/span&gt;,&lt;br /&gt;               &lt;span class="kwrd"&gt;this&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt; StockEventArgs(itemAboutToGoOutOfStock));&lt;br /&gt;           _mockChef.VerifyAllExpectations();&lt;br /&gt;       }&lt;br /&gt;       &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; ComplexCheck(&lt;span class="kwrd"&gt;string&lt;/span&gt; expected, &lt;span class="kwrd"&gt;string&lt;/span&gt; actual)&lt;br /&gt;       {&lt;br /&gt;           &lt;span class="kwrd"&gt;return&lt;/span&gt; expected.Equals(actual); &lt;span class="rem"&gt;// any complex test&lt;/span&gt;&lt;br /&gt;       }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;So here we use Arg&lt;t&gt;.Matches(predicate) to do a complex constraint on the string argument for Chef#GoEasyOn(). There are a bunch of other helpful constraints - explore the Arg&lt;t&gt; type docs (or the intellisense popup) for more.&lt;/t&gt;&lt;/t&gt;&lt;/span&gt;&lt;br /&gt;&lt;ul style="color: rgb(0, 0, 153);"&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:100%;"  &gt;Moq &lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;       [Test]&lt;br /&gt;       &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Test_ConstrainingArguments()&lt;br /&gt;       {&lt;br /&gt;           var itemAboutToGoOutOfStock = &lt;span class="str"&gt;"Eggs"&lt;/span&gt;;&lt;br /&gt;           _mockChef.Setup(chef =&amp;gt; chef.GoEasyOn(&lt;br /&gt;               It.Is&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt;(ingredient =&amp;gt; ComplexCheck(itemAboutToGoOutOfStock, ingredient))));&lt;br /&gt;&lt;br /&gt;           _mockInventory.Raise(inventory =&amp;gt; inventory.RunningLowOnIngredient += &lt;span class="kwrd"&gt;null&lt;/span&gt;,&lt;br /&gt;               &lt;span class="kwrd"&gt;new&lt;/span&gt; StockEventArgs(itemAboutToGoOutOfStock));&lt;br /&gt;           _mockChef.VerifyAll();&lt;br /&gt;       }&lt;br /&gt;       &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; ComplexCheck(&lt;span class="kwrd"&gt;string&lt;/span&gt; expected, &lt;span class="kwrd"&gt;string&lt;/span&gt; actual)&lt;br /&gt;       {&lt;br /&gt;           &lt;span class="kwrd"&gt;return&lt;/span&gt; expected.Equals(actual); &lt;span class="rem"&gt;// any complex test&lt;/span&gt;&lt;br /&gt;       }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Moq has It.Is&lt;t&gt;(predicate) for this purpose. Explore the type documentation (or the intellisense popup) for more helper constraints.&lt;/t&gt;&lt;/span&gt;&lt;br /&gt;&lt;ul style="color: rgb(0, 102, 0);"&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:100%;"  &gt;jMock &lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;The example is different. Here we are constraining the arguments to the Bake call with a predicate.&lt;/span&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="rem"&gt;//http://www.jmock.org/custom-matchers.html&lt;/span&gt;&lt;br /&gt; @Test&lt;br /&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; test_expectAndCheckArgs()&lt;br /&gt; {&lt;br /&gt;   context.checking( &lt;span class="kwrd"&gt;new&lt;/span&gt; Expectations() { {&lt;br /&gt;     oneOf(_mockInventory).isEmpty();&lt;br /&gt;       will(returnValue(&lt;span class="kwrd"&gt;false&lt;/span&gt;));&lt;br /&gt;     oneOf(_mockChef).bake(&lt;br /&gt;       with( FlavorMatcher.aPineappleFlavoredCake() ),&lt;br /&gt;       with( any(boolean.&lt;span class="kwrd"&gt;class&lt;/span&gt;)));&lt;br /&gt;   }} );&lt;br /&gt;   _bakery.pleaseDonate( OrderForOnePineappleCakeNoIcing() );&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; FlavorMatcher extends TypeSafeMatcher&amp;lt;CakeFlavors&amp;gt;&lt;br /&gt;{&lt;br /&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; boolean matchesSafely(CakeFlavors flavor)&lt;br /&gt; {  &lt;span class="rem"&gt;// any complex test&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;     &lt;span class="kwrd"&gt;return&lt;/span&gt; flavor == CakeFlavors.Pineapple;&lt;br /&gt;&lt;br /&gt; }&lt;br /&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; describeTo(org.hamcrest.Description description) {&lt;br /&gt;       description.appendText(&lt;span class="str"&gt;"a cake with pineapple flavor "&lt;/span&gt;);&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; @Factory&lt;br /&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; Matcher&amp;lt;CakeFlavors&amp;gt; aPineappleFlavoredCake()&lt;br /&gt;{&lt;br /&gt;   &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; FlavorMatcher();&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;once again more classes than I'd liked (Disclaimer: rusty java programmer could be the problem).&lt;br /&gt;&lt;br /&gt;Use with(matcherInstance) in place of arguments in the expectation. Derive a new Matcher derived class with your custom check.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:130%;"  &gt;&lt;a id="scen10"&gt;#9:&lt;/a&gt;Expect a sequence of calls in a specific order&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Ordered Expectations: Looking at the test in Section#4 - the test can be satisfied by the following implementation&lt;/span&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; PleaseDonate(Order order)&lt;br /&gt;       {&lt;br /&gt;           _chef.Bake(order.Flavor, order.WithIcing);&lt;br /&gt;           var isEmpty = _inventory.IsEmpty;&lt;br /&gt;       }&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;which is not what we were getting at. Seems like the test is missing something... the order of calls! Chef.Bake should be called after Inventory.IsEmpty.&lt;/span&gt;&lt;br /&gt;&lt;ul style="color: rgb(204, 0, 0);"&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:100%;"  &gt;Rhino Mocks&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;       [Test]&lt;br /&gt;       &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Test_ExpectCallsInOrder()&lt;br /&gt;       {&lt;br /&gt;           var mockCreator = &lt;span class="kwrd"&gt;new&lt;/span&gt; MockRepository();&lt;br /&gt;           _mockChef = mockCreator.DynamicMock&amp;lt;Chef&amp;gt;();&lt;br /&gt;           _mockInventory = mockCreator.DynamicMock&amp;lt;Inventory&amp;gt;();&lt;br /&gt;           mockCreator.ReplayAll();   &lt;span class="rem"&gt;// to avoid setting up an expect for an event handler subscribe in the following ctor.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;           _bakery = &lt;span class="kwrd"&gt;new&lt;/span&gt; Bakery(_mockChef, _mockInventory);&lt;br /&gt;&lt;br /&gt;           &lt;span class="kwrd"&gt;using&lt;/span&gt; (mockCreator.Ordered())&lt;br /&gt;           {&lt;br /&gt;               _mockInventory.Expect(inv =&amp;gt; inv.IsEmpty).Return(&lt;span class="kwrd"&gt;false&lt;/span&gt;);&lt;br /&gt;               _mockChef.Expect(chef =&amp;gt; chef.Bake(CakeFlavors.Pineapple, &lt;span class="kwrd"&gt;false&lt;/span&gt;));&lt;br /&gt;           }&lt;br /&gt;&lt;br /&gt;           _bakery.PleaseDonate(OrderForOnePineappleCakeNoIcing);&lt;br /&gt;&lt;br /&gt;           _mockChef.VerifyAllExpectations();&lt;br /&gt;           _mockInventory.VerifyAllExpectations();&lt;br /&gt;       }&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Woooaah! What just happened? Have a seat ; take a deep breath.&lt;br /&gt;Ordered expectations have been a feature of Rhino Mocks; however the v3.5 syntax revamp hasn't made an impact here. This took some doing .. Turns out you need to go old-skool for a bit.&lt;br /&gt;The key:&lt;br /&gt;   * Create a new MockRepository instance and invoke the DynamicMock method (instead of the static MockRepository.GenerateMock )&lt;br /&gt;   * Use the Ordered block to setup expectations in a specific order&lt;/span&gt;&lt;br /&gt;&lt;ul style="color: rgb(0, 0, 153);"&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:100%;"  &gt;Moq &lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;       [Test]&lt;br /&gt;       &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Test_ExpectCallsInOrder()&lt;br /&gt;       {&lt;br /&gt;           var sequence = String.Empty;&lt;br /&gt;           _mockInventory.Setup(inv =&amp;gt; inv.IsEmpty).Returns(&lt;span class="kwrd"&gt;false&lt;/span&gt;)&lt;br /&gt;               .Callback(&lt;span class="kwrd"&gt;delegate&lt;/span&gt; { sequence += &lt;span class="str"&gt;"1"&lt;/span&gt;; });&lt;br /&gt;           _mockChef.Setup(chef =&amp;gt; chef.Bake(CakeFlavors.Pineapple, &lt;span class="kwrd"&gt;false&lt;/span&gt;))&lt;br /&gt;               .Callback(&lt;span class="kwrd"&gt;delegate&lt;/span&gt; { sequence += &lt;span class="str"&gt;"2"&lt;/span&gt;; });&lt;br /&gt;&lt;br /&gt;           _bakery.PleaseDonate(OrderForOnePineappleCakeNoIcing);&lt;br /&gt;&lt;br /&gt;           Assert.AreEqual(&lt;span class="str"&gt;"12"&lt;/span&gt;, sequence, &lt;span class="str"&gt;"Calls not in expected order!"&lt;/span&gt;);&lt;br /&gt;           _mockChef.VerifyAll();&lt;br /&gt;           _mockInventory.VerifyAll();&lt;br /&gt;       }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Last time I checked (Jan25,2010) Moq does not support this out of the box. However you could work around this with a collecting object. Very naive.. you could come up with better solutions to fit your exact context.&lt;/span&gt;&lt;br /&gt;&lt;ul style="color: rgb(0, 102, 0);"&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:100%;"  &gt;jMock &lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt; @Test&lt;br /&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; test_expectCallsInSpecificOrder()&lt;br /&gt; {&lt;br /&gt;   final Sequence pleaseDonateSequence = context.sequence(&lt;span class="str"&gt;"pleaseDonate"&lt;/span&gt;);&lt;br /&gt;   context.checking( &lt;span class="kwrd"&gt;new&lt;/span&gt; Expectations() {{&lt;br /&gt;     oneOf(_mockInventory).isEmpty();&lt;br /&gt;       inSequence(pleaseDonateSequence);&lt;br /&gt;       will(returnValue(&lt;span class="kwrd"&gt;false&lt;/span&gt;));&lt;br /&gt;     oneOf(_mockChef).bake(CakeFlavors.Pineapple, &lt;span class="kwrd"&gt;false&lt;/span&gt;);&lt;br /&gt;       inSequence(pleaseDonateSequence);&lt;br /&gt;   }});&lt;br /&gt;  &lt;br /&gt;   _bakery.pleaseDonate( OrderForOnePineappleCakeNoIcing() ); &lt;br /&gt; }&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;jMock has the shortest syntax for ordered expectations. You create a named Sequence object and then tag the name along with each expectation (listed in the expected order).&lt;br /&gt;&lt;br /&gt;So there you have it. If it was a showdown, &lt;span style="font-weight: bold;"&gt;jMock would be ahead of Moq and Rhino Mocks would be just a sliver behind Moq.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;JMock:&lt;br /&gt;+ has a nice readable concise API for number of invocations and ordered expectations&lt;br /&gt;&lt;br /&gt;Moq:&lt;br /&gt;+ has a nice mechanism for type-safe custom callbacks and argument constraints&lt;br /&gt;&lt;br /&gt;Rhino:&lt;br /&gt;+ isn't bad. Does everything. However even with the v3.5 syntax revamp, it is a little unintuitive as compared to the others. The documentation was a bit noob-unfriendly, when I needed it. However it is the only option if can't use .net 3.5 for your tests (which should be rare).&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-713581711685659894?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/713581711685659894/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2010/01/meet-frameworks-rhino-v-moq-v-jmock.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/713581711685659894'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/713581711685659894'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2010/01/meet-frameworks-rhino-v-moq-v-jmock.html' title='Meet the frameworks : Rhino v Moq v jMock : Part II'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-624044420653418351</id><published>2010-01-26T17:46:00.016+05:30</published><updated>2010-01-26T23:22:36.520+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='Rhino'/><category scheme='http://www.blogger.com/atom/ns#' term='Mocks'/><category scheme='http://www.blogger.com/atom/ns#' term='jMock'/><category scheme='http://www.blogger.com/atom/ns#' term='Moq'/><title type='text'>Meet the frameworks : Rhino Mocks v Moq v jMock : Part 1</title><content type='html'>&lt;span style="font-family:trebuchet ms;"&gt;If you've been near any TDD-infected person, you're sure to have heard about Mock frameworks (or served as a by-standing casualty in a classicist v Mockist skirmish). Then you have to look. At first you're apprehensive, it looks like too much work (defining interfaces, creating mocks, expectations, et. all). Soon you're cornered by a Data Access object or a Network stream and you have no choice. You dip your feet into the pool of mocks.. soon enough you're splashing around like a silly kid creating mocks willy-nilly (they're free). Unknown to you, the pool has some whirlpools that suck you in when you're having too much fun and not paying any attention. In the end, it's like mock-Children of the Corn.. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;I'm a sucker for horror stories (and there's that other little matter of being biased towards state-based tests.) As with most things, there is more than one way to use a tool - mock frameworks are no exception. The folks at mockobjects.com have a new book out which explains the right way (not read it yet; maybe I'll still be converted into a mockist.)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Personally my pet-peeve with mock frameworks has been the learning curve. Usually you don't have a dedicated time-slot to learn a mock framework (and that's kind of a good constraint since the mock frameworks are flexible, powerful and consequently huge); I'd bet that most of us learn them while trying to get a test to pass. Nothing like a reluctant mock framework with cryptic error messages between you and a green bar, to get you into real-curse-practice. The only thing that comes a distant second is "Which is better? Rhino Mocks or Moq ?" from people who haven't explored either of them. If both of them scratch your itch, take a pick!&lt;br /&gt;&lt;br /&gt;So I've tried to list down the most probable scenarios and try each of them with &lt;span style="font-size:180%;"&gt;&lt;a href="http://www.ayende.com/projects/rhino-mocks.aspx"&gt;RhinoMocks&lt;/a&gt;, &lt;/span&gt;&lt;a href="http://code.google.com/p/moq/"&gt;&lt;span style="font-size:180%;"&gt;Moq &lt;/span&gt;&lt;/a&gt;and &lt;span style="font-size:180%;"&gt;&lt;a href="http://www.jmock.org/"&gt;jMock&lt;/a&gt; &lt;/span&gt;(always wanted to write some tests in jUnit).&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;ol&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;a href="http://www.blogger.com/post-edit.g?blogID=14744716&amp;amp;postID=624044420653418351#scen1"&gt;Expect a Call on mockCollaborator.method()&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;a href="http://www.blogger.com/post-edit.g?blogID=14744716&amp;amp;postID=624044420653418351#scen2"&gt;Expect a call on mockCollaborator.getProperty and return something&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;a href="http://www.blogger.com/post-edit.g?blogID=14744716&amp;amp;postID=624044420653418351#scen3"&gt;Expect n calls to mockCollaborator.Method()&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;a href="http://www.blogger.com/post-edit.g?blogID=14744716&amp;amp;postID=624044420653418351#scen4"&gt;Return values from mockCollaborator.Method()&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;a href="http://www.blogger.com/post-edit.g?blogID=14744716&amp;amp;postID=624044420653418351#scen5"&gt;Expect no call (Don't call me!)&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://madcoderspeak.blogspot.com/2010/01/meet-frameworks-rhino-v-moq-v-jmock.html#scen6"&gt;&lt;span style="font-family:trebuchet ms;"&gt;Throw an exception in response to an expected call on mockCollaborator.Method()&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://madcoderspeak.blogspot.com/2010/01/meet-frameworks-rhino-v-moq-v-jmock.html#scen7"&gt;&lt;span style="font-family:trebuchet ms;"&gt;Custom callbacks or blocks of code to execute when a mockCollaborator.Method() is called&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://madcoderspeak.blogspot.com/2010/01/meet-frameworks-rhino-v-moq-v-jmock.html#scen8"&gt;&lt;span style="font-family:trebuchet ms;"&gt;Raise an event from a mock collaborator&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://madcoderspeak.blogspot.com/2010/01/meet-frameworks-rhino-v-moq-v-jmock.html#scen9"&gt;&lt;span style="font-family:trebuchet ms;"&gt;Argument Constraints&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://madcoderspeak.blogspot.com/2010/01/meet-frameworks-rhino-v-moq-v-jmock.html#scen10"&gt;&lt;span style="font-family:trebuchet ms;"&gt;Expect a sequence of calls in a specific order&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-family:trebuchet ms;"&gt;You could use this to make your own choice (which is only yours to make). I've written this down as a self-reference for the next time I'm wondering "Why doesn't this @#&amp;amp;*(@ test fail?' or 'How is this test passing?'&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;h3  style="font-family:verdana;"&gt;&lt;span style="font-size:130%;"&gt;A template for interaction-tests&lt;/span&gt;&lt;/h3&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;br /&gt;For state-based tests, I'd usually write my assert first, step back to the action that will lead to the assert and finally arranging everything for the test to work. However this doesn't exactly work for interaction-based tests: In this realm, it's more helpful to write the action first, then the expectations and other steps for arrange and finally assert (which sometimes is just verifying that the expected mocks were called. Some frameworks like jMock do it automatically at the end of the test.)&lt;br /&gt;&lt;span style="color: rgb(102, 0, 0);"&gt;Arrange&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;ol&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;create mock objects for collaborators that you want to mock( not Stub. I hope you've read Martin Fowler's paper [link] on the difference.)&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Create your test subject (here a Bakery type) and inject the mock collaborators via ctor/setter methods.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Define the interaction via 'expects'. e.g. I expect the test subject to call methodX on collaboratorA with these parameters.&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;span style="color: rgb(102, 0, 0);"&gt;Act&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;ol&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;State the action/behavior that is the primary focus of this test&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;span style="color: rgb(102, 0, 0);"&gt;Assert&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;ol&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Assert any state-change (if applicable)&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Verify all expected calls on the collaborators were called.&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Source Code:&lt;/span&gt;&lt;br /&gt;The source code for this series is available for browse/checkout (you'll need subversion to checkout) at&lt;br /&gt;&lt;a href="https://code.google.com/p/bowling-kata-reloaded/source/browse/trunk/dotNet/tests/HowToMock/"&gt;Dot Net code&lt;/a&gt;&lt;br /&gt;&lt;a href="https://code.google.com/p/bowling-kata-reloaded/source/browse/trunk/Java/"&gt;Java code&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:130%;"  &gt;&lt;a id="scen1"&gt;#1&lt;/a&gt;: Expect a Call on mockCollaborator.method()&lt;/span&gt;&lt;br /&gt;&lt;ul style="color: rgb(204, 0, 0);"&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:100%;"  &gt;Rhino v3.5 (with NUnit 2.4.8)&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;br /&gt;Let's see how we do this in Rhino Mocks 3.5 - use the above section to work through this example.&lt;br /&gt;Rhino mocks has changed with a (IMHO noob-friendly/simpler) syntax with version 3.5 - Prior to that an explicit record-replay style was the norm. So if you're using a prior version, try moving to v3.5. (There is a forsaken commented-out source file in the above mentioned link for old-skool Rhino).&lt;br /&gt;&lt;br /&gt;To declare that you expect a method to be called, you use the &lt;span style="font-weight: bold;"&gt;Expect&lt;/span&gt; method on the respective mock object. Lambda expressions, Generics and type-inference result in compile-time checks and Intellisense guiding you all the way.&lt;br /&gt;The below expectation reads "&lt;span style="font-style: italic; color: rgb(0, 0, 153);"&gt;On the mockChef, expect Bake to be called with Vanilla and false as arguments.&lt;/span&gt;" (when someone calls PlaceOrder() on the bakery, which employs the Chef)&lt;br /&gt;&lt;span style="font-size:85%;"&gt;I'm not going to post the code to make this pass inline (for honoring the memory of brevity in blog posts). I suggest you try TDDing your way through like me / refer to the source repository.&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;[Test]&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Test_ExpectMethodCall()&lt;br /&gt;{  &lt;span class="rem"&gt;// arrange : create mocks&lt;/span&gt;&lt;br /&gt;    var mockChef = MockRepository.GenerateMock&amp;lt;Chef&amp;gt;();&lt;br /&gt;&lt;br /&gt;    &lt;span class="rem"&gt;// arrange: inject dependencies&lt;/span&gt;&lt;br /&gt;    Bakery bakery = &lt;span class="kwrd"&gt;new&lt;/span&gt; Bakery(mockChef);&lt;br /&gt;    &lt;span class="rem"&gt;// arrange: expect the Bake method on Chef to be called&lt;/span&gt;&lt;br /&gt;    mockChef.Expect(chef =&amp;gt; chef.Bake(CakeFlavors.Vanilla, &lt;span class="kwrd"&gt;false&lt;/span&gt;));&lt;br /&gt;&lt;br /&gt;    &lt;span class="rem"&gt;//act&lt;/span&gt;&lt;br /&gt;    bakery.PlaceOrder(&lt;span class="kwrd"&gt;new&lt;/span&gt; Order { Flavor = CakeFlavors.Vanilla, WithIcing = &lt;span class="kwrd"&gt;false&lt;/span&gt;, Quantity = 1 });&lt;br /&gt;&lt;br /&gt;    &lt;span class="rem"&gt;//assert&lt;/span&gt;&lt;br /&gt;    mockChef.VerifyAllExpectations();&lt;br /&gt;}&lt;/pre&gt;&lt;ul style="color: rgb(0, 0, 153);"&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:100%;"  &gt;Moq v 2.0.5 (with NUnit 2.4.8)&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:trebuchet ms;"&gt;Moq was the new kid on the block challenging the leading .Net mock frameworks with .Net3.5 lambda-expressions powered snappy syntax.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;  [Test]&lt;br /&gt;  &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Test_ExpectMethodCall()&lt;br /&gt;  {&lt;br /&gt;      &lt;span class="rem"&gt;//arrange&lt;/span&gt;&lt;br /&gt;      var mockChef = &lt;span class="kwrd"&gt;new&lt;/span&gt; Mock&amp;lt;Chef&amp;gt;();&lt;br /&gt;&lt;br /&gt;      &lt;span class="rem"&gt;//arrange: inject dep&lt;/span&gt;&lt;br /&gt;      var bakery = &lt;span class="kwrd"&gt;new&lt;/span&gt; Bakery(mockChef.Object);&lt;br /&gt;      &lt;span class="rem"&gt;// arrange: expect&lt;/span&gt;&lt;br /&gt;      _mockChef.Setup(chef =&amp;gt; chef.Bake(CakeFlavors.Vanilla, &lt;span class="kwrd"&gt;true&lt;/span&gt;));&lt;br /&gt;&lt;br /&gt;      &lt;span class="rem"&gt;//act&lt;/span&gt;&lt;br /&gt;      _bakery.PlaceOrder(&lt;span class="kwrd"&gt;new&lt;/span&gt; Order { Flavor = CakeFlavors.Vanilla, WithIcing = &lt;span class="kwrd"&gt;true&lt;/span&gt;, Quantity = 1 });&lt;br /&gt;      &lt;span class="rem"&gt;//assert&lt;/span&gt;&lt;br /&gt;      _mockChef.VerifyAll();&lt;br /&gt;  }  &lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Differences&lt;br /&gt;#1: &lt;span style="font-weight: bold;"&gt;mockChef.Object&lt;/span&gt; is the mock collaborator; this is a common stumble for people new to Moq. I think (unverified) this is due to Moq's design of not having a different Repository or Mockery type.&lt;br /&gt;#2: Moq uses &lt;span style="font-weight: bold;"&gt;Setup &lt;/span&gt;for expecations (instead of Rhino's Expect)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;ul style="color: rgb(0, 102, 0);"&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:100%;"  &gt;jMock 2.5.1 (with jUnit 4.8.1)&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;jMock is the Java mock framework distilled from the experience of the gurus at &lt;a href="http://mockobjects.com/"&gt;mockobjects.com&lt;/a&gt; ; they have a new book out and are the recognized pioneers of the "Mock objects" technique. I highly recommend their second revision of the acclaimed '&lt;a href="http://www.jmock.org/oopsla2004.pdf"&gt;Mock Roles not objects&lt;/a&gt;' paper.&lt;br /&gt;So let's see how the test looks like in jMock:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;Mockery context = &lt;span class="kwrd"&gt;new&lt;/span&gt; JUnit4Mockery();&lt;br /&gt;&lt;br /&gt;@Test&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; test_expectCall()&lt;br /&gt;{&lt;br /&gt;Chef mockChef = context.mock(Chef.&lt;span class="kwrd"&gt;class&lt;/span&gt;);&lt;br /&gt;Bakery bakery = &lt;span class="kwrd"&gt;new&lt;/span&gt; Bakery(mockChef);&lt;br /&gt;&lt;br /&gt;context.checking( &lt;span class="kwrd"&gt;new&lt;/span&gt; Expectations() { {&lt;br /&gt; oneOf(mockChef).bake(CakeFlavors.Pineapple, &lt;span class="kwrd"&gt;false&lt;/span&gt; );&lt;br /&gt;} } );&lt;br /&gt;&lt;br /&gt;bakery.placeOrder( &lt;span class="kwrd"&gt;new&lt;/span&gt; Order(CakeFlavors.Pineapple, &lt;span class="kwrd"&gt;false&lt;/span&gt;, 1) );&lt;br /&gt;&lt;span class="rem"&gt;// mockChef.Verify() - autoverified : framework :)&lt;/span&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;br /&gt;Differences&lt;br /&gt;#1: jMock has a more fluent approach to specifying expectations - look inside the Expectations creation. It reads 'Expect one invocation on mockChef of method bake with parameters Pineapple and false. Refer to the nicely written &lt;a href="http://www.jmock.org/cheat-sheet.html"&gt;jMock cheatsheet&lt;/a&gt; in case you're feeling a bit lost.&lt;br /&gt;#2: You don't need to explicitly verify expectations - automatically done at the end of a test case.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:130%;"  &gt;&lt;a id="scen2"&gt;#2&lt;/a&gt; Expect a call on mockCollaborator.getProperty and return something&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;I've factored out common code into a SetUp method to shorten the code snippets. In general, .Net properties = one get_property method + one set_property method + one backing field. Syntactic sugar!&lt;br /&gt;&lt;br /&gt;So when someone queries Bakery.IsOpen, check to see if the Chef is available.&lt;/span&gt;&lt;br /&gt;&lt;ul style="color: rgb(204, 0, 0);"&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:100%;"  &gt;Rhino Mocks&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;      [Test]&lt;br /&gt;      &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Test_ExpectPropertyGet()&lt;br /&gt;      {&lt;br /&gt;          _mockChef.Expect(chef =&amp;gt; chef.IsAvailable).Return(&lt;span class="kwrd"&gt;true&lt;/span&gt;);&lt;br /&gt;          Assert.IsTrue(_bakery.IsOpen);&lt;br /&gt;&lt;br /&gt;          _mockChef.Expect(chef =&amp;gt; chef.IsAvailable).Return(&lt;span class="kwrd"&gt;false&lt;/span&gt;);&lt;br /&gt;          Assert.IsFalse(_bakery.IsOpen);&lt;br /&gt;&lt;br /&gt;          _mockChef.VerifyAllExpectations();&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Note the new Return method tagging along with the Expect to signify what should be returned when the Bakery makes a call to Chef#IsAvailable&lt;/span&gt;&lt;br /&gt;&lt;ul style="color: rgb(0, 0, 153);"&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:100%;"  &gt;Moq &lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;      [Test]&lt;br /&gt;      &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Test_ExpectPropertyGet()&lt;br /&gt;      {&lt;br /&gt;          _mockChef.Setup(chef =&amp;gt; chef.IsAvailable).Returns(&lt;span class="kwrd"&gt;true&lt;/span&gt;);&lt;br /&gt;          Assert.IsTrue(_bakery.IsOpen);&lt;br /&gt;&lt;br /&gt;          _mockChef.Setup(chef =&amp;gt; chef.IsAvailable).Returns(&lt;span class="kwrd"&gt;false&lt;/span&gt;);&lt;br /&gt;          Assert.IsFalse(_bakery.IsOpen);&lt;br /&gt;&lt;br /&gt;          _mockChef.VerifyAll();&lt;br /&gt;      }&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Moq calls it Returns which IMHO reads better.&lt;/span&gt;&lt;br /&gt;&lt;ul style="color: rgb(0, 102, 0);"&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:100%;"  &gt;jMock &lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Java does not have properties as first class language features. They are manually implemented as accessor/mutator method pair and a backing field.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:130%;"  &gt;&lt;a id="scen3"&gt;#3:&lt;/a&gt; Expect n calls to mockCollaborator.Method()&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;So if I place an Order for 3 Pineapple cakes, I'd expect the Chef#Bake to be called thrice.&lt;/span&gt;&lt;br /&gt;&lt;ul style="color: rgb(204, 0, 0);"&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:100%;"  &gt;Rhino Mocks&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;      [Test]&lt;br /&gt;      &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Test_ExpectMultipleCalls()&lt;br /&gt;      {&lt;br /&gt;          _mockChef.Expect(chef =&amp;gt; chef.Bake(CakeFlavors.Pineapple, &lt;span class="kwrd"&gt;true&lt;/span&gt;)).Repeat.Times(3);&lt;br /&gt;&lt;br /&gt;          _bakery.PlaceOrder(&lt;span class="kwrd"&gt;new&lt;/span&gt; Order { Flavor = CakeFlavors.Pineapple, WithIcing = &lt;span class="kwrd"&gt;true&lt;/span&gt;, Quantity = 3 });&lt;br /&gt;        &lt;br /&gt;          _mockChef.VerifyAllExpectations();&lt;br /&gt;      }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Tag on the Repeat property to the Expect if you expect it to be called n times.&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;Caveat: the test fails if the mock isn't called &lt;span style="font-weight: bold;"&gt;at least&lt;/span&gt; 3 times. If you call it 3 or more times, the test passes&lt;/span&gt;. So if you have a need for exactly thrice, dive into the rhino mocks docs and let me know if you figure out a way to make it work.&lt;br /&gt;&lt;ul style="color: rgb(0, 0, 153);"&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:100%;"  &gt;Moq &lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;       [Test]&lt;br /&gt;       &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Test_ExpectMultipleMethodCalls()&lt;br /&gt;       {&lt;br /&gt;           _bakery.PlaceOrder(&lt;span class="kwrd"&gt;new&lt;/span&gt; Order { Flavor = CakeFlavors.Pineapple, WithIcing = &lt;span class="kwrd"&gt;false&lt;/span&gt;, Quantity = 3 });&lt;br /&gt;           _mockChef.Verify( chef =&amp;gt; chef.Bake(CakeFlavors.Pineapple, &lt;span class="kwrd"&gt;false&lt;/span&gt;), Times.Exactly(3), &lt;span class="str"&gt;"Chef should have been called thrice!"&lt;/span&gt;);&lt;br /&gt;       }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Differences:&lt;br /&gt;#1. With Moq, you specify this during verification with an overload of Verify (as opposed to while defining expectations)&lt;br /&gt;#2 This test will pass only if Bake is called Exactly thrice (unlike Rhino)&lt;/span&gt;&lt;br /&gt;&lt;ul style="color: rgb(0, 102, 0);"&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:100%;"  &gt;jMock &lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt; @Test&lt;br /&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt;  test_expectMultipleCalls()&lt;br /&gt; {&lt;br /&gt;   context.checking( &lt;span class="kwrd"&gt;new&lt;/span&gt; Expectations() {{&lt;br /&gt;     exactly(3).of(_mockChef).bake(CakeFlavors.Pineapple, &lt;span class="kwrd"&gt;false&lt;/span&gt;);&lt;br /&gt;   }} );&lt;br /&gt; &lt;br /&gt;   _bakery.placeOrder( &lt;span class="kwrd"&gt;new&lt;/span&gt; Order(CakeFlavors.Pineapple, &lt;span class="kwrd"&gt;false&lt;/span&gt;, 3) );&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;jMock wins this one for readabililty.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:130%;"  &gt;&lt;a id="'scen4'"&gt;#4:&lt;/a&gt; Return values from mockCollaborator.Method()&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Refer to #2 for Rhino and Moq. You tag on a Return/Returns method call to the expectation.&lt;br /&gt;Let's say the bakery being a charitable organization, responds to a PleaseDonate message at the end of the day from cake-loving orphans. The bakery will ask the Chef to bake one for them after checking to see if they have surplus stocks in inventory.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;ul style="color: rgb(0, 102, 0);"&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:100%;"  &gt;jMock &lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt; @Test&lt;br /&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; test_expectCallAndReturnValue()&lt;br /&gt; {&lt;br /&gt;   context.checking( &lt;span class="kwrd"&gt;new&lt;/span&gt; Expectations() {{&lt;br /&gt;     oneOf(_mockInventory).isEmpty();&lt;br /&gt;       will(returnValue(&lt;span class="kwrd"&gt;false&lt;/span&gt;));&lt;br /&gt;     oneOf(_mockChef).bake(CakeFlavors.Pineapple, &lt;span class="kwrd"&gt;false&lt;/span&gt;);&lt;br /&gt;   }} );     &lt;br /&gt;  &lt;br /&gt;   _bakery.pleaseDonate( OrderForOnePineappleCakeNoIcing() );&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;jMock has a &lt;span style="font-weight: bold;"&gt;will&lt;/span&gt; method to signify what will happen when the method is invoked. Use the indentation (convention) so that it reads better.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:130%;"  &gt;&lt;a id="scen5"&gt;#5:&lt;/a&gt;Expect no call (Don't call me!)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;When the orphans send a PleaseDonate() and there are no surplus stocks in inventory, you wouldn't want to bother the overworked chef at the end of a weary day.&lt;/span&gt;&lt;br /&gt;&lt;ul style="color: rgb(204, 0, 0);"&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:100%;"  &gt;Rhino Mocks&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;       [Test]&lt;br /&gt;       &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Test_ExpectNoCall()&lt;br /&gt;       {&lt;br /&gt;           _mockInventory.Expect(inv =&amp;gt; inv.IsEmpty).Return(&lt;span class="kwrd"&gt;true&lt;/span&gt;);&lt;br /&gt;           _mockChef.Expect(chef =&amp;gt; chef.Bake(Arg&amp;lt;CakeFlavors&amp;gt;.Is.Anything, Arg&amp;lt;&lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt;.Is.Anything))&lt;br /&gt;               .Repeat.Never();&lt;br /&gt;&lt;br /&gt;           _bakery.PleaseDonate(OrderForOnePineappleCakeNoIcing);&lt;br /&gt;&lt;br /&gt;           _mockInventory.VerifyAllExpectations();&lt;br /&gt;           _mockChef.VerifyAllExpectations();&lt;br /&gt;       }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Note: This snippet gives you a sneak peek of Argument Constraints. In short the second line states '&lt;span style="font-style: italic;"&gt;mockChef#Bake should not be called (irrespective of arguments)&lt;/span&gt;' Bring the .Repeat.Never() clause  into plain view by placing it on a new line with one level of indentation.&lt;/span&gt;&lt;br /&gt;&lt;ul style="color: rgb(0, 0, 153);"&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:100%;"  &gt;Moq &lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;       [Test]&lt;br /&gt;       &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Test_ExpectNoCall()&lt;br /&gt;       {&lt;br /&gt;           _mockInventory.Setup(inventory =&amp;gt; inventory.IsEmpty).Returns(&lt;span class="kwrd"&gt;true&lt;/span&gt;);&lt;br /&gt;           _bakery.PleaseDonate(OrderForOnePineappleCakeNoIcing);&lt;br /&gt;&lt;br /&gt;           _mockChef.Verify(chef =&amp;gt; chef.Bake(It.IsAny&amp;lt;CakeFlavors&amp;gt;(), It.IsAny&amp;lt;&lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt;()), Times.Never());&lt;br /&gt;           _mockInventory.VerifyAll();&lt;br /&gt;       }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Differences:&lt;br /&gt;#1 Moq takes a different path of leaving the invocation-count check till the very end. Use the Verify Overload with Times.Never() as in Section#3&lt;br /&gt;#2 Argument constaints in Moq read slightly better than Rhino.&lt;/span&gt;&lt;br /&gt;&lt;ul style="color: rgb(0, 102, 0);"&gt;&lt;li&gt;&lt;span style="font-weight: bold;font-family:courier new;font-size:100%;"  &gt;jMock &lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt; @Test&lt;br /&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; test_expectNoCall()&lt;br /&gt; {&lt;br /&gt;   context.checking( &lt;span class="kwrd"&gt;new&lt;/span&gt; Expectations() {{&lt;br /&gt;     oneOf(_mockInventory).isEmpty();&lt;br /&gt;       will(returnValue(&lt;span class="kwrd"&gt;true&lt;/span&gt;));&lt;br /&gt;     never(_mockChef).bake( CakeFlavors.Pineapple, &lt;span class="kwrd"&gt;false&lt;/span&gt; );&lt;br /&gt;&lt;br /&gt;   }});&lt;br /&gt;  &lt;br /&gt;   _bakery.pleaseDonate( OrderForOnePineappleCakeNoIcing() ); &lt;br /&gt; }&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;jMock doesn't hide intent with never() leading the expectation. jMock's API shows the thought that's been put into it.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;5 down. 5 for the next part.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-624044420653418351?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/624044420653418351/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2010/01/meet-frameworks-rhino-mocks-v-moq-v.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/624044420653418351'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/624044420653418351'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2010/01/meet-frameworks-rhino-mocks-v-moq-v.html' title='Meet the frameworks : Rhino Mocks v Moq v jMock : Part 1'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-6548054973073184923</id><published>2009-10-23T19:31:00.000+05:30</published><updated>2009-11-05T11:34:17.196+05:30</updated><title type='text'>My TDD Workshop</title><content type='html'>&lt;span style="font-family:trebuchet ms;"&gt;I was recently asked to conduct a workshop (read everyone-off-their-armchairs-and-type-with-me) on Test Driven Development. Now since this is something that I love (could not be any more apt for my 100th blog-post), I kind of "invested all of my self esteem in this presentation" as Dilbert would have said.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;It ain't a workshop till you have slides :)  &lt;/span&gt;&lt;a style="font-family: trebuchet ms;" href="http://docs.google.com/present/view?id=dcx49m86_22f2n8txcm"&gt;Workshop Slide-set&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;The source code is available for download at &lt;/span&gt;&lt;a href="http://code.google.com/p/bowling-kata-reloaded/source/checkout"&gt;&lt;span style="font-family:trebuchet ms;"&gt;Google code as a project&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;I don't have the code examples complete - I didn't like the way the GUI example turned out ; gonna give it another whirl soon.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://creativecommons.org/licenses/by-nc-sa/3.0/us/" rel="license"&gt;&lt;img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-nc-sa/3.0/us/88x31.png"/&gt;&lt;/a&gt;&lt;br/&gt;&lt;span xmlns:dc="http://purl.org/dc/elements/1.1/" property="dc:title" href="http://purl.org/dc/dcmitype/Text" rel="dc:type"&gt;Test driven development Workshop 2009&lt;/span&gt; by &lt;a property="cc:attributionName" href="my-tdd-workshop.html" rel="cc:attributionURL" xmlns:cc="http://creativecommons.org/ns#"&gt;Gishu Pillai&lt;/a&gt; is licensed under a &lt;a href="http://creativecommons.org/licenses/by-nc-sa/3.0/us/" rel="license"&gt;Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License&lt;/a&gt;.&lt;br/&gt;Based on a work at &lt;a xmlns:dc="http://purl.org/dc/elements/1.1/" href="http://docs.google.com/present/edit?id=0AaQfN_JAz01mZGN4NDltODZfMjJmMm44dHhjbQ&amp;amp;hl=en" rel="dc:source"&gt;docs.google.com&lt;/a&gt;.&lt;br/&gt;Permissions beyond the scope of this license may be available at&lt;br /&gt; &lt;a href="my-tdd-workshop.html" rel="cc:morePermissions" xmlns:cc="http://creativecommons.org/ns#"&gt;my-tdd-workshop.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;My guiding principles were&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;to give the attendees a true taste of TDD (vs automated-tests after vs test-first programming)&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;to set up beacons to avoid the usual pits, which sink time, effort, people, projects&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;to condense what I felt were in the "must-know" category&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ol&gt;&lt;li style="font-family: trebuchet ms;"&gt;Test "driven" design - emergent design&lt;br /&gt;&lt;/li&gt;&lt;li style="font-family: trebuchet ms;"&gt;SOLID Principles&lt;/li&gt;&lt;li style="font-family: trebuchet ms;"&gt;Mocks and Dependency Injection&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;span style="font-family:trebuchet ms;"&gt;Model View Presenter / Humble dialog way of building GUIs&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;to learn myself from the interaction (I've learned from a lot of people online. It 's only fair that I give back)&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:trebuchet ms;"&gt;So I got onto google docs, fired up a presentation, wrote up a rough list of things that I considered important and off I went towards an initial draft. I asked around for a good non-toy problem for the code-alongs... to my surprise I didn't net that many.. so I settled for the Bowling Example of TDD yore (Ron Jeffries, Uncle Bob, et. all)&lt;br /&gt;&lt;span style="font-style: italic;"&gt;"Score a complete bowling game as per the standard scoring rules.&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;I also needed an extension to the problem that involved a bit of Mocks and GUIs (for some real world flavor) - so I extended the problem (of course with my "customer hat" on)&lt;br /&gt;&lt;span style="font-style: italic;"&gt;"Create a View/Display for the Bowling Game that shows pins rolled and score updates in real time."&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;I then tried to solve the problem myself. The second problem turned out to be more time-consuming than I imagined. (A definite possibility is that I had lost my touch with TDD and was rusty due to lack of practice - a shoutout to Naresh Jain, for helping me realize that)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Finally I published the draft online to the &lt;span style="font-weight: bold;"&gt;testdrivendevelopment yahoo group&lt;/span&gt; for scrutiny ; As always I got a lot of help and nice suggestions. (&lt;span style="font-weight: bold;"&gt;A big thank you! to all of you&lt;/span&gt;) I incorporated most of them - including expanding my 1-day plan to a 2-day (and finally a 3-day plan - Charlie Poole can go 'told you so')&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;I then conducted the first instance of the workshop with 13 attendees. &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;The first day went as per plan.  TDD Origins, SOLID Principles, Bowling Game Part I.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;However the second day, the rails came off. They loved the Rhino Mocks jumpstart - however coding along ate up a lot of hours. I skimmed the Moq equivalent exercise and somehow rushed through to the end. The grand-finale of building a GUI (which was supposed to illustrate how you can design incrementally and it's okay if you dont have a 30 page design-document blessed by the powers that be, if you pay attention to design all the time) had to be left as an "exercise for the attendee". I'll need to extend the workshop to a full 3 days next time.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Had the opportunity to do a lot of little experiments - like using &lt;/span&gt;&lt;span style="font-family:trebuchet ms;"&gt;a Chess Timer to time how much time I spent writing tests to code. &lt;/span&gt;&lt;span style="font-family:trebuchet ms;"&gt;Good fun overall! I&lt;/span&gt;&lt;span style="font-family:trebuchet ms;"&gt;t also showed me that I need to tune my content a bit more - the anonymous feedback was encouraging. Scored a 100% on "Would you recommend this (session) to someone else" ? Just the impetus I needed to sink another bunch of hours tinkering with the content.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-6548054973073184923?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/6548054973073184923/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2009/10/my-tdd-workshop.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/6548054973073184923'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/6548054973073184923'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2009/10/my-tdd-workshop.html' title='My TDD Workshop'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-437773518777852444</id><published>2009-09-14T17:09:00.000+05:30</published><updated>2009-09-14T17:59:01.746+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='BDD'/><category scheme='http://www.blogger.com/atom/ns#' term='cucumber'/><category scheme='http://www.blogger.com/atom/ns#' term='IronRuby'/><category scheme='http://www.blogger.com/atom/ns#' term='Automated Tests'/><title type='text'>Testing .Net code with Cucumber and IronRuby</title><content type='html'>&lt;span style="font-family:trebuchet ms;"&gt;As promised, this is the culmination of this trilogy. The previous two posts were a jump-start on Cucumber to test Ruby code. Next I moved towards using Cucumber's plain text stories to test .Net code.&lt;/span&gt;&lt;a style="font-family: trebuchet ms;" href="http://wiki.github.com/aslakhellesoy/cucumber/ironruby-and-net"&gt;Aslak Hellesoy has a wiki-post&lt;/a&gt;&lt;span style="font-family:trebuchet ms;"&gt; on how to do this ; however I found that you get eaten and spat out by a lot of IronRuby dragons along the way. So hold on.. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 0, 153);font-family:verdana;" &gt;1. Install the new DLR&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;First up install &lt;a href="http://msdn.microsoft.com/en-us/vstudio/dd582936.aspx"&gt;.Net Framework 4.0&lt;/a&gt; (I have Beta1) - this has the new Dynamic Language Runtime (DLR) that makes things like IronRuby and IronPython possible.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 0, 153);font-family:verdana;" &gt;2. Get the latest IronRuby release&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Next we need to &lt;a href="http://www.ironruby.net/Download"&gt;get IronRuby&lt;/a&gt; as a zip. Extract it to say &lt;span style="font-weight: bold;"&gt;d:\ironruby-0.9.0&lt;/span&gt; Add the path to the bin folder to your PATH environment variable to avoiding lengthy paths. Drop to a command shell, type 'ir' to invoke the interactive IronRuby console. Type something simple to test if it works. It should. &lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt;puts "Hello IronRuby"&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 0, 153);font-family:verdana;" &gt;3. Dragons ahead. Use diversion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;But I hit a snag with this version of IronRuby, &lt;a href="http://ironruby.codeplex.com/WorkItem/View.aspx?WorkItemId=1095"&gt;which had A BUG&lt;/a&gt;.&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;So I had to &lt;a href="http://wiki.github.com/ironruby/ironruby/getting-the-sources"&gt;get the latest&lt;/a&gt; (8 Sep 2009 master to be precise) version of the source from the github repository to overcome that.  You can download it as a zip or use git as you prefer. I got the zip&lt;br /&gt;ironruby-ironruby-90cdda82fd60f4b7e6d7d940501c586d55954466.zip (Could have used a shorter name)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Extract it to say d:\ir-src&lt;br /&gt;I hit a few path-too-long errors during extraction. Just keep skipping them. I think it's because of the rather large alphanumeric string which is the name of the top-level folder.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Once extracted, navigate to D:\ir-src\ironruby-ironruby-90cdda82fd60f4b7e6d7d940501c586d55954466\Merlin\Main\Languages\Ruby &lt;br /&gt;and open Ruby.sln in VS2008 (I have Dev Edition of VSTS.. Although it should build in VS Express Editions as per the docs - I &lt;a href="http://stackoverflow.com/questions/1415142/how-do-i-build-ironruby-on-visual-c-2008-express-edition"&gt;couldn't get the solution to open in it&lt;/a&gt;.)&lt;br /&gt;Build Solution. At the end of it you should find the built binaries in &lt;br /&gt;D:\ir-src\ironruby-ironruby-90cdda82fd60f4b7e6d7d940501c586d55954466\Merlin\Main\bin\Debug&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Rename that directory with the huge name to something like "ir".&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Copy all built binaries and overwrite the ones from the 0.9.0 release's bin folder i.e. D:\ironruby-0.9.0\bin.&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt; Open ir.exe.config in the same folder and update the Library paths element to the proper paths to folders within your ir-src folder. 'Handle with extreme care' or you'll lose hours chasing error messages. It should read&lt;br /&gt;Path#1 - &lt;span style="font-weight:bold;"&gt;D:\ir-src\ir\Merlin\Main\Languages\&lt;/span&gt; (NOT D:\ir-src\ir\Merlin\External.LCA_RESTRICTED\Languages)&lt;br /&gt;Path#2 &amp; #3 - &lt;span style="font-weight:bold;"&gt;D:\ir-src\ir\Merlin\External.LCA_RESTRICTED&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;My xml looks like &lt;br /&gt;&lt;pre&gt;&amp;lt;set language="Ruby" option="LibraryPaths" &lt;br /&gt;value="D:\ir-src\ir\Merlin\Main\Languages\Ruby\libs\;D:\ir-src\ir\Merlin\External.LCA_RESTRICTED&lt;br /&gt;\Languages\Ruby\redist-libs\ruby\site_ruby\1.8\;D:\ir-src\ir\Merlin\External.LCA_RESTRICTED\Lang&lt;br /&gt;uages\Ruby\redist-libs\ruby\1.8\" /&amp;gt;&lt;/pre&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 0, 153);font-family:verdana;" &gt;4. Wrapper script ICucumber&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;Lastly we need a wrapper script to invoke cucumber with Ironruby. Create a file called icucumber.bat under your Ruby bin folder i.e. D:\Ruby\bin\icucumber.bat with the following text. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;REM Update with appropriate values for GEM_PATH, Ruby bin and the path to ir.exe&lt;br /&gt;@ECHO OFF&lt;br /&gt;REM This is to tell IronRuby where to find gems.&lt;br /&gt;SET GEM_PATH=d:\ruby\lib\ruby\gems\1.8&lt;br /&gt;"D:\ironruby-0.9.0\bin\ir.exe" -D -X:ExceptionDetail "d:\ruby\bin\cucumber" %* &lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 0, 153);font-family:verdana;" &gt;5. Back to our example from the previous two posts.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;The .feature file stays unchanged.&lt;br /&gt;Delete c:\cukes\dot_net_features\support\BowlingGame.rb ; since we're going to implement the same in C# this time around as &lt;br /&gt;c:\cukes\dot_net_features\support\BowlingGame.cs&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; CukesDemo&lt;br /&gt;{&lt;br /&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; BowlingGame&lt;br /&gt;   {&lt;br /&gt;      &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; roll(&lt;span class="kwrd"&gt;int&lt;/span&gt; pins_knocked_down)&lt;br /&gt;      {&lt;br /&gt;        Score += pins_knocked_down;&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; Score&lt;br /&gt;      {&lt;br /&gt;         get; set;&lt;br /&gt;      }&lt;br /&gt;      &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; Over&lt;br /&gt;      {&lt;br /&gt;         get { &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;; }&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;Also create a small batch file to compile it to a DLL (Assumes csharp compiler is on the PATH). &lt;br /&gt;c:\cukes\dot_net_features\support\Compile.bat&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;IF EXIST bin GOTO COMPILE&lt;br /&gt;MKDIR bin&lt;br /&gt;:COMPILE&lt;br /&gt;csc /t:library /out:bin/BowlingGame.dll bowling_game.cs&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;Finally back to our &lt;span style="font-weight:bold;"&gt;step definitions&lt;/span&gt; to check the glue. Four changes needed - explained in comments.&lt;br /&gt;cukes\dot_net_features\step_definitions\bowling_game_steps.rb &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="comment"&gt;# CHANGE 1 : Add bin folder to load-path&lt;/span&gt;&lt;br /&gt;&lt;span class="global"&gt;$:&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;unshift&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;File&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;dirname&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;__FILE__&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;/../support/bin&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;   &lt;br /&gt;&lt;span class="comment"&gt;# CHANGE 2 : Get BowlingGame.dll&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;BowlingGame&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;      &lt;br /&gt;&lt;br /&gt;&lt;span class="constant"&gt;Given&lt;/span&gt; &lt;span class="punct"&gt;/^&lt;/span&gt;&lt;span class="constant"&gt;I&lt;/span&gt; &lt;span class="ident"&gt;am&lt;/span&gt; &lt;span class="ident"&gt;starting&lt;/span&gt; &lt;span class="ident"&gt;a&lt;/span&gt; &lt;span class="ident"&gt;new&lt;/span&gt; &lt;span class="ident"&gt;game&lt;/span&gt;&lt;span class="global"&gt;$/&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;&lt;br /&gt;   &lt;span class="comment"&gt;# CHANGE 3 : Use Namespace::ClassName.new  &lt;/span&gt;&lt;br /&gt;   &lt;span class="attribute"&gt;@game&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;CukesDemo&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;BowlingGame&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;   &lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="constant"&gt;When&lt;/span&gt; &lt;span class="punct"&gt;/^&lt;/span&gt;&lt;span class="constant"&gt;I&lt;/span&gt; &lt;span class="ident"&gt;roll&lt;/span&gt; &lt;span class="punct"&gt;(\&lt;/span&gt;&lt;span class="ident"&gt;d&lt;/span&gt;&lt;span class="punct"&gt;+)&lt;/span&gt; &lt;span class="ident"&gt;gutter&lt;/span&gt; &lt;span class="ident"&gt;balls&lt;/span&gt;&lt;span class="global"&gt;$/&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;count&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;  &lt;span class="ident"&gt;count&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_i&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;times&lt;/span&gt;&lt;span class="punct"&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class="attribute"&gt;@game&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;roll&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="constant"&gt;Then&lt;/span&gt; &lt;span class="punct"&gt;/^&lt;/span&gt;&lt;span class="ident"&gt;the&lt;/span&gt; &lt;span class="ident"&gt;score&lt;/span&gt; &lt;span class="ident"&gt;should&lt;/span&gt; &lt;span class="ident"&gt;be&lt;/span&gt; &lt;span class="punct"&gt;(\&lt;/span&gt;&lt;span class="ident"&gt;d&lt;/span&gt;&lt;span class="punct"&gt;+)&lt;/span&gt;&lt;span class="global"&gt;$/&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;expected_score&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;  &lt;span class="attribute"&gt;@game&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;score&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;should&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="ident"&gt;expected_score&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_i&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="constant"&gt;Then&lt;/span&gt; &lt;span class="punct"&gt;/^&lt;/span&gt;&lt;span class="ident"&gt;the&lt;/span&gt; &lt;span class="ident"&gt;game&lt;/span&gt; &lt;span class="ident"&gt;should&lt;/span&gt; &lt;span class="ident"&gt;be&lt;/span&gt; &lt;span class="ident"&gt;over&lt;/span&gt;&lt;span class="global"&gt;$/&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;&lt;br /&gt;  &lt;span class="comment"&gt;# CHANGE 4 :  be_over passes even if Over returns false. Don't know what is the equiv of over? &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;in&lt;/span&gt; &lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;Net&lt;/span&gt;&lt;br /&gt;  &lt;span class="comment"&gt;#~ @game.should be_over == true &lt;/span&gt;&lt;br /&gt;  &lt;span class="attribute"&gt;@game&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;over&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;should&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="constant"&gt;true&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="constant"&gt;When&lt;/span&gt; &lt;span class="punct"&gt;/^&lt;/span&gt;&lt;span class="ident"&gt;my&lt;/span&gt; &lt;span class="ident"&gt;rolls&lt;/span&gt; &lt;span class="ident"&gt;are&lt;/span&gt; &lt;span class="punct"&gt;(.*)&lt;/span&gt;&lt;span class="global"&gt;$/&lt;/span&gt; &lt;span class="ident"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;rolls&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;  &lt;span class="ident"&gt;rolls&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;split&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt; &lt;/span&gt;&lt;span class="punct"&gt;').&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt;&lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;roll&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;    &lt;span class="attribute"&gt;@game&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;roll&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;roll&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_i&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;Now for the grand finale, run Cucumber to verify our .Net DLL via IronRuby !!!&lt;/span&gt;&lt;br /&gt;&lt;img src="http://1.bp.blogspot.com/_nxgDpneh8yk/Sq41miAqPcI/AAAAAAAAAvs/W5IXJEjU1KQ/s1600/Cukes_06.jpg" alt="[Cukes_06.jpg]" border=0&gt;&lt;br /&gt;&lt;br /&gt;HTH&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-437773518777852444?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/437773518777852444/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2009/09/testing-net-code-with-cucumber-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/437773518777852444'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/437773518777852444'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2009/09/testing-net-code-with-cucumber-and.html' title='Testing .Net code with Cucumber and IronRuby'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_nxgDpneh8yk/Sq41miAqPcI/AAAAAAAAAvs/W5IXJEjU1KQ/s72-c/Cukes_06.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-3202622393468765340</id><published>2009-09-12T16:14:00.000+05:30</published><updated>2009-09-14T18:09:48.316+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='BDD'/><category scheme='http://www.blogger.com/atom/ns#' term='cucumber'/><category scheme='http://www.blogger.com/atom/ns#' term='Automated Tests'/><title type='text'>Scenario Outlines and Tagging in Cucumber</title><content type='html'>&lt;span style="font-family:trebuchet ms;"&gt;Post#2 in this trilogy.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);font-size:130%;" &gt;&lt;span style="font-family:verdana;"&gt;Scenario Outline&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Scenario tables are similar to Fit's ColumnFixture and NUnit's RowTest. You run the same scenario with different inputs each time.&lt;br /&gt;Let's go back to our plain text feature and add the following.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style="font-weight: bold;"&gt;Scenario Outline:&lt;/span&gt; score should be as per the std rules&lt;br /&gt;  Given I am starting a new game&lt;br /&gt;  When my rolls are &amp;lt;rolls&amp;gt;&lt;br /&gt;  Then the score should be &amp;lt;score&amp;gt;&lt;br /&gt;&lt;br /&gt; &lt;span style="font-weight: bold;"&gt;Scenarios:&lt;/span&gt; lets go bowling&lt;br /&gt; | rolls   | score |&lt;br /&gt; |5 2      | 7     |&lt;br /&gt; |5 5 5    | 15    |&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;The key things to remember here are the 'Scenario Outline:' marker to indicate that it is an outline. We then have placeholders within angular brackets. The Outline is then followed by one or more tables identified by the marker 'Scenarios:'&lt;br /&gt;The next line should contain column headers which correspond with the placeholders in the outline. Cucumber would substitute the values to run each row against the Outline.&lt;br /&gt;&lt;br /&gt;SARC and it should fail. Let's go fix that up in bowling_game.rb&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;BowlingGame&lt;/span&gt;&lt;br /&gt; &lt;span class="ident"&gt;attr_reader&lt;/span&gt; &lt;span class="symbol"&gt;:score&lt;/span&gt;&lt;br /&gt; &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;&lt;br /&gt;   &lt;span class="attribute"&gt;@score&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;0&lt;/span&gt;&lt;br /&gt; &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt; &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;roll&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt; &lt;span class="ident"&gt;pins_knocked_down&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;   &lt;span class="attribute"&gt;@score&lt;/span&gt; &lt;span class="punct"&gt;+=&lt;/span&gt; &lt;span class="ident"&gt;pins_knocked_down&lt;/span&gt;&lt;br /&gt; &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt; &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;score&lt;/span&gt;&lt;br /&gt;   &lt;span class="attribute"&gt;@score&lt;/span&gt;&lt;br /&gt; &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt; &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;over?&lt;/span&gt;&lt;br /&gt;   &lt;span class="constant"&gt;true&lt;/span&gt;&lt;br /&gt; &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;SARC. Now you should see this nice listing.&lt;/span&gt;&lt;br /&gt;&lt;img src="http://1.bp.blogspot.com/_nxgDpneh8yk/Sqt_EqqpnsI/AAAAAAAAAvk/V4G9YmIbYm8/s1600/cukes_05.jpg" alt="[cukes_05.jpg]" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);font-size:130%;" &gt;&lt;span style="font-family:verdana;"&gt;Tagging&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;You can tag a scenario (or a feature) with one (or more) tags.&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;@important, @fast&lt;br /&gt;Feature: Bowling Game Score Calculation&lt;br /&gt; In order to let the player know his score&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;By default, cucumber runs all .feature files in the features subfolder. You can group features in different subfolders as well e.g. I can define a new.feature within a new_features subfolder, which can then be run with&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&gt;cucumber new_features&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Overtime, it can get crowded with lots of subfolders. But tagging is here to save the day..&lt;br /&gt;To run only features/scenarios marked 'fast'&lt;br /&gt;&lt;pre&gt;&gt;cucumber --tags @fast&lt;/pre&gt;&lt;br /&gt;To run features/scenarios that are not marked 'fast'&lt;br /&gt;&lt;pre&gt;&gt;cucumber --tags ~@fast&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So that's another way to quickly sort out your tests.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);font-size:130%;" &gt;&lt;span style="font-family:verdana;"&gt;Language Support&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The next thing you'd probably want to know (just in case you need it) is that cucumber speaks multiple languages. You can write your .feature file in any language - provided that the necessary entries are made in the resource file - languages.yml.&lt;br /&gt;&lt;br /&gt;Next post - getting cucumber to test a .Net app with some help from IronRuby. Piqued?&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Resources&lt;/span&gt; on BDD / Cucumber (although I felt the majority were too entwined with Rails (e.g. WebRat for testing Web Apps via free step definitions) but then that very well could be the major user-base for cucumber right now.)&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;ScreenCast by Aslak Hellesoy &lt;a href="http://www.infoq.com/presentations/hellesoy-bdd-rspec"&gt;Executable User Stories with RSpec and BDD&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;ScreenCast by Ben Mabey &lt;a href="http://www.bestechvideos.com/2009/03/29/mountainwest-rubyconf-2009-outside-in-development-with-cucumber&lt;br /&gt;"&gt;Outside in development with Cucumber&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Blogpost series by Dave Astels &lt;a href="http://www.engineyard.com/blog/2009/cucumber-more-advanced/"&gt;Cucumber: More advanced &lt;/a&gt;&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;RailsCast episodes by Ryan Bates &lt;a href="http://railscasts.com/episodes/155-beginning-with-cucumber"&gt;Beginning with Cucumber&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;  &lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-3202622393468765340?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/3202622393468765340/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2009/09/scenario-outlines-and-tagging-in.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/3202622393468765340'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/3202622393468765340'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2009/09/scenario-outlines-and-tagging-in.html' title='Scenario Outlines and Tagging in Cucumber'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_nxgDpneh8yk/Sqt_EqqpnsI/AAAAAAAAAvk/V4G9YmIbYm8/s72-c/cukes_05.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-5405363243759877290</id><published>2009-09-12T13:29:00.000+05:30</published><updated>2009-11-04T21:19:11.680+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='BDD'/><category scheme='http://www.blogger.com/atom/ns#' term='cucumber'/><category scheme='http://www.blogger.com/atom/ns#' term='Automated Tests'/><title type='text'>Green in 30 mins : Getting Started with Cucumber (a test framework for BDD)</title><content type='html'>&lt;span style="font-weight: bold;"&gt;Prologue:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;BDD is TDD with an outside-in (top-down) bent.&lt;br /&gt;The way to tackle any new feature request is to ask &lt;span style="font-size:130%;"&gt;Why&lt;/span&gt; 5 times? An you should arrive at one of &lt;span style="font-weight: bold;"&gt;Protect Revenue&lt;/span&gt;, &lt;span style="font-weight: bold;"&gt;Increase Revenue&lt;/span&gt; or &lt;span style="font-weight: bold;"&gt;Manage Cost&lt;/span&gt;. If not, chances are you’re building something that is not needed.&lt;br /&gt;A feature can be summarized in a few lines as (ala Mike Cohn’s user story format)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style="font-weight: bold;"&gt;As a&lt;/span&gt; &amp;lt;role&amp;gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;I want&lt;/span&gt; &amp;lt;feature&amp;gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;So that&lt;/span&gt; &amp;lt;value&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;br /&gt;&lt;a href="http://dannorth.net/2008/09/jbehave-20-is-live"&gt;Dan North began this journey&lt;/a&gt; with JBehave.&lt;br /&gt;It evolved over time into a Ruby gem - &lt;a href="http://rspec.info/"&gt;RSpec&lt;/a&gt; courtesy David Chelimsky n co. RSpec consisted of two parts - example runner and a story runner. The story runner runs features (think big cog)  written up as plain text files which can be ‘executed’ (via some developer-added connecting-glue code in a separate location). The example runner (think small cog) is a bunch of module specs that make the feature happen. (think xUnit for BDD).&lt;br /&gt;The RSpec story runner has now been simplified/improved and become &lt;a href="http://cukes.info/"&gt;Cucumber&lt;/a&gt; – a really neat little tool by Aslak Hellesoy. There are others too who have contributed to this movement like Dave Astels, et. all&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You can still use RSpec example runner in tango with Cucumber or you could stick with xUnit under the hood instead of RSpec.&lt;br /&gt;Enough prologue for today.&lt;br /&gt;&lt;br /&gt;Now I've spent 3-4 days chasing hyperlinks and watching screencasts (links at the end of Post#2 in this series), this post should give you a rolling start on cucumber.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);font-size:130%;" &gt;&lt;span style="font-family:verdana;"&gt;Step1# Installation&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;You need a few Ruby Gems to get rolling. (RSpec &amp;amp; Win32Console not mandatory)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;gem install rspec&lt;br /&gt;gem install cucumber&lt;br /&gt;gem install win32console&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;I have rspec (1.2.8) | cucumber (0.3.99) | win32console (1.2.0). Try ‘cucumber –help’ to verify this step. Win32console is for color output on Windows.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 0, 153);font-size:130%;" &gt;&lt;span style="font-family:verdana;"&gt;Step2# Lets go bowling&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;I’ll take the popular ‘Score a bowling game’ TDD Kata as an example.&lt;br /&gt;So we begin with a feature. (I’ll skip the pop-the-why-stack ; this feature falls into the ‘protect revenue’ category). Find a nice empty directory let’s say &lt;span style="font-weight: bold;"&gt;c:\cukes&lt;/span&gt;. Create a &lt;span style="font-weight: bold;"&gt;features&lt;/span&gt; subdirectory within it.&lt;br /&gt;We create a new file : &lt;span style="font-weight: bold;"&gt;features\bowling_score.feature&lt;/span&gt; and type this in. This is called the feature narrative – it’s just a descriptive block of text. However the form is slightly different the context/value clause rises to the top with the prefix &lt;span style="font-weight: bold;"&gt;In order to&lt;/span&gt; &amp;lt;business value&amp;gt;. Spotlight on business value!&lt;br /&gt;Note: &lt;a href="http://wiki.github.com/aslakhellesoy/cucumber/gherkin"&gt;Indentation matters&lt;/a&gt;! Spaces preferred.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;Feature: Bowling Game Score Calculation&lt;br /&gt;  In order to let the player know his score&lt;br /&gt;  As a CEO of TheBowlingInc&lt;br /&gt;  I want to calculate the score at the end of a bowling fame&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Next we Save And Run Cucumber from the c:\cukes directory. This step I hereby alias to &lt;span style="font-weight: bold;"&gt;SARC&lt;/span&gt;. This outputs &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;c:\cukes&gt;cucumber&lt;br /&gt;Feature: Bowling Game Score Calculation&lt;br /&gt;  In order to let the player know his score&lt;br /&gt;  As a CEO of TheBowlingInc&lt;br /&gt;  I want to calculate the score at the end of a bowling fame&lt;br /&gt;&lt;br /&gt;0 scenarios&lt;br /&gt;0 steps&lt;br /&gt;0m0.000s&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;So now that prompts us : we need &lt;span style="font-style: italic;"&gt;Scenarios&lt;/span&gt;. A Feature may contain multiple scenarios (which collectively validate the feature).&lt;br /&gt;A Scenario is executable. A Scenario takes the form&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style="font-weight: bold;"&gt;Scenario:&lt;/span&gt; &amp;lt;text description&amp;gt;&lt;br /&gt;  &lt;span style="font-weight: bold;"&gt;Given&lt;/span&gt; &amp;lt;context&amp;gt;&lt;br /&gt;  &lt;span style="font-weight: bold;"&gt;When&lt;/span&gt; &amp;lt;action&amp;gt;&lt;br /&gt;  &lt;span style="font-weight: bold;"&gt;Then&lt;/span&gt; &amp;lt;user-visible outcome&amp;gt; &lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;So we expand our feature like this.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Feature: Bowling Game Score Calculation&lt;br /&gt;  In order to let the player know his score&lt;br /&gt;  As a CEO of TheBowlingInc&lt;br /&gt;  I want to calculate the score at the end of a bowling fame&lt;br /&gt;&lt;br /&gt;  Scenario: All Gutters score 0&lt;br /&gt;     Given I am starting a new game&lt;br /&gt;     When I roll 20 gutter balls&lt;br /&gt;     Then the score should be 0&lt;br /&gt;     And the game should be over&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;In addition you can write &lt;span style="font-weight: bold;"&gt;And&lt;/span&gt; &amp;lt;step&amp;gt; to have multiple steps – the above example is equivalent to 2 &lt;span style="font-weight: bold;"&gt;Then&lt;/span&gt; clauses. You can use it under &lt;span style="font-weight: bold;"&gt;Given/When&lt;/span&gt; too. Save and run cucumber again. (or SARC from here on)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="http://3.bp.blogspot.com/_nxgDpneh8yk/SqtlzqiLEVI/AAAAAAAAAu8/4ouyuDeMi5g/s1600/cukes_01.jpg" alt="[cukes_01.jpg]" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;For some reason the snippets don’t show up. So we play a little trick. Create a subfolder under &lt;span style="font-weight: bold;"&gt;features&lt;/span&gt; called &lt;span style="font-weight: bold;"&gt;step_definitions&lt;/span&gt;. Create a new blank file called &lt;span style="font-weight: bold;"&gt;bowling_game_steps.rb&lt;/span&gt; in it. Run cucumber again. Now you should see some snippets. Copy them from the console and paste into the blank file. SARC. You should now see that the first step is shown as a TODO and the rest are skipped (and in a different step-color to boot)&lt;br /&gt;&lt;br /&gt;The first snippet looks like&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="constant"&gt;Given&lt;/span&gt; &lt;span class="punct"&gt;/^&lt;/span&gt;&lt;span class="constant"&gt;I&lt;/span&gt; &lt;span class="ident"&gt;am&lt;/span&gt; &lt;span class="ident"&gt;starting&lt;/span&gt; &lt;span class="ident"&gt;a&lt;/span&gt; &lt;span class="ident"&gt;new&lt;/span&gt; &lt;span class="ident"&gt;game&lt;/span&gt;&lt;span class="global"&gt;$/&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;pending&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;We need to define a “step” – specify the action to be taken i.e. when cucumber encounters a matching Given clause for the regex, what action should it take? You define that as the content of the block. Let’s say we want to create a new instance of a game. So replace `pending` with&lt;br /&gt;`@game = BowlingGame.new`&lt;br /&gt;SARC and now we have a familiar color – Red (of the Red-Green-Refactor fame). We’re notified that our step has failed.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="http://2.bp.blogspot.com/_nxgDpneh8yk/Sqtw_UXblsI/AAAAAAAAAvE/vAfZGUmQ224/s1600/cukes_02.jpg" alt="[cukes_02.jpg]" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;We have no class called Bowling Game yet. Create a new subfolder under &lt;span style="font-weight: bold;"&gt;features&lt;/span&gt; called &lt;span style="font-weight: bold;"&gt;support&lt;/span&gt; to house our app classes. Create a new file in there ; &lt;span style="font-weight: bold;"&gt;features\support\bowling_game.cs&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;class BowlingGame; end&lt;br /&gt;&lt;br /&gt;SARC and we’re green…. partially.. better than red. Cucumber now points us to the next step.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;img src="http://1.bp.blogspot.com/_nxgDpneh8yk/Sqt29_zo8HI/AAAAAAAAAvM/ws8CesqVMrk/s1600/cukes_03.jpg" alt="[cukes_03.jpg]" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;I’ll define all the steps like this.. while you take a breather. There. The updated version &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="constant"&gt;Given&lt;/span&gt; &lt;span class="punct"&gt;/^&lt;/span&gt;&lt;span class="constant"&gt;I&lt;/span&gt; &lt;span class="ident"&gt;am&lt;/span&gt; &lt;span class="ident"&gt;starting&lt;/span&gt; &lt;span class="ident"&gt;a&lt;/span&gt; &lt;span class="ident"&gt;new&lt;/span&gt; &lt;span class="ident"&gt;game&lt;/span&gt;&lt;span class="global"&gt;$/&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;&lt;br /&gt;  &lt;span class="attribute"&gt;@game&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;BowlingGame&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="constant"&gt;When&lt;/span&gt; &lt;span class="punct"&gt;/^&lt;/span&gt;&lt;span class="constant"&gt;I&lt;/span&gt; &lt;span class="ident"&gt;roll&lt;/span&gt; &lt;span class="punct"&gt;(\&lt;/span&gt;&lt;span class="ident"&gt;d&lt;/span&gt;&lt;span class="punct"&gt;+)&lt;/span&gt; &lt;span class="ident"&gt;gutter&lt;/span&gt; &lt;span class="ident"&gt;balls&lt;/span&gt;&lt;span class="global"&gt;$/&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;count&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;  &lt;span class="ident"&gt;count&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_i&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;times&lt;/span&gt;&lt;span class="punct"&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class="attribute"&gt;@game&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;roll&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="constant"&gt;Then&lt;/span&gt; &lt;span class="punct"&gt;/^&lt;/span&gt;&lt;span class="ident"&gt;the&lt;/span&gt; &lt;span class="ident"&gt;score&lt;/span&gt; &lt;span class="ident"&gt;should&lt;/span&gt; &lt;span class="ident"&gt;be&lt;/span&gt; &lt;span class="punct"&gt;(\&lt;/span&gt;&lt;span class="ident"&gt;d&lt;/span&gt;&lt;span class="punct"&gt;+)&lt;/span&gt;&lt;span class="global"&gt;$/&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;expected_score&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;  &lt;span class="attribute"&gt;@game&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;score&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;should&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="ident"&gt;expected_score&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_i&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="constant"&gt;Then&lt;/span&gt; &lt;span class="punct"&gt;/^&lt;/span&gt;&lt;span class="ident"&gt;the&lt;/span&gt; &lt;span class="ident"&gt;game&lt;/span&gt; &lt;span class="ident"&gt;should&lt;/span&gt; &lt;span class="ident"&gt;be&lt;/span&gt; &lt;span class="ident"&gt;over&lt;/span&gt;&lt;span class="global"&gt;$/&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;&lt;br /&gt;  &lt;span class="attribute"&gt;@game&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;should&lt;/span&gt; &lt;span class="ident"&gt;be_over&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="constant"&gt;When&lt;/span&gt; &lt;span class="punct"&gt;/^&lt;/span&gt;&lt;span class="ident"&gt;my&lt;/span&gt; &lt;span class="ident"&gt;rolls&lt;/span&gt; &lt;span class="ident"&gt;are&lt;/span&gt; &lt;span class="punct"&gt;(.*)&lt;/span&gt;&lt;span class="global"&gt;$/&lt;/span&gt; &lt;span class="ident"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;rolls&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;  &lt;span class="ident"&gt;rolls&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;split&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt; &lt;/span&gt;&lt;span class="punct"&gt;').&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt;&lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;roll&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;    &lt;span class="attribute"&gt;@game&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;roll&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;roll&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_i&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;NOTE&lt;/span&gt;:&lt;br /&gt;&lt;/span&gt;&lt;ol&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;The second step is an example of a parameterized step. If the regex in the step definition contains groups, &lt;span style="font-weight: bold;"&gt;the matched contents are passed in as parameters to the block for the step&lt;/span&gt;. Parameter passed in are strings so you need to convert it to the right type before use. Standard regexp rules apply for matching groups. So now the step can match both ‘When I roll 5 gutter balls’ and When I roll 20 gutter balls’. You also see parameters highlighted distinctly in cucumber output. Cool!&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Then steps use a new &lt;span style="font-weight: bold;"&gt;should &lt;/span&gt;method which is added to all objects. You can read more about such helper methods &lt;a href="http://rspec.rubyforge.org/rspec/1.2.8/classes/Spec/Expectations.html"&gt;here&lt;/a&gt; and &lt;a href="http://rspec.rubyforge.org/rspec/1.2.8/classes/Spec/Matchers.html"&gt;here&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;Cucumber tells after each step what needs to be done next. This rhythm is similar to the TDD approach.&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Here’s the updated bowling_game.rb with ‘the simplest thing that could possibly work’&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;BowlingGame&lt;/span&gt;&lt;br /&gt; &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;roll&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt; &lt;span class="ident"&gt;pins_knocked_down&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt; &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;score&lt;/span&gt;&lt;br /&gt;   &lt;span class="number"&gt;0&lt;/span&gt;&lt;br /&gt; &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt; &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;over?&lt;/span&gt;&lt;br /&gt;   &lt;span class="constant"&gt;true&lt;/span&gt;&lt;br /&gt; &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;SARC this time we specify the no source&lt;br /&gt;option as a CL argument&lt;/span&gt;&lt;br /&gt;&lt;pre&gt; &gt;cucumber –s &lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="http://4.bp.blogspot.com/_nxgDpneh8yk/Sqt4OEhaIbI/AAAAAAAAAvU/VNIOBXDI4Jk/s1600/cukes_04.jpg" alt="[cukes_04.jpg]" border="0" /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;And we’ve reached the promised land -  plain text file story/features that can be verified automatically at the push of a button. That's pretty cool.&lt;br /&gt;&lt;br /&gt;Just to reiterate the folder structure.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="http://3.bp.blogspot.com/_nxgDpneh8yk/Sqt5iH_Rw9I/AAAAAAAAAvc/g5nIB4s_gv4/s1600/folder_hier.jpg" alt="[folder_hier.jpg]" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;In the next post, we move up the learning curve with Scenario tables and tagging.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-5405363243759877290?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/5405363243759877290/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2009/09/green-in-30-mins-getting-started-with.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/5405363243759877290'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/5405363243759877290'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2009/09/green-in-30-mins-getting-started-with.html' title='Green in 30 mins : Getting Started with Cucumber (a test framework for BDD)'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_nxgDpneh8yk/SqtlzqiLEVI/AAAAAAAAAu8/4ouyuDeMi5g/s72-c/cukes_01.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-5035637089406078998</id><published>2009-07-28T21:11:00.001+05:30</published><updated>2009-07-28T21:15:54.779+05:30</updated><title type='text'>How to talk to a C# / ASP.Net web service via Ruby / Rails</title><content type='html'>&lt;span style="font-family: trebuchet ms;"&gt;Maybe not the right answer.. but I took the path of least resistance and succeeded. Yay Ruby!&lt;br /&gt;&lt;br /&gt;First I did a dummy Asp.net Xml Web service as shown in &lt;a href="http://msdn.microsoft.com/en-us/library/aa290754%28VS.71%29.aspx"&gt;this MSDN walkthrough&lt;/a&gt; which does F to C temp conversion. This meant that I can access my legacy/existing C# code without any interop hassles. Yes it is SOAP based (and old-school) but it will have to do for now. You can test out the web service via a dummy stub page that exercises the web service. You can also infer the needed urls from this page.&lt;br /&gt;&lt;br /&gt;Next I found &lt;a href="http://rpheath.com/posts/298-consuming-soap-services-in-ruby"&gt;&lt;span style="font-weight: bold;"&gt;this uber-blog post by Ryan Heath&lt;/span&gt;&lt;/a&gt; and it was all downhill after that.&lt;br /&gt;&lt;br /&gt;You write a wrapper Ruby class like this which gets the WSDL and sets itself up. You can then just call your Web methods on it!&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;   &lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;soap/wsdlDriver&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;TempConverterWrapper&lt;/span&gt;&lt;br /&gt;      &lt;span class="ident"&gt;attr_accessor&lt;/span&gt; &lt;span class="symbol"&gt;:endpoint&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:service_name&lt;/span&gt;&lt;br /&gt;      &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;endpoint&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;service&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class="attribute"&gt;@endpoint&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;endpoint&lt;/span&gt;&lt;br /&gt;        &lt;span class="attribute"&gt;@service&lt;/span&gt;  &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;service&lt;/span&gt;&lt;br /&gt;      &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;      &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;convert_fahrenheit_to_celsius&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;temp&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class="ident"&gt;soap&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;wsdl&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;create_rpc_driver&lt;/span&gt;&lt;br /&gt;        &lt;span class="ident"&gt;response&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;soap&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;convert_fahrenheit_to_celsius&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:temp_in_fahrenheit&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;temp&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class="ident"&gt;soap&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;reset_stream&lt;/span&gt;&lt;br /&gt;        &lt;span class="ident"&gt;response&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;convert_fahrenheit_to_celsiusResult&lt;/span&gt;&lt;br /&gt;      &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;br /&gt;    &lt;span class="ident"&gt;private&lt;/span&gt;&lt;br /&gt;        &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;wsdl&lt;/span&gt;&lt;br /&gt;          &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;http://&lt;span class="expr"&gt;#{@endpoint}&lt;/span&gt;/&lt;span class="expr"&gt;#{@service}&lt;/span&gt;.asmx?WSDL&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;          &lt;span class="constant"&gt;SOAP&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;WSDLDriverFactory&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;http://&lt;span class="expr"&gt;#{@endpoint}&lt;/span&gt;/&lt;span class="expr"&gt;#{@service}&lt;/span&gt;.asmx?WSDL&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;&lt;br /&gt;        &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;Your main / irb code to exercise this web service. &lt;span style="font-weight:bold;"&gt;More bang / LOC&lt;/span&gt;!&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Enter a fahrenheit value to convert to celsius... via a Web Service&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;temp_fahrenheit&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;gets&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_f&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="ident"&gt;wrapper&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;TempConverterWrapper&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;localhost:1464&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;TemperatureConverter&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;The corresponding celsius value is &lt;span class="expr"&gt;#{wrapper.convert_fahrenheit_to_celsius(temp_fahrenheit)}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-5035637089406078998?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/5035637089406078998/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2009/07/how-to-talk-to-c-aspnet-web-service-via.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/5035637089406078998'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/5035637089406078998'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2009/07/how-to-talk-to-c-aspnet-web-service-via.html' title='How to talk to a C# / ASP.Net web service via Ruby / Rails'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-6989464853043122425</id><published>2009-07-24T10:05:00.000+05:30</published><updated>2009-07-24T12:03:24.877+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='JQuery'/><category scheme='http://www.blogger.com/atom/ns#' term='GUI'/><category scheme='http://www.blogger.com/atom/ns#' term='Rails'/><title type='text'>How to show a Tree (TreeView) in a Rails view?</title><content type='html'>&lt;span style="font-family:trebuchet ms;"&gt;Well there seems to be no one-way for displaying a tree in Rails. But it has to be some javascript/AJAX doing its thing with CSS on HTML lists. So I took a look at YUI Tree (the first thing that google threw up) but it felt bloated and the learning curve was a bit too steep. Some time later.. I found a tree plugin for JQuery and also found that there is a RailsCast to use JQuery with Rails (so I knew its possible to interop).&lt;br /&gt;I've been wanting to look at what JQuery is - with the massive good-will it is building up. Did a couple of tutorials &lt;a href="http://docs.jquery.com/How_jQuery_Works"&gt;1&lt;/a&gt; and &lt;a href="http://docs.jquery.com/Tutorials:Getting_Started_with_jQuery"&gt;2 &lt;/a&gt;on their site to get started. &lt;a href="http://docs.jquery.com/Downloading_jQuery"&gt;Downloaded&lt;/a&gt; the jquery.js file (1 file for all the goodness !! awesome).&lt;br /&gt;Next it's time to &lt;a href="http://bassistance.de/jquery-plugins/jquery-plugin-treeview/"&gt;download the zip&lt;/a&gt; for the excellent JQuery tree plugin by &lt;a href="http://bassistance.de/"&gt;Jorn Zaefferer&lt;/a&gt; - incidentally its the same person who wrote the second tutorial. I felt better about my chances for success.&lt;br /&gt;&lt;br /&gt;I'm assuming you have a Rails app and the code for your hieararchy all done to this point. It's going to be a simple tree showing the hierarchy (no fancy AJAX callbacks or delayed loading of children... although I think its supported)&lt;br /&gt;&lt;br /&gt;Unzip the treeview plugin folder v1.4 (it has a version of jquery bundled too inside the lib subfolder). I see&lt;br /&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;span style="font-weight: bold;"&gt;jquery.treeview.XXX.js&lt;/span&gt; (the javascript files) : Moved them to my &lt;span style="font-weight: bold;"&gt;public\javascripts &lt;/span&gt;folder within my Rails project folder. Also copied the &lt;span style="font-weight: bold;"&gt;lib&lt;/span&gt; subfolder here.&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;span style="font-weight: bold;"&gt;jquery.treeview.css&lt;/span&gt; (the CSS stylesheet) : Moved them to my &lt;span style="font-weight: bold;"&gt;public\stylesheets&lt;/span&gt; folder&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;span style="font-weight: bold;"&gt;images&lt;/span&gt; subfolder : Moved the images in this folder to a new subfolder &lt;span style="font-weight: bold;"&gt;public\images\jquery.treeview.images&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:trebuchet ms;"&gt; Now the CSS file has references to the images. So do a find-replace to make sure all the images are reachable in their new locations; "url(images/" becomes "url(../images/jquery.treeview.images/"&lt;br /&gt;&lt;br /&gt;I have a show action on my controller that creates @root_node which is a typical Node object with a Children attribute - an array of child nodes. So now we need something to render it as an hierarchical HTML list - a Rails helper method for your controller&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;display_segment&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt; &lt;span class="ident"&gt;node&lt;/span&gt; &lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span class="ident"&gt;html&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;node_class&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;node&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;children&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;length&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="number"&gt;0&lt;/span&gt; &lt;span class="punct"&gt;?&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;file&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;folder&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;html&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&amp;lt;span class=&lt;span class="escape"&gt;\&amp;quot;&lt;/span&gt;&lt;span class="expr"&gt;#{node_class}&lt;/span&gt;&lt;span class="escape"&gt;\&amp;quot;&lt;/span&gt;&amp;gt;&lt;span class="expr"&gt;#{h(node.to_s)}&lt;/span&gt; &amp;lt;/span&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;html&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&amp;lt;ul id=&lt;span class="escape"&gt;\&amp;quot;&lt;/span&gt;children_of_&lt;span class="expr"&gt;#{h(node.sid)}&lt;/span&gt;&lt;span class="escape"&gt;\&amp;quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;node&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;children&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt;&lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;child_node&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;      &lt;br /&gt;      &lt;span class="ident"&gt;html&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="ident"&gt;display_segment&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt; &lt;span class="ident"&gt;child_node&lt;/span&gt; &lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;html&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&amp;lt;/ul&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Let's also take a look at the view show.html.erb&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;h3&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;  You are viewing &lt;span class="asp"&gt;&amp;lt;%&lt;/span&gt;= @data_file_path &lt;span class="asp"&gt;%&amp;gt;&lt;/span&gt;  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;h3&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;title&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;span class="asp"&gt;&amp;lt;%&lt;/span&gt;= controller.action_name &lt;span class="asp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;title&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="asp"&gt;&amp;lt;%&lt;/span&gt;= stylesheet_link_tag &lt;span class="str"&gt;'appstylesheet'&lt;/span&gt;&lt;span class="asp"&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ul&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="my_tree"&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="filetree"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="asp"&gt;&amp;lt;%&lt;/span&gt;= display_segment(@root_node) &lt;span class="asp"&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ul&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt; Things to note&lt;br /&gt;&lt;ul&gt;&lt;li&gt;First we need an enclosing &lt;span style="font-weight: bold;"&gt;ul&lt;/span&gt; block with css class set to &lt;span style="font-weight: bold;"&gt;filetree&lt;/span&gt;. This would be picked up our custom javascript snippet to JQuery-magically turn into a tree. So we need to make a note to give it a good id - here &lt;span style="font-weight: bold;"&gt;my_tree&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Next the content is rendered via our recursive helper function. Children of a node are in a nested &lt;span style="font-weight: bold;"&gt;ul&lt;/span&gt;  block. Each leaf-node is a &lt;span style="font-weight: bold;"&gt;li&lt;/span&gt; item and has css class as "&lt;span style="font-weight: bold;"&gt;file&lt;/span&gt;". parents have css class as "&lt;span style="font-weight: bold;"&gt;folder&lt;/span&gt;"&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;So now it should look something like this.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_nxgDpneh8yk/SmlQ9agI0uI/AAAAAAAAAuI/3hiHesvdCv8/s1600-h/tree_before_style.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 200px; height: 130px;" src="http://1.bp.blogspot.com/_nxgDpneh8yk/SmlQ9agI0uI/AAAAAAAAAuI/3hiHesvdCv8/s200/tree_before_style.jpg" alt="" id="BLOGGER_PHOTO_ID_5361905847377646306" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now the stage is set for JQuery to do its thing. First lets introduce these 2 lines to the head tag of our view.&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="asp"&gt;&amp;lt;%&lt;/span&gt;= javascript_include_tag &lt;span class="str"&gt;'lib/jquery'&lt;/span&gt;, &lt;span class="str"&gt;'jquery.treeview'&lt;/span&gt;, &lt;span class="str"&gt;'custom'&lt;/span&gt; &lt;span class="asp"&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="asp"&gt;&amp;lt;%&lt;/span&gt;= stylesheet_link_tag &lt;span class="str"&gt;'jquery.treeview.css'&lt;/span&gt; &lt;span class="asp"&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So we say we want to use the jquery javascript file, followed by the treeview plugin and finally our own custom javascript file that we'll write next.&lt;br /&gt;We also want to use the treeview CSS stylesheet. You can do a "View Source" in firefox to see what the translated HTML looks like - std. stuff.&lt;br /&gt;&lt;br /&gt;We're nearing the end here - Our &lt;span style="font-weight: bold;"&gt;\public\javascripts\custom.js&lt;/span&gt; file to sprinkle some JQuery dust on this thing&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;$(document).ready( function() {&lt;br /&gt;$(&lt;span class="str"&gt;"#my_tree"&lt;/span&gt;).treeview();&lt;br /&gt;} );&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here we're giving a function to be executed when the page/document is ready. This function finds our top-level list element with id = "my_tree" and calls the treeview() method on it.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_nxgDpneh8yk/SmlUR9ENpoI/AAAAAAAAAuQ/5wgjhEr4u_g/s1600-h/tree_after_style.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 212px;" src="http://4.bp.blogspot.com/_nxgDpneh8yk/SmlUR9ENpoI/AAAAAAAAAuQ/5wgjhEr4u_g/s320/tree_after_style.jpg" alt="" id="BLOGGER_PHOTO_ID_5361909498788030082" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;Victory Jig time!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-6989464853043122425?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/6989464853043122425/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2009/07/how-to-show-tree-treeview-in-rails-view.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/6989464853043122425'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/6989464853043122425'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2009/07/how-to-show-tree-treeview-in-rails-view.html' title='How to show a Tree (TreeView) in a Rails view?'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_nxgDpneh8yk/SmlQ9agI0uI/AAAAAAAAAuI/3hiHesvdCv8/s72-c/tree_before_style.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-8520949363493564910</id><published>2009-07-10T12:00:00.000+05:30</published><updated>2009-07-10T12:39:50.182+05:30</updated><title type='text'>Illustrated How to do a simple C++ DLL project in Visual Studio ?</title><content type='html'>&lt;span style="font-family:trebuchet ms;"&gt;Agreed that it isn't a big deal ... however I struggle with this everytime I dip my toes after a long managed stint.. and after a question on stackoverflow - it seems I'm not alone.&lt;br /&gt;&lt;br /&gt;So here goes.. Fire up Visual Studio&lt;br /&gt;&lt;br /&gt;Ctrl+Shift+N to go to the new project dialog or Right click on the Solution Node - Add - New Project... Press Next instead of Finish to go to the next screen.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_nxgDpneh8yk/SlbjEyB_BpI/AAAAAAAAAtE/HBgamwupWME/s1600-h/C%2B%2B_DLL_01.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 400px; height: 261px;" src="http://3.bp.blogspot.com/_nxgDpneh8yk/SlbjEyB_BpI/AAAAAAAAAtE/HBgamwupWME/s400/C%2B%2B_DLL_01.jpg" alt="" id="BLOGGER_PHOTO_ID_5356718478092863122" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_nxgDpneh8yk/SlbkdgLyLMI/AAAAAAAAAtM/LzpHc9vY3Uw/s1600-h/C%2B%2B_DLL_02.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 283px;" src="http://1.bp.blogspot.com/_nxgDpneh8yk/SlbkdgLyLMI/AAAAAAAAAtM/LzpHc9vY3Uw/s400/C%2B%2B_DLL_02.jpg" alt="" id="BLOGGER_PHOTO_ID_5356720002310483138" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;So when I do that I have the following structure. &lt;/span&gt;&lt;br /&gt;&lt;ul style="font-family: trebuchet ms;"&gt;&lt;li&gt;Stdafx.h &amp;amp; stdafx.cpp – defines and includes standard header files. Leave unmodified.&lt;/li&gt;&lt;li&gt;WinHookFacade_VS2005.cpp – defines the DLL Main function (entry point). Leave unmodified unless you have your very own dllmain.cpp with custom code.&lt;/li&gt;&lt;li&gt;Readme.txt – just a text file, you can stuff some info in.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Try to build the project. It should build fine.. do it just to be sure.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Next step &lt;span style="font-weight: bold;"&gt;include all your .h and .cpp&lt;/span&gt; into the project. Right click on the project in solution explorer - Add - Existing item..&lt;br /&gt;&lt;br /&gt;You may have build failures.. now its time to enter the maze of C++ Project settings&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;C++ Settings&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If you want additional directories to be looked for resolving header includes. Right click on Project Node - Properties&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;IMPORTANT: Check the Configuration combobox to read “All Configurations” each time you change a project setting else you risk the debug and release configurations getting out of sync.&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_nxgDpneh8yk/SlblHuexdqI/AAAAAAAAAtU/CLaI3KFvO9A/s1600-h/C%2B%2B_DLL_03.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 277px;" src="http://4.bp.blogspot.com/_nxgDpneh8yk/SlblHuexdqI/AAAAAAAAAtU/CLaI3KFvO9A/s400/C%2B%2B_DLL_03.jpg" alt="" id="BLOGGER_PHOTO_ID_5356720727702730402" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Also for some reason, precompiled headers are frowned upon at my workplace. So I turn them off too..&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_nxgDpneh8yk/SlblteQU0aI/AAAAAAAAAtc/N2QxKkEox14/s1600-h/C%2B%2B_DLL_04.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 121px;" src="http://2.bp.blogspot.com/_nxgDpneh8yk/SlblteQU0aI/AAAAAAAAAtc/N2QxKkEox14/s320/C%2B%2B_DLL_04.jpg" alt="" id="BLOGGER_PHOTO_ID_5356721376182194594" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Define any preprocessor symbols you want to.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;DETOUR example.. WINHOOKFACADE_EXPORTS is a symbol defined here - which will cause my functions to be exported from here. Referencing projects will not have this symbol defined and will import my functions. The header files begin like this&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;#ifdef WINHOOKFACADE_EXPORTS&lt;br /&gt;&lt;span class="preproc"&gt;#define&lt;/span&gt; WINHOOKFACADE_API __declspec(dllexport)&lt;br /&gt;&lt;span class="preproc"&gt;#else&lt;/span&gt;&lt;br /&gt;&lt;span class="preproc"&gt;#define&lt;/span&gt; WINHOOKFACADE_API __declspec(dllimport)&lt;br /&gt;&lt;span class="preproc"&gt;#endif&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;void&lt;/span&gt; WINHOOKFACADE_API Hook();&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Also in this case, you may want different symbols defined in both configurations. E.g. DEBUG is defined only in Debug configuration and so on.. so change the Configuration Combobox accordingly before making changes.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_nxgDpneh8yk/SlbmcjnBzKI/AAAAAAAAAtk/CUKPoEaN0SI/s1600-h/C%2B%2B_DLL_05.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 126px;" src="http://4.bp.blogspot.com/_nxgDpneh8yk/SlbmcjnBzKI/AAAAAAAAAtk/CUKPoEaN0SI/s400/C%2B%2B_DLL_05.jpg" alt="" id="BLOGGER_PHOTO_ID_5356722185073446050" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Linker Settings&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;span style="font-weight: bold;"&gt;To change the default location of the built binary file&lt;/span&gt;: E.g. I want the output to be generated in a SolutionDir\bin\Debug or Release. So you can use the helpful macros by pressing the tiny button on the right of the input field&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;$(SolutionDir)bin\$(ConfigurationName)\$(ProjectName).dll&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;I also keep the lib files that I need to link to in SolutionDir\bin\lib subfolder. So &lt;span style="font-weight: bold;"&gt;specify the additional folders to scan for .lib files&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_nxgDpneh8yk/SlbndnuQ62I/AAAAAAAAAts/7Y9ZPOrvgDU/s1600-h/C%2B%2B_DLL_06.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 199px;" src="http://3.bp.blogspot.com/_nxgDpneh8yk/SlbndnuQ62I/AAAAAAAAAts/7Y9ZPOrvgDU/s400/C%2B%2B_DLL_06.jpg" alt="" id="BLOGGER_PHOTO_ID_5356723302869035874" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;To specify the lib files you need to link to... &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_nxgDpneh8yk/SlboSGM4bfI/AAAAAAAAAt0/L3YGEZLp2Gw/s1600-h/C%2B%2B_DLL_08.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 140px;" src="http://1.bp.blogspot.com/_nxgDpneh8yk/SlboSGM4bfI/AAAAAAAAAt0/L3YGEZLp2Gw/s400/C%2B%2B_DLL_08.jpg" alt="" id="BLOGGER_PHOTO_ID_5356724204403715570" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;span style="font-weight: bold;"&gt;To specify where the lib file for the current project should be generated&lt;/span&gt;. In my case I want it to also go in under SolutionDir\bin\lib and named WinHookFacade_Debug.lib or WinHookFacade_Release.lib&lt;br /&gt;Use the GUI macro helper thingie to come up with your own incantation. In my case it is &lt;/span&gt;&lt;br /&gt;&lt;pre&gt;$(SolutionDir)bin\lib\$(ProjectName)_$(ConfigurationName).lib&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_nxgDpneh8yk/SlbowFwfXpI/AAAAAAAAAt8/9p5r64M96DE/s1600-h/C%2B%2B_DLL_07.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 174px;" src="http://4.bp.blogspot.com/_nxgDpneh8yk/SlbowFwfXpI/AAAAAAAAAt8/9p5r64M96DE/s400/C%2B%2B_DLL_07.jpg" alt="" id="BLOGGER_PHOTO_ID_5356724719680708242" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt; Pre-Post Build steps:&lt;br /&gt;If you’d like to do some tasks (like copying over something) before or after a build, check out the Build events node under Configuration Properties. I’d recommend against using this.. having this in the build script (e.g. ant or nant) makes it more visible – it tends to get hidden and out of sync in the project properties.&lt;br /&gt;&lt;br /&gt;Phew! That's it. Take a nap now to recharge those brain cells.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-8520949363493564910?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/8520949363493564910/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2009/07/illustrated-how-to-do-simple-c-dll.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/8520949363493564910'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/8520949363493564910'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2009/07/illustrated-how-to-do-simple-c-dll.html' title='Illustrated How to do a simple C++ DLL project in Visual Studio ?'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_nxgDpneh8yk/SlbjEyB_BpI/AAAAAAAAAtE/HBgamwupWME/s72-c/C%2B%2B_DLL_01.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-5111148426645897246</id><published>2009-06-17T12:29:00.001+05:30</published><updated>2009-06-17T12:45:35.113+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>How to compile ruby from source on Windows?</title><content type='html'>&lt;span style="font-family:trebuchet ms;"&gt;I wanted to play with the latest version of ruby. I got the win32 binary zip of 1.9.1 p0 - however irb used to popup an error message on startup - used it for sometime but then I decided to fix it. Checked back on &lt;a href="http://www.ruby-lang.org/en/downloads/"&gt;ruby's download page&lt;/a&gt; and found an updated version p129. Downloaded it but it was a source zip.&lt;br /&gt;&lt;br /&gt;I wasn't sure that compiling it from source would be trivial... however it reinforced the simplicity of the ruby way. Summarizing the steps I found on &lt;a href="http://www.ruby-forum.com/topic/58141"&gt;this post&lt;/a&gt; at ruby-forum.com&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;ol style="font-family: trebuchet ms;"&gt;&lt;li&gt;Get the source zip from the download page and unzip it locally to say c:\ruby-src&lt;/li&gt;&lt;li&gt;Open the Visual Studio Command prompt (I have VS2008 on WinXP SP2)&lt;/li&gt;&lt;li&gt;Make a folder for your build say c:\ruby-build. Move into it / change dir&lt;/li&gt;&lt;li style="font-family: courier new;"&gt;c:\ruby-build&gt; c:\ruby-src\ruby-1.9.1-p129\win32\configure.bat&lt;/li&gt;&lt;li style="font-family: courier new;"&gt;c:\ruby-build&gt; nmake&lt;/li&gt;&lt;li style="font-family: courier new;"&gt;c:\ruby-build&gt; nmake test&lt;/li&gt;&lt;li style="font-family: courier new;"&gt;c:\ruby-build&gt; nmake DESTDIR=c:/ruby-build install&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-family:trebuchet ms;"&gt;That's it.. you'll find the binaries within a usr folder within the ruby-build folder.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-5111148426645897246?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/5111148426645897246/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2009/06/how-to-compile-ruby-from-source-on.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/5111148426645897246'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/5111148426645897246'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2009/06/how-to-compile-ruby-from-source-on.html' title='How to compile ruby from source on Windows?'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-9127971656369373503</id><published>2009-06-16T11:28:00.000+05:30</published><updated>2009-06-16T12:03:58.009+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='windows hooks'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><title type='text'>How to create a global (system) windows hook ?</title><content type='html'>&lt;span style="font-family:trebuchet ms;"&gt;What are Windows Hooks? You probably don't want to know that :) Good starting points are&lt;/span&gt;&lt;br /&gt;&lt;a style="font-family: trebuchet ms;" href="http://msdn.microsoft.com/en-us/library/ms632589%28VS.85%29.aspx"&gt;The MSDN door to hooks&lt;/a&gt;&lt;br /&gt;&lt;a style="font-family: trebuchet ms;" href="http://msdn.microsoft.com/en-us/library/ms997537.aspx"&gt;Win32 Hooks&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;br /&gt;A global / system hook would be “I want to be called when anyone does X in any process” ; the other kind is when “I want to be called when anyone does X in ThreadID#Y”. Creating a &lt;a href="http://support.microsoft.com/kb/318804"&gt;&lt;span style="font-weight: bold;"&gt;global windows hook cannot be done in managed code&lt;/span&gt;&lt;/a&gt; except (some keyboard/mouse hooks) via P/Invoke (so save yourself some time although local hooks are possible).&lt;br /&gt;Windows would callback on the Hook function ; also called the filter function. The signature -&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;LRESULT CALLBACK FilterFunctionForHook(&lt;span class="kwrd"&gt;int&lt;/span&gt; code, WPARAM wParam, LPARAM lParam)&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;For global hooks, the filter function should be contained in an unmanaged DLL&lt;/span&gt; – I created one called WinHookFacade.dll. This unmanaged DLL would be injected into each process. Also the copy of the DLL loaded into other process cannot be explicitly unloaded – will unload when the process goes down. Also any bad code in the hook function can result in bad scary things and may require the user to go through a logoff-login or reboot cycle. Avoid if possible because global hooks will extract their pound of performance. But when has that stopped us programmers ? ;) Hence exercise caution with global hooks.&lt;br /&gt;&lt;br /&gt;To create a global hook, you therefore need to create an exe project that hooks/unhooks the filter function and a dll project that contains the filter function.&lt;br /&gt;&lt;h2&gt;The Hook&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;void&lt;/span&gt; Hook()&lt;br /&gt;{&lt;br /&gt;HINSTANCE hCurrentDll = GetModuleHandle(_T(&lt;span class="str"&gt;"WinHookFacade.dll"&lt;/span&gt;));&lt;br /&gt;g_HookHandle = SetWindowsHookEx(WH_CBT,&lt;br /&gt;FilterFunctionForHook,&lt;br /&gt;hCurrentDll,&lt;br /&gt;0);&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (g_HookHandle == NULL)&lt;br /&gt;&lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; std::exception(&lt;span class="str"&gt;"Unable to hook"&lt;/span&gt;);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The key here would be the &lt;a href="http://msdn.microsoft.com/en-us/library/ms644990%28VS.85%29.aspx"&gt;SetWindowsHookEx&lt;/a&gt; Win32 API function. The first parameter is what &lt;span style="font-weight: bold;"&gt;type of hook&lt;/span&gt; you’d like to register for – See &lt;a href="http://msdn.microsoft.com/en-us/library/ms644959%28VS.85%29.aspx"&gt;this page&lt;/a&gt; for available types. In this example, &lt;a href="http://msdn.microsoft.com/en-us/library/ms644959%28VS.85%29.aspx#wh_cbthook"&gt;WH_CBT&lt;/a&gt; means events related to windows (creation,activation,destructions etc). The second parameter is the &lt;span style="font-weight: bold;"&gt;name of the Hook/Filter function&lt;/span&gt; that shall be called back by the OS – detailed below. The third parameter is a &lt;span style="font-weight: bold;"&gt;handle to the DLL containing the hook function&lt;/span&gt; for global hooks (if null, it indicates a thread-specific hook). The fourth parameter is 0 for global hooks (for thread/local hooks, it is the &lt;span style="font-weight: bold;"&gt;Thread ID&lt;/span&gt; you want to hook into).&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;The Callback&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;LRESULT CALLBACK FilterFunctionForHook(&lt;span class="kwrd"&gt;int&lt;/span&gt; code, WPARAM wParam, LPARAM lParam)&lt;br /&gt;{&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (code &amp;gt;= 0)&lt;br /&gt;{&lt;br /&gt;   &lt;span class="rem"&gt;//your code e.g.&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;switch&lt;/span&gt;(code)&lt;br /&gt;   {&lt;br /&gt;      &lt;span class="kwrd"&gt;case&lt;/span&gt; HCBT_ACTIVATE:&lt;br /&gt;     &lt;span class="rem"&gt;// log the window title                  &lt;/span&gt;&lt;br /&gt;     ...&lt;br /&gt;}&lt;br /&gt;&lt;span class="kwrd"&gt;return&lt;/span&gt; CallNextHookEx(g_HookHandle, code, wParam, lParam);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This function would be called in the process in which the event occurs (e.g. where a window is created). Process Isolation : a process cannot run custom code into another process; hence DLL injection. Also the &lt;a href="http://msdn.microsoft.com/en-us/library/ms644974.aspx"&gt;CallNextHookEx&lt;/a&gt; Win32 API function must be called to pass control onto the next filter function in queue passing it the original arguments received to be a good citizen. The first parameter is the Hook Handle obtained when you registered the Hook function.&lt;br /&gt;&lt;br /&gt;IMPORTANT: However this value must be the same across all instances of the shared Hook DLL &amp;amp; must be available within the filter function. For this reason, you need to create the “hook handle” in a &lt;span style="font-weight: bold;"&gt;shared data segment&lt;/span&gt; Whaa.. how do I do that? Declare your HHOOK variable like this&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="preproc"&gt;#pragma&lt;/span&gt; data_seg (&lt;span class="str"&gt;".MY_HOOK_DATA"&lt;/span&gt;)&lt;br /&gt;HHOOK g_HookHandle = 0;&lt;br /&gt;&lt;span class="preproc"&gt;#pragma&lt;/span&gt; data_seg()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This function is supposed to call the next function in queue without doing anything &lt;span style="font-style: italic;"&gt;if the code argument is less than zero&lt;/span&gt;. If not, the function may execute custom code to do specific tasks. The wParam and lParam arguments are pointers to handles/structures containing additional info. The exact type of structure depends on the value of the code parameter – check msdn for the page for the specific alias of the filterfunction e.g. in my case it would be &lt;a href="http://msdn.microsoft.com/en-us/library/ms644977%28VS.85%29.aspx"&gt;CBTPROC&lt;/a&gt;; wParam is a handle to the window and lParam is a pointer to a struct&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Cleanup&lt;/h2&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;void&lt;/span&gt; Unhook()&lt;br /&gt;{&lt;br /&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (!UnhookWindowsHookEx(g_HookHandle))&lt;br /&gt;     &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; std::exception(&lt;span class="str"&gt;"Unhook failed!"&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt; g_HookHandle = NULL;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here the primary player is the &lt;a href="http://msdn.microsoft.com/en-us/library/ms644993%28VS.85%29.aspx"&gt;UnhookWindowsHookEx&lt;/a&gt; Win32 API Function. In case of an error, you’d need to use the fugly GetLastError() function to know what really went wrong.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Test Drive&lt;/h2&gt;&lt;br /&gt;Now to take this for a spin, create an exe project referencing the DLL containing the hook function. The main function will call on the exported functions as shown below..&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;int&lt;/span&gt; _tmain(&lt;span class="kwrd"&gt;int&lt;/span&gt; argc, _TCHAR* argv[])&lt;br /&gt;{&lt;br /&gt;  &lt;span class="kwrd"&gt;char&lt;/span&gt; buffer[256];&lt;br /&gt;  &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;  {&lt;br /&gt;      printf(&lt;span class="str"&gt;"Hooking..."&lt;/span&gt;);&lt;br /&gt;      Hook();&lt;br /&gt;      printf(&lt;span class="str"&gt;"Done.\n"&lt;/span&gt;);&lt;br /&gt;    &lt;br /&gt;    &lt;br /&gt;      printf(&lt;span class="str"&gt;"Press Enter to exit\n"&lt;/span&gt;);      &lt;span class="rem"&gt;// hook is running&lt;/span&gt;&lt;br /&gt;      gets(buffer);&lt;br /&gt;&lt;br /&gt;      printf(&lt;span class="str"&gt;"Unhooking..."&lt;/span&gt;);&lt;br /&gt;      Unhook();&lt;br /&gt;      printf(&lt;span class="str"&gt;"Done. Woohoo!!\n"&lt;/span&gt;);&lt;br /&gt;  …&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That’s all there is to it.&lt;br /&gt;CAUTION: Also if you get something wrong, the effects would be felt immediately – in my case, the UI would freeze as soon as my botched hook function was registered; my taskbar would be nuked and random error dialogs from running apps. But nothing a reboot can’t solve! C++ string compiler errors, WinAPI gotchas &amp;amp; hooks -- It was like walking on a tightrope in dark windy conditions. &amp;lt;runs back to the managed side&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-9127971656369373503?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/9127971656369373503/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2009/06/how-to-create-global-system-windows.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/9127971656369373503'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/9127971656369373503'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2009/06/how-to-create-global-system-windows.html' title='How to create a global (system) windows hook ?'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-1256027709755525037</id><published>2009-04-22T22:52:00.000+05:30</published><updated>2009-04-23T01:35:24.464+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>Ruby is slow... until you learn to write good code.</title><content type='html'>&lt;span style="font-family:trebuchet ms;"&gt;I wrote up a small program to find prime-numbers between x and y ; implemented the &lt;a href="http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes"&gt;Sieve of Eratosthenes.&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:trebuchet ms;"&gt;The SOE is basically where you take all numbers (say 1-100) into an array. Cross out 1. Loop from 2-Sqrt(N) i.e. 2-10. Now cross out every multiple of 2 in the array. Next cross out every multiple of 3.. and so on. Finally all the numbers that aren't crossed out are prime.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:trebuchet ms;"&gt;However I did a very simplistic implementation (test-driven) to boot. All the tests did pass.. however running it to get all primes between 10K and 100K took &lt;span style="font-weight: bold;"&gt;34 secs&lt;/span&gt; to execute. And I was on the new n improved ruby 1.9 with a better VM. I switched to the stable ruby 1.8.6 and it took &lt;span style="font-weight: bold;"&gt;~60 secs&lt;/span&gt;.&lt;span style="font-weight: bold;"&gt; &lt;/span&gt;So now I turned back to my primary Weapon &lt;span style="font-weight: bold;"&gt;C#. &lt;/span&gt;The same steps implemented in C# took &lt;span style="font-weight: bold;"&gt;722 msecs. &lt;/span&gt;So now there were 2 possibilities&lt;br /&gt;1. Ruby is sloooow (the usual gripe)&lt;br /&gt;2. Something in my algorithm is messed up.&lt;br /&gt;&lt;br /&gt;So I posted my source onto StackOverflow - (my current fave time sink :) to get some eyeballs to look at the problem. &lt;br /&gt;So here's my naive implementation&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;PrimeGenerator&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;self.get_primes_between&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt; &lt;span class="ident"&gt;x&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;y&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;sieve_array&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Array&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;y&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;index&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;      &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;index&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="number"&gt;0&lt;/span&gt; &lt;span class="punct"&gt;?&lt;/span&gt; &lt;span class="number"&gt;0&lt;/span&gt; &lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="ident"&gt;index&lt;/span&gt;&lt;span class="punct"&gt;+&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class="ident"&gt;position_when_we_can_stop_checking&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Math&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;sqrt&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;y&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;to_i&lt;/span&gt;&lt;br /&gt;    &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;2&lt;/span&gt;&lt;span class="punct"&gt;..&lt;/span&gt;&lt;span class="ident"&gt;position_when_we_can_stop_checking&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt;&lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;factor&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;      &lt;span class="ident"&gt;sieve_array&lt;/span&gt;&lt;span class="punct"&gt;[(&lt;/span&gt;&lt;span class="ident"&gt;factor&lt;/span&gt;&lt;span class="punct"&gt;)..&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;y&lt;/span&gt;&lt;span class="punct"&gt;-&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;)].&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt;&lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;number&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;        &lt;span class="ident"&gt;sieve_array&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;number&lt;/span&gt;&lt;span class="punct"&gt;-&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;0&lt;/span&gt; &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;isMultipleOf&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;number&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;factor&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span class="ident"&gt;sieve_array&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;select&lt;/span&gt;&lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;element&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;br /&gt;      &lt;span class="punct"&gt;(&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;element&lt;/span&gt; &lt;span class="punct"&gt;!=&lt;/span&gt; &lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;x&lt;/span&gt;&lt;span class="punct"&gt;..&lt;/span&gt;&lt;span class="ident"&gt;y&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;include?&lt;/span&gt; &lt;span class="ident"&gt;element&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;self.isMultipleOf&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;x&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;y&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;x&lt;/span&gt; &lt;span class="punct"&gt;%&lt;/span&gt; &lt;span class="ident"&gt;y&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="number"&gt;0&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;# Benchmarking code&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;benchmark&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;&lt;span class="constant"&gt;Benchmark&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;bm&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;30&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;r&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;  &lt;span class="ident"&gt;r&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;report&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Gishu&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="ident"&gt;a&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;PrimeGenerator&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;get_primes_between&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt; &lt;span class="number"&gt;1_000&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;10_000&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;A few people got back with what might be the problem.&lt;br /&gt;One of the first and most voted issue was the slicing the array to get a new subset array. That's got to be expensive inside a loop for an array of this size. Obviously I was using for loops in C# (since C# doesn't have Ruby's each)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="keyword"&gt;for&lt;/span&gt; &lt;span class="ident"&gt;index&lt;/span&gt; &lt;span class="keyword"&gt;in&lt;/span&gt; &lt;span class="ident"&gt;factor&lt;/span&gt;&lt;span class="punct"&gt;..&lt;/span&gt;&lt;span class="ident"&gt;y&lt;/span&gt;&lt;span class="punct"&gt;-&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;&lt;br /&gt;  &lt;span class="ident"&gt;sieve_array&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;index&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;0&lt;/span&gt; &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;isMultipleOf&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;index&lt;/span&gt;&lt;span class="punct"&gt;+&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;factor&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;That shaved off 8 secs - 24%. But still 26 secs. Another optimization was to reduce iterations - instead of checking each number with IsMultiple(number, _loopVar), set the 'step' for the loop to equal _loopVar (so from 2 you go 4,6,8,10...)&lt;br /&gt;&lt;br /&gt;And finally &lt;a href="http://stackoverflow.com/users/1060/mike-woodhouse"&gt;Mike Woodhouse&lt;/a&gt; dispatched a homer. He posted a tiny snippet that did the same thing in &lt;span style="font-weight: bold;"&gt;under 1 sec.&lt;/span&gt; No that's not a typo.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;sieve_to&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;n&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="ident"&gt;s&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;..&lt;/span&gt;&lt;span class="ident"&gt;n&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;to_a&lt;/span&gt;&lt;br /&gt;  &lt;span class="ident"&gt;s&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;]=&lt;/span&gt;&lt;span class="ident"&gt;s&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;]=&lt;/span&gt;&lt;span class="constant"&gt;nil&lt;/span&gt;&lt;br /&gt;  &lt;span class="ident"&gt;s&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;p&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword"&gt;next&lt;/span&gt; &lt;span class="keyword"&gt;unless&lt;/span&gt; &lt;span class="ident"&gt;p&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword"&gt;break&lt;/span&gt; &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;p&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt; &lt;span class="ident"&gt;p&lt;/span&gt; &lt;span class="punct"&gt;&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;n&lt;/span&gt;&lt;br /&gt;    &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;p&lt;/span&gt;&lt;span class="punct"&gt;*&lt;/span&gt;&lt;span class="ident"&gt;p&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;step&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;n&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;p&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;m&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;s&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;m&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;nil&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;span class="ident"&gt;s&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;compact&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;# Usage:&lt;br /&gt;# puts sieve_to(11).select{|x| x&gt;=3}.inspect&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;        user     system      total        real&lt;br /&gt;Gishu  27.219000   0.000000  27.219000 ( 27.375000)&lt;br /&gt;Mike    0.141000   0.000000   0.141000 (  0.140625)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;I then had to know how he did it..&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Smart#1: He skips if array[_loopvar] is already 0. whereas if array[6] is crossed out due to 3, I did a scanning run to set all multiples of 6 to 0 which were already 0.(now down to &lt;span style="font-weight: bold;"&gt;6 secs&lt;/span&gt;)&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Smart#2: Use the Numeric#step trick to jump to the next multiple vs traversing entire list with an IsMultiple check (now down to &lt;span style="font-weight: bold;"&gt;0.25 secs&lt;/span&gt;)&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Smart#3: He begins the inner loop with Square of p. e.g if _loopvar is 7, I used to check from 8-&gt;end. Mike checks from 49-&gt;end. This one was a little tricky to figure out.. the reason is 7x2, 7x3, 7x4, 7x5, 7x6 have already been crossed out when _loopVar &lt;span style="font-weight: bold;"&gt;was&lt;/span&gt; 2,3,4,5,6 respectively. (now down to &lt;span style="font-weight: bold;"&gt;0.21 secs&lt;/span&gt;)&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Smart#4: Smart use of Ruby's nil for crossed out vs my choice of 0. That followed by Array#compact reduces the number of elements for the final select operation to get primes between x and y (now down to &lt;span style="font-weight: bold;"&gt;0.18 secs&lt;/span&gt;.)&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;So after all that it's &lt;span style="font-weight:bold;"&gt;Ruby 0.15 secs&lt;/span&gt; and &lt;span style="font-weight:bold;"&gt;C#&lt;/span&gt; (with same optimizations) &lt;span style="font-weight:bold;"&gt;0.028 secs&lt;/span&gt;, much more easy to take in.&lt;br /&gt;&lt;br /&gt;An interesting thought to end this post is that even with the naive first implementation C# performed reasonably well... under a sec. I'd have moved on to the next task. Ruby on the other hand slowed to a crawl forcing me to take another look for optimizations. In a indirect sort of way, C#'s superior performance could be hiding bad/substandard solutions and letting programmers get away with it... &lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-1256027709755525037?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/1256027709755525037/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2009/04/i-wrote-up-small-program-to-find-prime.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/1256027709755525037'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/1256027709755525037'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2009/04/i-wrote-up-small-program-to-find-prime.html' title='Ruby is slow... until you learn to write good code.'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-2627401408343433661</id><published>2009-04-08T10:22:00.000+05:30</published><updated>2009-04-08T11:03:47.002+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Sorting'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>MergeSort in Ruby</title><content type='html'>&lt;span style="font-family:trebuchet ms;"&gt;Finally got the ball rolling on the 'Introduction to Algorithms' book.. What I figured was that I implement the sorting algorithms in ruby - help me get better at ruby AND algorithms.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;I've got to confess.. I'm test-infected so I'm gonna TDD my way out. This series of posts are not going to be in a walkthrough style of narration.. I'm just going to post complete samples. The order of methods indicate how the code was built up.. (the first method is the 'oldest'.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms; color: rgb(153, 0, 0);"&gt;Here's &lt;/span&gt;&lt;span style="font-weight: bold; font-family: trebuchet ms; color: rgb(153, 0, 0);"&gt;merge_sort_test.rb&lt;/span&gt;&lt;span style="font-family: trebuchet ms; color: rgb(153, 0, 0);"&gt; [The Test Fixture]&lt;/span&gt;&lt;br /&gt;--&lt;br /&gt;&lt;pre&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;test/unit&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;merge_sort&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;TestMergeSort&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Test&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Unit&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;TestCase&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;test_partition_array_with_even_number_of_elements&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;left&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;right&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;MergeSort&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;partition_array&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;11&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;5&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;9&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;15&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;assert_equal&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;11&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;5&lt;/span&gt;&lt;span class="punct"&gt;],&lt;/span&gt; &lt;span class="ident"&gt;left&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;assert_equal&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;9&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;15&lt;/span&gt;&lt;span class="punct"&gt;],&lt;/span&gt; &lt;span class="ident"&gt;right&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;test_partition_array_with_odd_number_of_elements&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;left&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;right&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;MergeSort&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;partition_array&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;11&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;5&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;45&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;9&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;15&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;assert_equal&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;11&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;5&lt;/span&gt;&lt;span class="punct"&gt;],&lt;/span&gt; &lt;span class="ident"&gt;left&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;assert_equal&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;45&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;9&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;15&lt;/span&gt;&lt;span class="punct"&gt;],&lt;/span&gt; &lt;span class="ident"&gt;right&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;test_merge_arrays&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;assert_equal&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;10&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;20&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;30&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;40&lt;/span&gt;&lt;span class="punct"&gt;],&lt;/span&gt; &lt;br /&gt;      &lt;span class="constant"&gt;MergeSort&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;merge_arrays&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;10&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;30&lt;/span&gt;&lt;span class="punct"&gt;],&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;20&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;40&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span class="ident"&gt;assert_equal&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;3&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;5&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;9&lt;/span&gt;&lt;span class="punct"&gt;],&lt;/span&gt; &lt;br /&gt;      &lt;span class="constant"&gt;MergeSort&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;merge_arrays&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;5&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;9&lt;/span&gt;&lt;span class="punct"&gt;],&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;3&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;assert_equal&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;3&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;5&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;9&lt;/span&gt;&lt;span class="punct"&gt;],&lt;/span&gt; &lt;br /&gt;      &lt;span class="constant"&gt;MergeSort&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;merge_arrays&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;3&lt;/span&gt;&lt;span class="punct"&gt;],&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;5&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;9&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;test_sort&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;assert_equal&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;2&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;3&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;4&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;5&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;6&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;7&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;8&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;9&lt;/span&gt;&lt;span class="punct"&gt;],&lt;/span&gt;  &lt;br /&gt;      &lt;span class="constant"&gt;MergeSort&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;sort&lt;/span&gt;&lt;span class="punct"&gt;([&lt;/span&gt; &lt;span class="number"&gt;8&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;3&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;4&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;9&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;2&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;7&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;6&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;5&lt;/span&gt;&lt;span class="punct"&gt;])&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;--&lt;br /&gt;&lt;span style="font-weight: bold; font-family: trebuchet ms; color: rgb(153, 0, 0);"&gt;merge_sort.rb&lt;/span&gt;&lt;span style="font-family: trebuchet ms; color: rgb(153, 0, 0);"&gt; [The Implementation]&lt;/span&gt;&lt;br /&gt;--&lt;br /&gt;&lt;pre&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;MergeSort&lt;/span&gt; &lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;self.partition_array&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt; &lt;span class="ident"&gt;input_array&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;mid_index&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;input_array&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;length&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt; &lt;span class="number"&gt;2&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;-&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt;&lt;br /&gt;    &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;input_array&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;..&lt;/span&gt;&lt;span class="ident"&gt;mid_index&lt;/span&gt;&lt;span class="punct"&gt;],&lt;/span&gt; &lt;span class="ident"&gt;input_array&lt;/span&gt;&lt;span class="punct"&gt;[(&lt;/span&gt;&lt;span class="ident"&gt;mid_index&lt;/span&gt;&lt;span class="punct"&gt;+&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;)..(&lt;/span&gt;&lt;span class="ident"&gt;input_array&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;length&lt;/span&gt;&lt;span class="punct"&gt;-&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;)]]&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;self.merge_arrays&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;array1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;array2&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;merged_array&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;[]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class="keyword"&gt;until&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;array1&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;empty?&lt;/span&gt; &lt;span class="punct"&gt;||&lt;/span&gt; &lt;span class="ident"&gt;array2&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;empty?&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;&lt;br /&gt;      &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;array1&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="ident"&gt;array2&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;])&lt;/span&gt;&lt;br /&gt;        &lt;span class="ident"&gt;merged_array&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="ident"&gt;array1&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;shift&lt;/span&gt;&lt;br /&gt;      &lt;span class="keyword"&gt;else&lt;/span&gt;&lt;br /&gt;        &lt;span class="ident"&gt;merged_array&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="ident"&gt;array2&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;shift&lt;/span&gt;&lt;br /&gt;      &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span class="ident"&gt;merged_array&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="ident"&gt;array1&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="ident"&gt;array2&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;self.sort&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt; &lt;span class="ident"&gt;input_array&lt;/span&gt; &lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="ident"&gt;input_array&lt;/span&gt; &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;input_array&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;length&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="number"&gt;2&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span class="ident"&gt;left&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;right&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;partition_array&lt;/span&gt; &lt;span class="ident"&gt;input_array&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;sortedLeft&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;sort&lt;/span&gt; &lt;span class="ident"&gt;left&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;sortedRight&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;sort&lt;/span&gt; &lt;span class="ident"&gt;right&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;y&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;merge_arrays&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt; &lt;span class="ident"&gt;sortedLeft&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;sortedRight&lt;/span&gt; &lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;--&lt;br /&gt;&lt;span style="color: rgb(153, 0, 0);font-family:trebuchet ms;" &gt;A command line 'runner'/'main' function&lt;/span&gt;&lt;br /&gt;--&lt;br /&gt;&lt;pre&gt;&lt;span class="comment"&gt;# Console runner / main&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="punct"&gt;!&lt;/span&gt;&lt;span class="constant"&gt;ARGV&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;nil?&lt;/span&gt;&lt;br /&gt;  &lt;span class="ident"&gt;input&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;[]&lt;/span&gt;&lt;br /&gt;  &lt;span class="constant"&gt;ARGV&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt;&lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;x&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;input&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="ident"&gt;x&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_i&lt;/span&gt;&lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="constant"&gt;MergeSort&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;sort&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;input&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;inspect&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;--&lt;br /&gt;&gt;ruby merge_sort.rb 90, 100, 40, 10, 45&lt;br /&gt;[10, 40, 45, 90, 100]&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;And we're done! IMHO The Ruby Array class really shines here w.r.t. readability.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-2627401408343433661?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/2627401408343433661/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2009/04/mergesort-in-ruby.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/2627401408343433661'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/2627401408343433661'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2009/04/mergesort-in-ruby.html' title='MergeSort in Ruby'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-2737361317623908202</id><published>2009-02-03T16:38:00.000+05:30</published><updated>2009-02-04T18:37:50.280+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='.net'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Dynamic evaluation of an expression</title><content type='html'>&lt;span style="font-family:trebuchet ms;"&gt;In this post, I'll tackle Step#2 of evaluating an expression like &lt;span style="font-weight: bold;"&gt;2 * (3 + 5)&lt;/span&gt; and return 16.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Convert expression from infix to postfix (see the last 2 posts)&lt;/li&gt;&lt;li&gt;Evaluate postfix expression to determine result&lt;/li&gt;&lt;/ol&gt;As always, write a new test for ExpressionConverter&lt;/span&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;[Test]&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; TestEvaluate()&lt;br /&gt;{&lt;br /&gt;   ExpressionConverter converter = &lt;span class="kwrd"&gt;new&lt;/span&gt; ExpressionConverter();&lt;br /&gt;   Assert.AreEqual(10, converter.EvaluateInfixExpression(&lt;span class="str"&gt;"((1+2) + 3) * 8/4"&lt;/span&gt;));&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;The implementation is very simple now that we have the ability to 'convert to postfix'.&lt;/span&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; EvaluateInfixExpression(&lt;span class="kwrd"&gt;string&lt;/span&gt; sInfixExpression)&lt;br /&gt;{&lt;br /&gt;   List&lt;&lt;span class="kwrd"&gt;object&lt;/span&gt;&gt; postfixExpression = &lt;span class="kwrd"&gt;this&lt;/span&gt;.ConvertInfixToPostfix(sInfixExpression);&lt;br /&gt;   Stack&lt;&lt;span class="kwrd"&gt;object&lt;/span&gt;&gt; stack = &lt;span class="kwrd"&gt;new&lt;/span&gt; Stack&lt;&lt;span class="kwrd"&gt;object&lt;/span&gt;();&lt;br /&gt;   &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;object&lt;/span&gt; term &lt;span class="kwrd"&gt;in&lt;/span&gt; postfixExpression)&lt;br /&gt;   {&lt;br /&gt;       &lt;span class="kwrd"&gt;if&lt;/span&gt; (term &lt;span class="kwrd"&gt;is&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt;)&lt;br /&gt;       {&lt;br /&gt;           stack.Push(term);&lt;br /&gt;       }&lt;br /&gt;       &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;       {&lt;br /&gt;          Operator operatorTerm = term &lt;span class="kwrd"&gt;as&lt;/span&gt; Operator;&lt;br /&gt;          &lt;span class="kwrd"&gt;int&lt;/span&gt; iValue2 = (&lt;span class="kwrd"&gt;int&lt;/span&gt;) stack.Pop();&lt;br /&gt;          &lt;span class="kwrd"&gt;int&lt;/span&gt; iValue1 = (&lt;span class="kwrd"&gt;int&lt;/span&gt;) stack.Pop();&lt;br /&gt;          stack.Push( operatorTerm.Evaluate(iValue1, iValue2) );&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;   &lt;span class="kwrd"&gt;return&lt;/span&gt; stack.Peek();&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Except that we don't have Operator#Evaluate()... Lets get over that hurdle. Mark this test with a temp Ignore tag. Write a new test in the TestOperator fixture&lt;/span&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;[Test]&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; TestPlusOperator_Evaluate()&lt;br /&gt;{&lt;br /&gt;   Assert.AreEqual(30, Operator.Plus.Evaluate(10, 20));&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;If each operator could have a associated evaluate code block that evaluated 2 parameters and returned the result, we'd be done. A new member variable, a new parameterized ctor and a new code block later.. Here are the changes&lt;/span&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Operator&lt;br /&gt;{&lt;br /&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; Operator Plus = &lt;span class="kwrd"&gt;new&lt;/span&gt; Operator(&lt;span class="str"&gt;"+"&lt;/span&gt;, 1, &lt;span style="font-weight: bold;"&gt;(x, y) =&gt; x + y );&lt;br /&gt;   &lt;span class="kwrd"&gt;private&lt;/span&gt; Func&lt;&lt;span class="kwrd"&gt;int&lt;/span&gt;,&lt;span class="kwrd"&gt;int&lt;/span&gt;,&lt;span class="kwrd"&gt;int&lt;/span&gt;&gt; m_evaluateDelegate;&lt;br /&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;private&lt;/span&gt; Operator(&lt;span class="kwrd"&gt;string&lt;/span&gt; sSymbol, &lt;span class="kwrd"&gt;int&lt;/span&gt; iPrecedenceLevel, Func&lt;&lt;span class="kwrd"&gt;int&lt;/span&gt;,&lt;span class="kwrd"&gt;int&lt;/span&gt;,&lt;span class="kwrd"&gt;int&lt;/span&gt;&gt; evaluateDelegate):&lt;span class="kwrd"&gt;this&lt;/span&gt;(sSymbol, iPrecedenceLevel)&lt;br /&gt;   {&lt;br /&gt;       m_evaluateDelegate = evaluateDelegate;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; Evaluate(&lt;span class="kwrd"&gt;int&lt;/span&gt; iValue1, &lt;span class="kwrd"&gt;int&lt;/span&gt; iValue2)&lt;br /&gt;   {&lt;br /&gt;      &lt;span class="kwrd"&gt;return&lt;/span&gt; m_evaluateDelegate(iValue1,iValue2);&lt;br /&gt;   }&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Green. Ditto for the other operators -, *, /&lt;br /&gt;All done. Finally a console app to do this&lt;/span&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Main(&lt;span class="kwrd"&gt;string&lt;/span&gt;[] args)&lt;br /&gt;{&lt;br /&gt;   ExpressionConverter expr = &lt;span class="kwrd"&gt;new&lt;/span&gt; ExpressionConverter();&lt;br /&gt;&lt;br /&gt;   Console.WriteLine(&lt;span class="str"&gt;"Postfix version is "&lt;/span&gt;);&lt;br /&gt;   &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;object&lt;/span&gt; term &lt;span class="kwrd"&gt;in&lt;/span&gt; expr.ConvertInfixToPostfix(args[0]))&lt;br /&gt;   {   Console.Write(term + &lt;span class="str"&gt;" "&lt;/span&gt;);   }&lt;br /&gt;   Console.WriteLine();&lt;br /&gt;&lt;br /&gt;   Console.WriteLine(&lt;span class="str"&gt;"Expression evaluated to "&lt;/span&gt; + expr.EvaluateInfixExpression(args[0]) );&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;This is how it works.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;Release&gt;DynCalc.exe "((1+2) + 3) * 2 - 8/4"&lt;br /&gt;Postfix version is&lt;br /&gt;1 2 + 3 + 2 * 8 4 / -&lt;br /&gt;Expression evaluated to 10&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Now ExpressionConverter is no longer a converter.. we should probably rename it to Expression. Also it has no instance state. All methods can therefore be converted to static methods - no need to create an instance to invoke members. Done. &lt;br /&gt;Other than non-happy paths like malformed expressions.. (can be done) it's all good. End of series. I had fun..&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-2737361317623908202?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/2737361317623908202/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2009/02/dynamic-evaluation-of-expression.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/2737361317623908202'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/2737361317623908202'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2009/02/dynamic-evaluation-of-expression.html' title='Dynamic evaluation of an expression'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-4391223589549144266</id><published>2009-02-03T14:08:00.000+05:30</published><updated>2009-02-03T16:50:00.741+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='.net'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Test driving an infix to postfix expression converter (2 of 3)</title><content type='html'>&lt;span style="font-family:trebuchet ms;"&gt;So at the end of &lt;a href="http://madcoderspeak.blogspot.com/2009/02/test-driving-infix-to-postfix.html"&gt;Post 1&lt;/a&gt; of this series. we've a converter that doesn't yet understand operator precedence.&lt;br /&gt;Let me refresh my memory before proceeding..&lt;br /&gt;An operator token belongs to a class/family of 'Operators', has a string representation like *, +, /, - and finally has a relative precedence associated with it.&lt;br /&gt;1 for +, -&lt;br /&gt;2 for *, /&lt;br /&gt;3 for (, )&lt;br /&gt;&lt;br /&gt;Seems like we need an Operator class instead of just a string. I'll mark the failing test with [Ignore("Detour")] tag while we go make some operators.&lt;br /&gt;Create a new test fixture, imagine a magical Operator class.. something like this&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 102, 0);font-family:courier new;font-size:85%;"  &gt;TestOperator.cs&lt;/span&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;[Test]&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; TestParse_PlusOperator()&lt;br /&gt;{&lt;br /&gt;Operator plusOp = Operator.Parse(&lt;span class="str"&gt;"+"&lt;/span&gt;);&lt;br /&gt;Assert.IsNotNull(plusOp);&lt;br /&gt;Assert.AreEqual(&lt;span class="str"&gt;"+"&lt;/span&gt;, plusOp.ToString());&lt;br /&gt;Assert.AreEqual(1, plusOp.PrecedenceLevel);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;I turn my ideas about Operators into a Type/Class.&lt;/span&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Operator&lt;br /&gt;{&lt;br /&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; m_OperatorSymbol;&lt;br /&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; m_iPrecedenceLevel;&lt;br /&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; Operator plusOperator = &lt;span class="kwrd"&gt;new&lt;/span&gt; Operator(&lt;span class="str"&gt;"+"&lt;/span&gt;, 1);&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; Operator(&lt;span class="kwrd"&gt;string&lt;/span&gt; sSymbol, &lt;span class="kwrd"&gt;int&lt;/span&gt; iPrecedenceLevel)&lt;br /&gt;{&lt;br /&gt;   m_OperatorSymbol = sSymbol;&lt;br /&gt;   m_iPrecedenceLevel = iPrecedenceLevel;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; PrecedenceLevel&lt;br /&gt;{&lt;br /&gt;   get { &lt;span class="kwrd"&gt;return&lt;/span&gt; m_iPrecedenceLevel; }&lt;br /&gt;}&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; ToString()&lt;br /&gt;{   &lt;span class="kwrd"&gt;return&lt;/span&gt; m_OperatorSymbol;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; Operator Parse(&lt;span class="kwrd"&gt;string&lt;/span&gt; stringToParse)&lt;br /&gt;{   &lt;span class="kwrd"&gt;return&lt;/span&gt; Operator.plusOperator;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Green! I took the quick way out with the Parse implementation.. I'll let the coming tests force me to distill that bit of code. I add similar tests for Minus (and then Multiply and Divide). I end up with a need for a 'switch case' in Parse().&lt;br /&gt;Also Parse should probably throw if its passed a token that it doesnt recognize. I'll note that down as a test too.&lt;/span&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;[Test]&lt;br /&gt;[ExpectedException(ExceptionType=&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(ArgumentException), ExpectedMessage=&lt;span class="str"&gt;"Unknown Operator! Cannot parse Gishu"&lt;/span&gt;)]&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; TestParse_InvalidInput()&lt;br /&gt;{&lt;br /&gt;Operator noOp = Operator.Parse(&lt;span class="str"&gt;"Gishu"&lt;/span&gt;);&lt;br /&gt;Assert.Fail(&lt;span class="str"&gt;"Operator learnt some AI to parse Gishu. This should have blown up by now!"&lt;/span&gt;);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;[Furious typing] Alright now Operator.Parse() looks like this.. all its tests pass.&lt;/span&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; Operator Parse(&lt;span class="kwrd"&gt;string&lt;/span&gt; stringToParse)&lt;br /&gt;{&lt;br /&gt;&lt;span class="kwrd"&gt;switch&lt;/span&gt; (stringToParse)&lt;br /&gt;{&lt;br /&gt;   &lt;span class="kwrd"&gt;case&lt;/span&gt; &lt;span class="str"&gt;"+"&lt;/span&gt;:&lt;br /&gt;       &lt;span class="kwrd"&gt;return&lt;/span&gt; Operator.plusOperator;&lt;br /&gt;   &lt;span class="kwrd"&gt;case&lt;/span&gt; &lt;span class="str"&gt;"-"&lt;/span&gt;:&lt;br /&gt;       &lt;span class="kwrd"&gt;return&lt;/span&gt; Operator.minusOperator;&lt;br /&gt;   &lt;span class="kwrd"&gt;case&lt;/span&gt; &lt;span class="str"&gt;"*"&lt;/span&gt;:&lt;br /&gt;       &lt;span class="kwrd"&gt;return&lt;/span&gt; Operator.multiplyOperator;&lt;br /&gt;   &lt;span class="kwrd"&gt;case&lt;/span&gt; &lt;span class="str"&gt;"/"&lt;/span&gt;:&lt;br /&gt;       &lt;span class="kwrd"&gt;return&lt;/span&gt; Operator.divisionOperator;&lt;br /&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;default&lt;/span&gt;:&lt;br /&gt;       &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentException(&lt;span class="str"&gt;"Unknown Operator! Cannot parse "&lt;/span&gt; + stringToParse);&lt;br /&gt;}&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Now lets update our tokenizer to use this new type. This looks like it might break a few tests.. but with baby steps and a vigilant eye, it'll all be better by the time I'm done with it. I'll start by modifying one of my initial tokenizer tests...&lt;/span&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;[RowTest]&lt;br /&gt;[Row(&lt;span class="str"&gt;"+"&lt;/span&gt;)]&lt;br /&gt;[Row(&lt;span class="str"&gt;" + "&lt;/span&gt;)]&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ReadPlusOperator(&lt;span class="kwrd"&gt;string&lt;/span&gt; sInput)&lt;br /&gt;{&lt;br /&gt;Tokenizer t = &lt;span class="kwrd"&gt;new&lt;/span&gt; Tokenizer(sInput);&lt;br /&gt;  &lt;br /&gt;&lt;span class="rem"&gt;//Assert.AreEqual("+", t.GetNextToken());&lt;/span&gt;&lt;br /&gt;Assert.AreEqual(Operator.Plus, t.GetNextToken());&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;This would require us to make the static plusOperator member public. The other option is to check each member of the operator object… which would be duplication of the testfixture for Operator. So lets share our operators with the world.. make em public and rename.&lt;/span&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Operator&lt;br /&gt;{&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; Operator Plus = &lt;span class="kwrd"&gt;new&lt;/span&gt; Operator(&lt;span class="str"&gt;"+"&lt;/span&gt;, 1);&lt;br /&gt;//...&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;And we're red...&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;font-size:85%;"  &gt;TestDynCalc.TestTokenizer.ReadPlusOperator( + ):&lt;br /&gt;Expected: &lt;+&gt;&lt;br /&gt;But was:  "+"&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Instead of making a big bang change.. let’s make an ugly hack inside Tokenizer#GetNextToken() to make just this test pass..&lt;/span&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;Regex regexOperator = &lt;span class="kwrd"&gt;new&lt;/span&gt; Regex(&lt;span class="str"&gt;@"^\s*([-+*/()])"&lt;/span&gt;);&lt;br /&gt;obResults = regexOperator.Match(m_sInputData);&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (obResults.Success)&lt;br /&gt;{&lt;br /&gt;Group obGroup = obResults.Groups[1];&lt;br /&gt;RemoveReadCharacters(obGroup);&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;span class="rem"&gt;//return obGroup.Value;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (obGroup.Value != &lt;span class="str"&gt;"+"&lt;/span&gt;)&lt;br /&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; obGroup.Value;&lt;br /&gt;&lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; Operator.Plus;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;I broke 2 tests - that tested the tokenizer with complete expressions containining +. Turns out its easy to fix them. &lt;/span&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;[Test]&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ReadMultipleTokens()&lt;br /&gt;{&lt;br /&gt;Tokenizer t = &lt;span class="kwrd"&gt;new&lt;/span&gt; Tokenizer(&lt;span class="str"&gt;" 2 + 3 - 34 * 2 / 1 "&lt;/span&gt;);&lt;br /&gt;&lt;span class="rem"&gt;//object[] arrExpectedTokens = new object[] { 2, "+", 3, "-", 34, "*", 2, "/", 1 };&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;object&lt;/span&gt;[] arrExpectedTokens = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt;[] { 2, &lt;span style="font-weight: bold;"&gt;Operator.Plus&lt;/span&gt;, 3, &lt;span class="str"&gt;"-"&lt;/span&gt;, 34, &lt;span class="str"&gt;"*"&lt;/span&gt;, 2, &lt;span class="str"&gt;"/"&lt;/span&gt;, 1 };&lt;br /&gt;&lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;object&lt;/span&gt; token &lt;span class="kwrd"&gt;in&lt;/span&gt; arrExpectedTokens)&lt;br /&gt;{&lt;br /&gt;    Assert.AreEqual(token, t.GetNextToken());&lt;br /&gt;}&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;All green. Excuse me while I repeat the procedure for all the other operators. The hack in Tokenizer#GetNextToken() can now be replaced by ... &lt;/span&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;return&lt;/span&gt; Operator.Parse(obGroup.Value);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;However we forgot the parantheses bros. while creating our operators. We need more operators! Mark Tokenizer with Ignore(“2 TDDed operators coming right up…”).. [more furious typing] we have new operators. Take off the ignore tag. Similar changes… and Tokenizer is now Operator-aware.&lt;br /&gt;Time to take off the ignore tag on ExpressionConverter tests and end our little detour.&lt;br /&gt;So we're back to red.. but this time, we've operators with precedence. [after some mental acrobatics with a pencil and an eraser on paper]&lt;br /&gt;The key to getting this is to check if the operator on top of stack is not a '(' and has higher precedence than the incoming/current token. If yes, pop the stack, write popped operator to output and retry. If no, push the incoming token onto the stack.&lt;br /&gt;So + should not be pushed if the top of stack[TOS] contains *; however * should be if TOS is +.&lt;br /&gt;So we add some more code to the final else block in ExpressionConverter#ConvertToPostfix.. &lt;/span&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (obStack.Count() &amp;gt; 0)&lt;br /&gt;{&lt;br /&gt;Operator termOnTopOfStack = obStack.Peek() &lt;span class="kwrd"&gt;as&lt;/span&gt; Operator;&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; ((termOnTopOfStack != Operator.OpenParantheses)&lt;br /&gt;    &amp;amp;&amp;amp; (termOnTopOfStack.PrecedenceLevel &amp;gt; (term &lt;span class="kwrd"&gt;as&lt;/span&gt; Operator).PrecedenceLevel))&lt;br /&gt;{&lt;br /&gt;    postfixExpr.Add(obStack.Pop());&lt;br /&gt;    &lt;span class="kwrd"&gt;continue&lt;/span&gt;;&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;obStack.Push(term);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;All Green! Woohoo! However the method seems to have grown to an uncomfortable size for me... maybe I can refactor.&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Rename method to ExpressionConverter#ConvertInfixToPostfix()&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Stack always contains Operators.. So we can do away the casting...Stack&lt;operator&gt; stackOfOperators&lt;br /&gt;&lt;/operator&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Replace ‘term.ToString() == ")" ‘ with type-based checks&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Each of ( and ) is a parenthesis together they make a set of parentheses. http://en.wikipedia.org/wiki/Parenthesis... well you live, you read wikis, you learn. Correct typos&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Extract some methods to clarify intent.&lt;br /&gt;Had to promote the stack and postfixExpr variables to class members. (All the extracted methods required the stack and List variables to be passed in)&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Looking good. I'll post the refactored version shortly. Let's try another expression/test.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;[Row(&lt;span class="str"&gt;"0-12000-(16*4)-20"&lt;/span&gt;, &lt;span class="str"&gt;"0 12000 - 16 4 * - 20 -"&lt;/span&gt;)]&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Red again! [A few brain cycles later]&lt;br /&gt;This breaks because the converter doesn’t recognize Left to Right precedence for operators at the same level. (In 0 - 5 + 3, - should be performed first to get the result of -2 even though precedence-wise + and - are equivalent.)&lt;br /&gt;But this can be easily solved by replacing &lt;span style="font-weight: bold;"&gt;&amp;gt;&lt;/span&gt; with &lt;span style="font-weight: bold;"&gt;&amp;gt;=&lt;/span&gt; where we compare operator precedence.  Here’s the final version of the class.&lt;/span&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ExpressionConverter&lt;br /&gt;{&lt;br /&gt; List&amp;lt;&lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt; m_postfixExpr = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt;();&lt;br /&gt; Stack&amp;lt;Operator&amp;gt; m_stackOfOperators = &lt;span class="kwrd"&gt;new&lt;/span&gt; Stack&amp;lt;Operator&amp;gt;();&lt;br /&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; List&amp;lt;Object&amp;gt; ConvertInfixToPostfix(&lt;span class="kwrd"&gt;string&lt;/span&gt; sInfixExpr)&lt;br /&gt; {&lt;br /&gt;     m_postfixExpr.Clear(); m_stackOfOperators.Clear();&lt;br /&gt;&lt;br /&gt;     Tokenizer parser = &lt;span class="kwrd"&gt;new&lt;/span&gt; Tokenizer(sInfixExpr);&lt;br /&gt;     &lt;span class="kwrd"&gt;object&lt;/span&gt; term = parser.GetNextToken();&lt;br /&gt;     &lt;span class="kwrd"&gt;while&lt;/span&gt; (term != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;     {&lt;br /&gt;         &lt;span class="kwrd"&gt;if&lt;/span&gt; (term &lt;span class="kwrd"&gt;is&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt;)&lt;br /&gt;         {&lt;br /&gt;             m_postfixExpr.Add(term);&lt;br /&gt;         }&lt;br /&gt;         &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (term == Operator.CloseParenthesis)&lt;br /&gt;         {&lt;br /&gt;             MoveOperatorsOnStackToPostfixExprTillMatchingOpenParenthesisIsFound();&lt;br /&gt;         }&lt;br /&gt;         &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;         {&lt;br /&gt;             Operator operatorTerm = term &lt;span class="kwrd"&gt;as&lt;/span&gt; Operator;&lt;br /&gt;             &lt;span class="kwrd"&gt;if&lt;/span&gt; (OperatorOnTopOfStackHasHigherOrSamePrecedenceAs(operatorTerm))&lt;br /&gt;             {&lt;br /&gt;                 m_postfixExpr.Add(m_stackOfOperators.Pop());&lt;br /&gt;                 &lt;span class="kwrd"&gt;continue&lt;/span&gt;;&lt;br /&gt;             }&lt;br /&gt;&lt;br /&gt;             m_stackOfOperators.Push(operatorTerm);&lt;br /&gt;         }&lt;br /&gt;&lt;br /&gt;         term = parser.GetNextToken();&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;     PopAllRemainingOperatorsOnStackToPostfixExpr();&lt;br /&gt;     &lt;span class="kwrd"&gt;return&lt;/span&gt; m_postfixExpr;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; OperatorOnTopOfStackHasHigherOrSamePrecedenceAs(Operator term)&lt;br /&gt; {&lt;br /&gt;     &lt;span class="kwrd"&gt;if&lt;/span&gt; (m_stackOfOperators.Count() == 0)&lt;br /&gt;         &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;     Operator termOnTopOfStack = m_stackOfOperators.Peek();&lt;br /&gt;     &lt;span class="kwrd"&gt;return&lt;/span&gt; ((termOnTopOfStack != Operator.OpenParenthesis)&lt;br /&gt;             &amp;amp;&amp;amp; (termOnTopOfStack.PrecedenceLevel &amp;gt;= term.PrecedenceLevel));&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; MoveOperatorsOnStackToPostfixExprTillMatchingOpenParenthesisIsFound()&lt;br /&gt; {&lt;br /&gt;     Operator term = m_stackOfOperators.Pop();&lt;br /&gt;     &lt;span class="kwrd"&gt;while&lt;/span&gt; (term != Operator.OpenParenthesis)&lt;br /&gt;     {&lt;br /&gt;         m_postfixExpr.Add(term);&lt;br /&gt;         term = m_stackOfOperators.Pop();&lt;br /&gt;     }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; PopAllRemainingOperatorsOnStackToPostfixExpr()&lt;br /&gt; {&lt;br /&gt;     &lt;span class="kwrd"&gt;while&lt;/span&gt; (m_stackOfOperators.Count &amp;gt; 0)&lt;br /&gt;         m_postfixExpr.Add(m_stackOfOperators.Pop());&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Code is good. End of post. In &lt;a href="http://madcoderspeak.blogspot.com/2009/02/dynamic-evaluation-of-expression.html"&gt;the next post&lt;/a&gt;, I'll write a console 'main' app to exercise the converter and evaluate the expression.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14744716-4391223589549144266?l=madcoderspeak.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://madcoderspeak.blogspot.com/feeds/4391223589549144266/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://madcoderspeak.blogspot.com/2009/02/test-driving-infix-to-postfix_03.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/4391223589549144266'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14744716/posts/default/4391223589549144266'/><link rel='alternate' type='text/html' href='http://madcoderspeak.blogspot.com/2009/02/test-driving-infix-to-postfix_03.html' title='Test driving an infix to postfix expression converter (2 of 3)'/><author><name>Gishu</name><uri>http://www.blogger.com/profile/17616896114730114577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp2.blogger.com/_nxgDpneh8yk/R7kDsbzGt3I/AAAAAAAAAJA/5HVvvhE97wY/S220/Thumbelina.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14744716.post-6623081267208564435</id><published>2009-02-02T18:47:00.000+05:30</published><updated>2009-02-03T16:49:34.053+05:30</updated><category scheme='http://www.blogger.com/atom/ns#' term='.net'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Test driving an infix to postfix expression converter (1 of 2)</title><content type='html'>&lt;span style="font-family:trebuchet ms;"&gt;I've been wanting to understand infix to postfix conversion - strangely intriguing to me. Here's what I'm about to ramble on for a while today...&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Given an expression in infix form (operators appear inline in the expression) like&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;3 * (2 + 5)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Transform it to its postfix equivalent&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;3 2 5 + *&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;&lt;br /&gt;This form can be easily evaluated by a computer. You keep pushing terms onto a stack.. everytime you hit a operator, you pop the last 2 values and perform the operation, push the result back on the stack. In time, you will run out of terms and have the result at the top of the stack.&lt;br /&gt;e.g. Stack builds from left to right (TOS is extreme right)&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);font-family:courier new;" &gt;Read 3 Stack [3]&lt;br /&gt;Read 2 Stack [3 2]&lt;br /&gt;Read 5 Stack [3 2 5]&lt;br /&gt;Read + Stack [3 7]   #Pop 5,2 Perform 2+5, Store 7 back on stack&lt;br /&gt;Read * Stack [21]    # Pop 7,3 Perform 3*7, Store 21 back on stack.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Time and again I've procrastinated.. Then I hit &lt;a style="color: rgb(153, 0, 0);" href="http://bartdesmet.net/blogs/bart/archive/2006/10/11/DynCalc-_2D00_-Dynamic-compilation-illustrated-_2D00_-Part-1_3A00_-Infix-to-postfix.aspx"&gt;Bart De Smet's blog post dated Oct 2006&lt;/a&gt; - It's time! :). You may want to read up on the algorithm to parse an infix expression.&lt;br /&gt;&lt;br /&gt;Just to make things interesting I'm going to do it TDD style.. red-green-refactor to glory. I'm trying to shorten the post to the essence.&lt;br /&gt;&lt;br /&gt;I've TDDed myself a Tokenizer, a class that parses a string, uses a couple of regular expressions and returns the next number/operator with each call to GetNextToken().&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 102, 0);font-family:courier new;font-size:85%;"  &gt;Tokenizer.cs&lt;/span&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Tokenizer&lt;br /&gt;{&lt;br /&gt;&lt;span class="kwrd"&gt;string&lt;/span&gt; m_sInputData;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; Tokenizer(&lt;span class="kwrd"&gt;string&lt;/span&gt; sInput)&lt;br /&gt;{    m_sInputData = sInput;    }&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; GetNextToken()&lt;br /&gt;{&lt;br /&gt;Regex regexNumber = &lt;span class="kwrd"&gt;new&lt;/span&gt; Regex(&lt;span class="str"&gt;@"^\s*(\d+)"&lt;/span&gt;);&lt;br /&gt;Match obResults = regexNumber.Match(m_sInputData);&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (obResults.Success)&lt;br /&gt;{&lt;br /&gt;    Group obGroup = obResults.Groups[1];&lt;br /&gt;    RemoveReadCharacters(obGroup);&lt;br /&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; Int32.Parse(obGroup.Value);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Regex regexOperator = &lt;span class="kwrd"&gt;new&lt;/span&gt; Regex(&lt;span class="str"&gt;@"^\s*([-+*/()])"&lt;/span&gt;);&lt;br /&gt;obResults = regexOperator.Match(m_sInputData);&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (obResults.Success)&lt;br /&gt;{&lt;br /&gt;    Group obGroup = obResults.Groups[1];&lt;br /&gt;    RemoveReadCharacters(obGroup);&lt;br /&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt;obGroup.Value;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; RemoveReadCharacters(Group obMatchedGroup)&lt;br /&gt;{&lt;br /&gt;m_sInputData = m_sInputData.Remove(0, obMatchedGroup.Index + obMatchedGroup.Length);&lt;br /&gt;}&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The tokenizer has around 20 tests. I'll post one of the latter tests to illustrate usage&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 102, 0);font-family:courier new;font-size:85%;"  &gt;TestTokenizer.cs&lt;/span&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;[Test]&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ReadMultipleTokensWithParantheses()&lt;br /&gt;{&lt;br /&gt;Tokenizer t = &lt;span class="kwrd"&gt;new&lt;/span&gt; Tokenizer(&lt;span class="str"&gt;" ( 1 + 2 ) * (3 - (8/2))"&lt;/span&gt;);&lt;br /&gt;&lt;span class="kwrd"&gt;object&lt;/span&gt;[] arrExpectedTokens = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt;[] { &lt;span class="str"&gt;"("&lt;/span&gt;, 1, &lt;span class="str"&gt;"+"&lt;/span&gt;, 2, &lt;span class="str"&gt;")"&lt;/span&gt;, &lt;span class="str"&gt;"*"&lt;/span&gt;, &lt;span class="str"&gt;"("&lt;/span&gt;, 3, &lt;span class="str"&gt;"-"&lt;/span&gt;, &lt;span class="str"&gt;"("&lt;/span&gt;, 8, &lt;span class="str"&gt;"/"&lt;/span&gt;, 2, &lt;span class="str"&gt;")"&lt;/span&gt;, &lt;span class="str"&gt;")"&lt;/span&gt; };&lt;br /&gt;&lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;object&lt;/span&gt; token &lt;span class="kwrd"&gt;in&lt;/span&gt; arrExpectedTokens)&lt;br /&gt;{&lt;br /&gt;Assert.AreEqual(token, t.GetNextToken());&lt;br /&gt;}&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;All set to start with the meat of the problem: ExpressionConverter. So we'll come up with out first test employing some wishful thinking. The output is going to be reordered sequence of numbers and operators.. hence List&amp;lt;objects&amp;gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(0, 102, 0);font-family:courier new;font-size:85%;"  &gt;TestExpressionConverter.cs&lt;/span&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;[Test]&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; TestConvert_Simple()&lt;br /&gt;{&lt;br /&gt;ExpressionConverter converter = &lt;span class="kwrd"&gt;new&lt;/span&gt; ExpressionConverter();&lt;br /&gt;List&amp;lt;&lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt; postfixExpr = converter.ConvertToPostfix(&lt;span class="str"&gt;" 2 + 3 "&lt;/span&gt;);&lt;br /&gt;StringBuilder sb = &lt;span class="kwrd"&gt;new&lt;/span&gt; StringBuilder();&lt;br /&gt;&lt;span class="kwrd"&gt;foreach&lt;/span&gt;(&lt;span class="kwrd"&gt;object&lt;/span&gt; term &lt;span class="kwrd"&gt;in&lt;/span&gt; postfixExpr)&lt;br /&gt;{&lt;br /&gt; sb.AppendFormat(&lt;span class="str"&gt;"{0} "&lt;/span&gt;, term.ToString());&lt;br /&gt;}&lt;br /&gt;Assert.AreEqual(&lt;span class="str"&gt;"2 3 +"&lt;/span&gt;, sb.ToString());&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;To make this compile, I need to define the ExpressionConverter class and the ConvertToPostfix method within it. Something like this&lt;/span&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; List&amp;lt;Object&amp;gt; ConvertToPostfix(&lt;span class="kwrd"&gt;string&lt;/span&gt; sInfixExpr)&lt;br /&gt;{&lt;br /&gt;List&amp;lt;&lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;
