<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/rss2full.xsl" type="text/xsl" media="screen"?><?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/itemcontent.css" type="text/css" media="screen"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-12467669</atom:id><lastBuildDate>Thu, 04 Dec 2008 19:08:34 +0000</lastBuildDate><title>Jay Fields' Thoughts</title><description>experiences in software development</description><link>http://blog.jayfields.com/</link><managingEditor>blogger@jayfields.com (Jay Fields)</managingEditor><generator>Blogger</generator><openSearch:totalResults>415</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>5</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/jayfields/mjKQ" type="application/rss+xml" /><item><guid isPermaLink="false">tag:blogger.com,1999:blog-12467669.post-2098060504113224707</guid><pubDate>Wed, 19 Nov 2008 20:10:00 +0000</pubDate><atom:updated>2008-11-19T18:06:09.213-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">testing</category><title>Ubiquitous Assertion Syntax</title><description>One thing that really bothers me about testing is having various different assertion syntaxes. Take a look at the following JUnit examples. (don't worry, I'll be picking on Ruby and .net frameworks as well)&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source vibrant_ink"&gt;&lt;span class="source source_java"&gt;@&lt;span class="storage storage_type storage_type_java"&gt;Test&lt;/span&gt; &lt;span class="storage storage_modifier storage_modifier_access-control storage_modifier_access-control_java"&gt;public&lt;/span&gt; &lt;span class="storage storage_type storage_type_java"&gt;void&lt;/span&gt; simpleAdd() {&lt;br /&gt;    assertEquals(&lt;span class="constant constant_numeric constant_numeric_java"&gt;2&lt;/span&gt;, &lt;span class="constant constant_numeric constant_numeric_java"&gt;1&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_java"&gt;+&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_java"&gt;1&lt;/span&gt;);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@&lt;span class="storage storage_type storage_type_java"&gt;Test&lt;/span&gt;(expected= &lt;span class="support support_type support_type_built-ins support_type_built-ins_java"&gt;IndexOutOfBoundsException&lt;/span&gt;.&lt;span class="storage storage_type storage_type_java"&gt;class&lt;/span&gt;) &lt;span class="storage storage_modifier storage_modifier_access-control storage_modifier_access-control_java"&gt;public&lt;/span&gt; &lt;span class="storage storage_type storage_type_java"&gt;void&lt;/span&gt; empty() { &lt;br /&gt;    &lt;span class="keyword keyword_other keyword_other_class-fns keyword_other_class-fns_java"&gt;new&lt;/span&gt; &lt;span class="support support_type support_type_built-ins support_type_built-ins_java"&gt;ArrayList&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_java"&gt;&amp;lt;&lt;/span&gt;&lt;span class="support support_type support_type_built-ins support_type_built-ins_java"&gt;Object&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_java"&gt;&amp;gt;&lt;/span&gt;().get(&lt;span class="constant constant_numeric constant_numeric_java"&gt;0&lt;/span&gt;); &lt;br /&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;In both tests I want to verify something; however the two tests use different mechanisms for verification. This adds pain for anyone reading or maintaining the test. When determining what a test is verifying you need to look for assertions as well as expected exceptions in the annotation.&lt;br /&gt;&lt;br /&gt;When you start adding &lt;a href="http://blog.jayfields.com/2008/02/behavior-based-testing.html"&gt;behavior based tests&lt;/a&gt; the situation gets even worse.&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source vibrant_ink"&gt;&lt;span class="source source_java"&gt;&lt;span class="storage storage_type storage_type_java"&gt;Mockery&lt;/span&gt; context = &lt;span class="keyword keyword_other keyword_other_class-fns keyword_other_class-fns_java"&gt;new&lt;/span&gt; &lt;span class="storage storage_type storage_type_java"&gt;Mockery&lt;/span&gt;();&lt;br /&gt;&lt;br /&gt;@&lt;span class="storage storage_type storage_type_java"&gt;Test&lt;/span&gt; &lt;span class="storage storage_modifier storage_modifier_access-control storage_modifier_access-control_java"&gt;public&lt;/span&gt; &lt;span class="storage storage_type storage_type_java"&gt;void&lt;/span&gt; simpleAdd() {&lt;br /&gt;    assertEquals(&lt;span class="constant constant_numeric constant_numeric_java"&gt;2&lt;/span&gt;, &lt;span class="constant constant_numeric constant_numeric_java"&gt;1&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_java"&gt;+&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_java"&gt;1&lt;/span&gt;);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@&lt;span class="storage storage_type storage_type_java"&gt;Test&lt;/span&gt;(expected= &lt;span class="support support_type support_type_built-ins support_type_built-ins_java"&gt;IndexOutOfBoundsException&lt;/span&gt;.&lt;span class="storage storage_type storage_type_java"&gt;class&lt;/span&gt;) &lt;span class="storage storage_modifier storage_modifier_access-control storage_modifier_access-control_java"&gt;public&lt;/span&gt; &lt;span class="storage storage_type storage_type_java"&gt;void&lt;/span&gt; empty() {&lt;br /&gt;    &lt;span class="keyword keyword_other keyword_other_class-fns keyword_other_class-fns_java"&gt;new&lt;/span&gt; &lt;span class="support support_type support_type_built-ins support_type_built-ins_java"&gt;ArrayList&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_java"&gt;&amp;lt;&lt;/span&gt;&lt;span class="support support_type support_type_built-ins support_type_built-ins_java"&gt;Object&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_java"&gt;&amp;gt;&lt;/span&gt;().get(&lt;span class="constant constant_numeric constant_numeric_java"&gt;0&lt;/span&gt;);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@&lt;span class="storage storage_type storage_type_java"&gt;Test&lt;/span&gt; &lt;span class="storage storage_modifier storage_modifier_access-control storage_modifier_access-control_java"&gt;public&lt;/span&gt; &lt;span class="storage storage_type storage_type_java"&gt;void&lt;/span&gt; forWorksCorrectly() {&lt;br /&gt;    &lt;span class="storage storage_modifier storage_modifier_java"&gt;final&lt;/span&gt; &lt;span class="support support_type support_type_built-ins support_type_built-ins_java"&gt;List&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_java"&gt;&amp;lt;&lt;/span&gt;&lt;span class="support support_type support_type_built-ins support_type_built-ins_java"&gt;Integer&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_java"&gt;&amp;gt;&lt;/span&gt; list = context.mock(&lt;span class="support support_type support_type_built-ins support_type_built-ins_java"&gt;List&lt;/span&gt;.&lt;span class="storage storage_type storage_type_java"&gt;class&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;    context.checking(&lt;span class="keyword keyword_other keyword_other_class-fns keyword_other_class-fns_java"&gt;new&lt;/span&gt; &lt;span class="storage storage_type storage_type_java"&gt;Expectations&lt;/span&gt;() {{&lt;br /&gt;        one(list).add(&lt;span class="constant constant_numeric constant_numeric_java"&gt;1&lt;/span&gt;);&lt;br /&gt;        one(list).add(&lt;span class="constant constant_numeric constant_numeric_java"&gt;2&lt;/span&gt;);&lt;br /&gt;    }});&lt;br /&gt;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_java"&gt;for&lt;/span&gt; (&lt;span class="storage storage_type storage_type_java"&gt;int&lt;/span&gt; i=&lt;span class="constant constant_numeric constant_numeric_java"&gt;1&lt;/span&gt;; i &lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_java"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_java"&gt;3&lt;/span&gt;; i&lt;span class="keyword keyword_operator keyword_operator_increment-decrement keyword_operator_increment-decrement_java"&gt;++&lt;/span&gt;) {&lt;br /&gt;        list.add(i);&lt;br /&gt;    }&lt;br /&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Testing 1.0&lt;/span&gt;&lt;br /&gt;3 different tests, 3 different ways to verify your code does what you expect it to. To make matters worse the mock expectations live in the body of the test, so there's no guarantee that when looking for assertions you only need to look at the last few lines of the test. Every time you encounter a test you must spend time looking at the test, top to bottom, and determine what is actually being tested.&lt;br /&gt;&lt;br /&gt;The tests above are simple, it's a much bigger problem when a test uses a few different forms of verification.&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source vibrant_ink"&gt;&lt;span class="source source_java"&gt;&lt;span class="storage storage_type storage_type_java"&gt;Mockery&lt;/span&gt; context = &lt;span class="keyword keyword_other keyword_other_class-fns keyword_other_class-fns_java"&gt;new&lt;/span&gt; &lt;span class="storage storage_type storage_type_java"&gt;Mockery&lt;/span&gt;();&lt;br /&gt;&lt;br /&gt;@&lt;span class="storage storage_type storage_type_java"&gt;Test&lt;/span&gt;(expected= &lt;span class="support support_type support_type_built-ins support_type_built-ins_java"&gt;IndexOutOfBoundsException&lt;/span&gt;.&lt;span class="storage storage_type storage_type_java"&gt;class&lt;/span&gt;) &lt;span class="storage storage_modifier storage_modifier_access-control storage_modifier_access-control_java"&gt;public&lt;/span&gt; &lt;span class="storage storage_type storage_type_java"&gt;void&lt;/span&gt; terribleTest() {&lt;br /&gt;    &lt;span class="storage storage_modifier storage_modifier_java"&gt;final&lt;/span&gt; &lt;span class="support support_type support_type_built-ins support_type_built-ins_java"&gt;List&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_java"&gt;&amp;lt;&lt;/span&gt;&lt;span class="support support_type support_type_built-ins support_type_built-ins_java"&gt;Integer&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_java"&gt;&amp;gt;&lt;/span&gt; original = &lt;span class="keyword keyword_other keyword_other_class-fns keyword_other_class-fns_java"&gt;new&lt;/span&gt; &lt;span class="support support_type support_type_built-ins support_type_built-ins_java"&gt;ArrayList&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_java"&gt;&amp;lt;&lt;/span&gt;&lt;span class="support support_type support_type_built-ins support_type_built-ins_java"&gt;Integer&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_java"&gt;&amp;gt;&lt;/span&gt;(asList(&lt;span class="constant constant_numeric constant_numeric_java"&gt;1&lt;/span&gt;, &lt;span class="constant constant_numeric constant_numeric_java"&gt;2&lt;/span&gt;));&lt;br /&gt;    assertEquals(&lt;span class="constant constant_numeric constant_numeric_java"&gt;2&lt;/span&gt;, original.size());&lt;br /&gt;    &lt;span class="storage storage_modifier storage_modifier_java"&gt;final&lt;/span&gt; &lt;span class="support support_type support_type_built-ins support_type_built-ins_java"&gt;List&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_java"&gt;&amp;lt;&lt;/span&gt;&lt;span class="support support_type support_type_built-ins support_type_built-ins_java"&gt;Integer&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_java"&gt;&amp;gt;&lt;/span&gt; list = context.mock(&lt;span class="support support_type support_type_built-ins support_type_built-ins_java"&gt;List&lt;/span&gt;.&lt;span class="storage storage_type storage_type_java"&gt;class&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;    context.checking(&lt;span class="keyword keyword_other keyword_other_class-fns keyword_other_class-fns_java"&gt;new&lt;/span&gt; &lt;span class="storage storage_type storage_type_java"&gt;Expectations&lt;/span&gt;() {{&lt;br /&gt;        one(list).add(&lt;span class="constant constant_numeric constant_numeric_java"&gt;1&lt;/span&gt;);&lt;br /&gt;        one(list).add(&lt;span class="constant constant_numeric constant_numeric_java"&gt;2&lt;/span&gt;);&lt;br /&gt;    }});&lt;br /&gt;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_java"&gt;for&lt;/span&gt; (&lt;span class="support support_type support_type_built-ins support_type_built-ins_java"&gt;Integer&lt;/span&gt; anOriginal : original) {&lt;br /&gt;        list.add(anOriginal);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    original.clear();&lt;br /&gt;    original.get(&lt;span class="constant constant_numeric constant_numeric_java"&gt;0&lt;/span&gt;);&lt;br /&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;Okay, it would be terrible to run into a test that bad. You might work with people who are smart enough not to do such a thing, but it's very common to see tests that have both assertions and methods that are mocked. You may not consider mocked methods to be a form of verification, but if one of those methods isn't called as you specified it should be called, your test will fail. If it can cause your test to fail, it's a form of verification in my book.&lt;br /&gt;&lt;br /&gt;In Java, there are at least 3 ways to define expected behavior, and often a test mixes more than one. This is not a good situation for a test reader or maintainer.&lt;br /&gt;&lt;br /&gt;In the Ruby and .net worlds, the story isn't much better. The state based assertions are specified differently than the behavior based assertions; however, both Ruby and .net have a superior way of handling expected exceptions: assert_raises and Assert.Throws.&lt;br /&gt;&lt;br /&gt;Below are similar tests in test/unit with mocha (Ruby), with an example of assert_raises for handling the expected exception.&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source vibrant_ink"&gt;&lt;span class="source source_ruby"&gt;&lt;span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;testState&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  assert_equal &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;2&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;testError&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  assert_raises&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;NoMethodError&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;{&lt;/span&gt;&lt;span class="meta meta_syntax meta_syntax_ruby meta_syntax_ruby_start-block"&gt; &lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[]&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;not_a_method &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;testBehavior&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  array &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[]&lt;/span&gt;&lt;br /&gt;  array&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;expects&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;with&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;br /&gt;  array&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;expects&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;with&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;2&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;2&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;each &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;number&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;br /&gt;    array &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_augmented keyword_operator_assignment_augmented_ruby"&gt;&amp;lt;&amp;lt;&lt;/span&gt; number&lt;br /&gt;  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;And, for the .net crowd, here's the NUnit + NMock version of the 3 types of tests. As previously mentioned, NUnit provides an assertion for expecting exceptions, but there's still a mismatch between the state based and behavior based assertions. (full disclosure, I don't have Visual Studio running on my Mac, so if there's a typo, forgive me)&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source vibrant_ink"&gt;&lt;span class="source source_java"&gt;&lt;span class="storage storage_modifier storage_modifier_access-control storage_modifier_access-control_java"&gt;private&lt;/span&gt; &lt;span class="storage storage_type storage_type_java"&gt;Mockery&lt;/span&gt; mocks = &lt;span class="keyword keyword_other keyword_other_class-fns keyword_other_class-fns_java"&gt;new&lt;/span&gt; &lt;span class="storage storage_type storage_type_java"&gt;Mockery&lt;/span&gt;();&lt;br /&gt;&lt;br /&gt;[&lt;span class="storage storage_type storage_type_java"&gt;Test&lt;/span&gt;]&lt;br /&gt;&lt;span class="meta meta_definition meta_definition_method meta_definition_method_java"&gt;&lt;span class="storage storage_modifier storage_modifier_java"&gt;public &lt;/span&gt;&lt;span class="storage storage_type storage_type_java"&gt;void&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_java"&gt;Add&lt;/span&gt;&lt;span class="meta meta_definition meta_definition_param-list meta_definition_param-list_java"&gt;(&lt;/span&gt;)&lt;br /&gt;&lt;/span&gt;{&lt;br /&gt;    &lt;span class="storage storage_type storage_type_java"&gt;Assert&lt;/span&gt;.&lt;span class="storage storage_type storage_type_java"&gt;AreEqual&lt;/span&gt;(&lt;span class="constant constant_numeric constant_numeric_java"&gt;2&lt;/span&gt;, &lt;span class="constant constant_numeric constant_numeric_java"&gt;1&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_java"&gt;+&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_java"&gt;1&lt;/span&gt;);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;[&lt;span class="storage storage_type storage_type_java"&gt;Test&lt;/span&gt;]&lt;br /&gt;&lt;span class="meta meta_definition meta_definition_method meta_definition_method_java"&gt;&lt;span class="storage storage_modifier storage_modifier_java"&gt;public &lt;/span&gt;&lt;span class="storage storage_type storage_type_java"&gt;void&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_java"&gt;Raise&lt;/span&gt;&lt;span class="meta meta_definition meta_definition_param-list meta_definition_param-list_java"&gt;(&lt;/span&gt;)&lt;br /&gt;&lt;/span&gt;{&lt;br /&gt;   &lt;span class="storage storage_type storage_type_java"&gt;Assert&lt;/span&gt;.&lt;span class="storage storage_type storage_type_java"&gt;Throws&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_java"&gt;&amp;lt;&lt;/span&gt;&lt;span class="storage storage_type storage_type_java"&gt;ArgumentException&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_java"&gt;&amp;gt;&lt;/span&gt;(delegate { &lt;span class="keyword keyword_control keyword_control_catch-exception keyword_control_catch-exception_java"&gt;throw&lt;/span&gt; &lt;span class="keyword keyword_other keyword_other_class-fns keyword_other_class-fns_java"&gt;new&lt;/span&gt; &lt;span class="storage storage_type storage_type_java"&gt;ArgumentException&lt;/span&gt;() } );&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;[&lt;span class="storage storage_type storage_type_java"&gt;Test&lt;/span&gt;]&lt;br /&gt;&lt;span class="meta meta_definition meta_definition_method meta_definition_method_java"&gt;&lt;span class="storage storage_modifier storage_modifier_java"&gt;public &lt;/span&gt;&lt;span class="storage storage_type storage_type_java"&gt;void&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_java"&gt;Behavior&lt;/span&gt;&lt;span class="meta meta_definition meta_definition_param-list meta_definition_param-list_java"&gt;(&lt;/span&gt;)&lt;br /&gt;&lt;/span&gt;{&lt;br /&gt;    &lt;span class="storage storage_type storage_type_java"&gt;IList&lt;/span&gt; list = &lt;span class="storage storage_type storage_type_java"&gt;mocks.NewMock&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_java"&gt;&amp;lt;&lt;/span&gt;&lt;span class="storage storage_type storage_type_java"&gt;IList&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_java"&gt;&amp;gt;&lt;/span&gt;();&lt;br /&gt;&lt;br /&gt;    &lt;span class="storage storage_type storage_type_java"&gt;Expect&lt;/span&gt;.&lt;span class="storage storage_type storage_type_java"&gt;Once&lt;/span&gt;.&lt;span class="storage storage_type storage_type_java"&gt;On&lt;/span&gt;(list).&lt;span class="support support_type support_type_built-ins support_type_built-ins_java"&gt;Method&lt;/span&gt;(&lt;span class="string string_quoted string_quoted_double string_quoted_double_java"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_java"&gt;"&lt;/span&gt;Add&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_java"&gt;"&lt;/span&gt;&lt;/span&gt;).&lt;span class="storage storage_type storage_type_java"&gt;With&lt;/span&gt;(&lt;span class="constant constant_numeric constant_numeric_java"&gt;1&lt;/span&gt;);&lt;br /&gt;    &lt;span class="storage storage_type storage_type_java"&gt;Expect&lt;/span&gt;.&lt;span class="storage storage_type storage_type_java"&gt;Once&lt;/span&gt;.&lt;span class="storage storage_type storage_type_java"&gt;On&lt;/span&gt;(list).&lt;span class="support support_type support_type_built-ins support_type_built-ins_java"&gt;Method&lt;/span&gt;(&lt;span class="string string_quoted string_quoted_double string_quoted_double_java"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_java"&gt;"&lt;/span&gt;Add&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_java"&gt;"&lt;/span&gt;&lt;/span&gt;).&lt;span class="storage storage_type storage_type_java"&gt;With&lt;/span&gt;(&lt;span class="constant constant_numeric constant_numeric_java"&gt;2&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_java"&gt;for&lt;/span&gt; (&lt;span class="storage storage_type storage_type_java"&gt;int&lt;/span&gt; i=&lt;span class="constant constant_numeric constant_numeric_java"&gt;1&lt;/span&gt;; i &lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_java"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_java"&gt;3&lt;/span&gt;; i&lt;span class="keyword keyword_operator keyword_operator_increment-decrement keyword_operator_increment-decrement_java"&gt;++&lt;/span&gt;) {&lt;br /&gt;        &lt;span class="storage storage_type storage_type_java"&gt;list.Add&lt;/span&gt;(i);&lt;br /&gt;    }&lt;br /&gt;    &lt;span class="storage storage_type storage_type_java"&gt;mocks.VerifyAllExpectationsHaveBeenMet&lt;/span&gt;();&lt;br /&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Testing 2.0&lt;/span&gt;&lt;br /&gt;In each language there have been steps forward. Both Java and C# have moved in the right direction regarding placement of behavior based expectations. Ruby still suffers from setup placement of mock expectations, but at least the behavior based expectations follow the same assertion syntax that the state based assertions use.&lt;br /&gt;&lt;br /&gt;In Java, the Mockito framework represents a step in the right direction, moving the mock expectations to the end of the test.&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source vibrant_ink"&gt;&lt;span class="source source_java"&gt;@&lt;span class="storage storage_type storage_type_java"&gt;Test&lt;/span&gt; &lt;span class="storage storage_modifier storage_modifier_access-control storage_modifier_access-control_java"&gt;public&lt;/span&gt; &lt;span class="storage storage_type storage_type_java"&gt;void&lt;/span&gt; forRevisited() {&lt;br /&gt;    &lt;span class="support support_type support_type_built-ins support_type_built-ins_java"&gt;List&lt;/span&gt; list = mock(&lt;span class="support support_type support_type_built-ins support_type_built-ins_java"&gt;List&lt;/span&gt;.&lt;span class="storage storage_type storage_type_java"&gt;class&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_java"&gt;for&lt;/span&gt; (&lt;span class="storage storage_type storage_type_java"&gt;int&lt;/span&gt; i=&lt;span class="constant constant_numeric constant_numeric_java"&gt;1&lt;/span&gt;; i &lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_java"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_java"&gt;3&lt;/span&gt;; i&lt;span class="keyword keyword_operator keyword_operator_increment-decrement keyword_operator_increment-decrement_java"&gt;++&lt;/span&gt;) {&lt;br /&gt;        list.add(i);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    verify(list).add(&lt;span class="constant constant_numeric constant_numeric_java"&gt;1&lt;/span&gt;);&lt;br /&gt;    verify(list).add(&lt;span class="constant constant_numeric constant_numeric_java"&gt;2&lt;/span&gt;);&lt;br /&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;Likewise, in .net, Rhino Mocks allows you to use "Arrange, Act, Assert Syntax (AAA)". The result of AAA is (hopefully) all of your tests put their assertions at the end.&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source vibrant_ink"&gt;&lt;span class="source source_java"&gt;&lt;span class="meta meta_definition meta_definition_method meta_definition_method_java"&gt;&lt;span class="storage storage_modifier storage_modifier_java"&gt;public &lt;/span&gt;&lt;span class="storage storage_type storage_type_java"&gt;void&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_java"&gt;ForRevisited&lt;/span&gt;&lt;span class="meta meta_definition meta_definition_param-list meta_definition_param-list_java"&gt;(&lt;/span&gt;)&lt;br /&gt;&lt;/span&gt;{&lt;br /&gt;    var list = &lt;span class="storage storage_type storage_type_java"&gt;MockRepository&lt;/span&gt;.&lt;span class="storage storage_type storage_type_java"&gt;GenerateStub&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_java"&gt;&amp;lt;&lt;/span&gt;&lt;span class="support support_type support_type_built-ins support_type_built-ins_java"&gt;List&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_java"&gt;&amp;gt;&lt;/span&gt;();&lt;br /&gt;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_java"&gt;for&lt;/span&gt; (&lt;span class="storage storage_type storage_type_java"&gt;int&lt;/span&gt; i=&lt;span class="constant constant_numeric constant_numeric_java"&gt;1&lt;/span&gt;; i &lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_java"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_java"&gt;3&lt;/span&gt;; i&lt;span class="keyword keyword_operator keyword_operator_increment-decrement keyword_operator_increment-decrement_java"&gt;++&lt;/span&gt;) {&lt;br /&gt;        &lt;span class="storage storage_type storage_type_java"&gt;list.Add&lt;/span&gt;(i);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="storage storage_type storage_type_java"&gt;list.AssertWasCalled&lt;/span&gt;( x =&lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_java"&gt;&amp;gt;&lt;/span&gt; x.&lt;span class="storage storage_type storage_type_java"&gt;Add&lt;/span&gt;(&lt;span class="constant constant_numeric constant_numeric_java"&gt;1&lt;/span&gt;));&lt;br /&gt;    &lt;span class="storage storage_type storage_type_java"&gt;list.AssertWasCalled&lt;/span&gt;( x =&lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_java"&gt;&amp;gt;&lt;/span&gt; x.&lt;span class="storage storage_type storage_type_java"&gt;Add&lt;/span&gt;(&lt;span class="constant constant_numeric constant_numeric_java"&gt;2&lt;/span&gt;));&lt;br /&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;These steps are good for the big two (Java &amp; C#); however, I'd say they are still a bit too far away from ubiquitous assertion syntax for my taste.&lt;br /&gt;&lt;br /&gt;RSpec represents forward progress in the Ruby community.&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source vibrant_ink"&gt;&lt;span class="source source_ruby"&gt;it &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;should test state&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do&lt;br /&gt;&lt;/span&gt;  &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;2&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;should &lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby"&gt;==&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt;&lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;it &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;should test an error&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do&lt;br /&gt;&lt;/span&gt;  lambda &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;{&lt;/span&gt;&lt;span class="meta meta_syntax meta_syntax_ruby meta_syntax_ruby_start-block"&gt; &lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[]&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;not_a_method &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;}&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;should raise_error&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;NoMethodError&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;it &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;should test behavior&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do&lt;br /&gt;&lt;/span&gt;  array &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[]&lt;/span&gt;&lt;br /&gt;  array&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;should_receive&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;with&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;br /&gt;  array&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;should_receive&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;with&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;2&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;2&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;each &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;number&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;br /&gt;    array &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_augmented keyword_operator_assignment_augmented_ruby"&gt;&amp;lt;&amp;lt;&lt;/span&gt; number&lt;br /&gt;  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;RSpec does a good job of starting all their assertions with "should", (almost?) to a fault. It's not surprising that RSpec was able to somewhat unify the syntax, since the testing framework provides the ability to write both state based and behavior based tests. Looking at the tests you can focus on scanning for the word "should" when looking for what's being tested.&lt;br /&gt;&lt;br /&gt;Unfortunately the unified "should" syntax results in possibly the ugliest assertion ever: lambda {…}.should raise_error(Exception). And, as I previously stated RSpec still suffers from setup placement of the mock expectation "should" methods. Perhaps RSpec could benefit from AAA or some type of test spy &lt;a href="http://pastie.org/319161"&gt;(example implementation available on pastie.org)&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source vibrant_ink"&gt;&lt;span class="source source_ruby"&gt;&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; this doesn't work, but maybe it should....&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;it &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;should test behavior&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do&lt;br /&gt;&lt;/span&gt;  array &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;Spy&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;on &lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[]&lt;/span&gt;&lt;br /&gt;  &lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;2&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;each &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;number&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;br /&gt;    array &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_augmented keyword_operator_assignment_augmented_ruby"&gt;&amp;lt;&amp;lt;&lt;/span&gt; number&lt;br /&gt;  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;  array&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;should have_received &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_augmented keyword_operator_assignment_augmented_ruby"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt;&lt;br /&gt;  array&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;should have_received &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_augmented keyword_operator_assignment_augmented_ruby"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;2&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Next Generation Testing (Testing 3.0?)&lt;/span&gt;&lt;br /&gt;Eventually I expect all testing frameworks will follow RSpec's lead and include their own mocking support, though I'm not holding my breath since it's been two years since I &lt;a href="http://blog.jayfields.com/2006/12/xunit-absence-of-mocks-and-stubs.html"&gt;originally suggested&lt;/a&gt; that this should happen. Today's landscape looks largely the same as it did 2 years ago. When testing frameworks take that next step, the syntax should naturally converge.&lt;br /&gt;&lt;br /&gt;In the Ruby world you do have another option, but one with serious risk. I've been looking for ubiquitous assertion syntax for so long that I rolled my own framework in Ruby: &lt;a href="http://expectations.rubyforge.org"&gt;expectations&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Expectations standardizes on both the location of your assertions (expectations) and how you express them. The following code shows how you can expect a state based result, an exception, and a behavior based result.&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source vibrant_ink"&gt;&lt;span class="source source_ruby"&gt;expect &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;2&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do&lt;br /&gt;&lt;/span&gt;  &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;expect &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;NoMethodError&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do&lt;br /&gt;&lt;/span&gt;  &lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[]&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;no_method_error&lt;br /&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;expect &lt;span class="support support_class support_class_ruby"&gt;Object&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;to&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;receive&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;ping&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;with&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;pong&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;obj&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;br /&gt;  obj&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;ping&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;pong&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;As a result of expectations implementation you can always look at the first line of a test and know exactly what you are testing.&lt;br /&gt;&lt;br /&gt;Full disclosure: Before you go and install expectations and start using it for your production application, you need to know one big problem: there's no support for expectations. I'm no longer doing Ruby full-time and no one has stepped up to maintain the project. It's out there, it works, and it's all yours, but it comes with no guarantees.&lt;br /&gt;&lt;br /&gt;In the .net and Java worlds, the future of testing looks less... evolved. In the .net world, the ever focused on testing Jim Newkirk has teamed up with Brad Wilson to create xUnit.net. xUnit.net represents evolution in the .net space, but as far as I can tell they haven't done much in the way of addressing ubiquitous assertion syntax. In Java, I don't see any movement towards addressing the issue, but can it even happen without closures (anonymous methods, delegates, whatever)?&lt;br /&gt;&lt;br /&gt;I'm surprised that more people aren't bothered by the lack of ubiquitous assertion syntax. Perhaps we have become satisfied with disparity in syntax and the required full test scan.&lt;div class="blogger-post-footer"&gt;&lt;br/&gt;&lt;a href="http://www.jayfields.com"&gt;&amp;copy; Jay Fields - www.jayfields.com&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/jayfields/mjKQ?a=UGzQdm"&gt;&lt;img src="http://feeds.feedburner.com/~a/jayfields/mjKQ?i=UGzQdm" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/jayfields/mjKQ?a=matIN"&gt;&lt;img src="http://feeds.feedburner.com/~f/jayfields/mjKQ?i=matIN" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/jayfields/mjKQ?a=xjDRn"&gt;&lt;img src="http://feeds.feedburner.com/~f/jayfields/mjKQ?i=xjDRn" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/jayfields/mjKQ?a=q6svN"&gt;&lt;img src="http://feeds.feedburner.com/~f/jayfields/mjKQ?i=q6svN" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/jayfields/mjKQ?a=DijCn"&gt;&lt;img src="http://feeds.feedburner.com/~f/jayfields/mjKQ?i=DijCn" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/jayfields/mjKQ?a=XHWan"&gt;&lt;img src="http://feeds.feedburner.com/~f/jayfields/mjKQ?i=XHWan" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/jayfields/mjKQ/~4/458932525" height="1" width="1"/&gt;</description><link>http://feeds.feedburner.com/~r/jayfields/mjKQ/~3/458932525/ubiquitous-assertion-syntax.html</link><author>blogger@jayfields.com (Jay Fields)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">8</thr:total><feedburner:origLink>http://blog.jayfields.com/2008/11/ubiquitous-assertion-syntax.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-12467669.post-1225436403449461453</guid><pubDate>Wed, 19 Nov 2008 01:00:00 +0000</pubDate><atom:updated>2008-11-18T22:24:57.732-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">developers</category><category domain="http://www.blogger.com/atom/ns#">success</category><title>Specialize in Something Relevant</title><description>&lt;blockquote&gt;generalist: a person competent in several different fields or activities&lt;/blockquote&gt;If you read my blog entry on &lt;a href="http://blog.jayfields.com/2008/10/language-specialization.html"&gt;Language Specialization&lt;/a&gt; you might have concluded that I prefer generalists. If, in our industry, generalists were what the definition describes, then I would prefer generalists. Unfortunately, business software developers seem to have created their own definition of generalist.&lt;blockquote&gt;business software developing generalist: I know how to do the simplest tasks with many different languages/tools, but I can not be considered competent with any of them.&lt;/blockquote&gt;I blame Scott Ambler. To me anyway, it seems like the daft generalist movement started when Scott  wrote &lt;a href="http://www.agilemodeling.com/essays/generalizingSpecialists.htm"&gt;Generalizing Specialists&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;Our industry has always been saturated by bad programmers. I'm on record stating that at least &lt;a href="http://blog.jayfields.com/2008/08/elephant-in-server-room.html"&gt;50% of the people writing business software&lt;/a&gt; should find a new profession. The problem with bad developers is that they take good ideas and turn them in to monstrosities.&lt;br /&gt;&lt;br /&gt;I remember reading Generalizing Specialists and being inspired. I thought Scott gave fantastic and relevant advice. Unfortunately, many bad or junior developers heard: Don't bother to deeply understand anything, instead, you're agile if you know a little about everything. Suddenly, when I started interviewing developers I ran into situations like this.&lt;ul&gt;&lt;li&gt;me: So, I see you have Erlang on your resume, how do you like the language?&lt;li&gt;candidate: I like it's concurrency handling, but I'm a bit weary of it's syntax.&lt;li&gt;me: (thinking - okay, do you have any original thoughts on Erlang?) I can understand those points of view, what problem were you trying to solve with Erlang and why did you think it was the right tool?&lt;li&gt;candidate: Oh, I really only got through the 2 minute tutorial, you know, hello world basically. But if you guys have Erlang projects you want me to work on I'm happy to, I'm a generalist, I like all languages.&lt;li&gt;me: Okay, so what language would you say you know the most about?&lt;li&gt;candidate: I don't bother to specialize, I do a little bit with each language, you know, hello world or whatever, so I can use the right tool for the job. That's the best part of being a generalist.&lt;li&gt;me: (thinking - this interview is already over) Okay, so tell me about the languages/tools you've had to use at your different jobs?&lt;/ul&gt;Inevitably, the candidate doesn't even have a deep understanding of the tools they've used at work, because they are too busy doing hello world in every language invented. They also love to say that they take the Pragmatic Programmers advice to extreme and 'learn' several languages a year.&lt;br /&gt;&lt;br /&gt;The truth is, these generalists have little in the way of valuable knowledge. They provide their projects with little more knowledge than a Google search can bestow in 30 minutes. In short, they're worthless, &lt;a href="http://en.wikipedia.org/wiki/NNPP"&gt;if not destructive&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I don't actually blame Scott Ambler. In my opinion he was right then, and he's right now. Become a Generalizing Specialist is still the advice that I currently give developers.&lt;br /&gt;&lt;br /&gt;Specializing in something makes you an asset to the team. If I'm building a Web 2.0 website, I want everyone to have an understanding of HTML, CSS, Javascript, Ruby, &amp; SQL. However, I also want each team member to specialize in one of those areas. Knowing IE quirks is just as important as knowing how to optimize MySQL. And, I want to make sure I have team members that can get into the deep, dark corners of delivering highly effective software. That doesn't mean everyone needs to know what a straight join in MySQL does, but at least 1 person should. The rest of the team isn't entirely off the hook though, they better understand how to write basic SQL statements that are maintainable and at least semi-performant.&lt;br /&gt;&lt;br /&gt;Becoming a Generalizing Specialist takes time, but the first step is becoming a Specialist. Once you deeply understand one language/tool, you can move on to the next relevant language/tool. How do you know when it's time to move on? When you start having answers to questions that people aren't asking. If you're constantly looking up answers to common questions, you aren't a specialist. However, if you start providing more (relevant) detail in your answers than people are looking for, you're on your way to possessing the deep understanding that a Specialist should have. At that point, it's probably time to start looking deeply into something else.&lt;br /&gt;&lt;br /&gt;One painful mistake to look out for is specializing in something less relevant. If you work for a trading firm that writes only thick client applications, understanding why Chrome's Javascript VM is better than Firefox's Javascript VM is probably not the best use of your time. It's true that you may move on to a web application at some point, but by then your information will probably have become stale anyway. Stick to specializing in things that you work with day to day. Your language, your IDE, the Domain Specific Languages you use in your applications (regular expressions, SQL, LINQ, etc), or the frameworks you use (Spring, ASP.net, etc) are things you should specialize in to increase the value you provide to your team.&lt;br /&gt;&lt;br /&gt;Eventually, you become competent with several different tools and languages. You've become a Generalizing Specialist and as such you are significantly more valuable to your team.&lt;div class="blogger-post-footer"&gt;&lt;br/&gt;&lt;a href="http://www.jayfields.com"&gt;&amp;copy; Jay Fields - www.jayfields.com&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/jayfields/mjKQ?a=GHi7kF"&gt;&lt;img src="http://feeds.feedburner.com/~a/jayfields/mjKQ?i=GHi7kF" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/jayfields/mjKQ?a=6Ze8N"&gt;&lt;img src="http://feeds.feedburner.com/~f/jayfields/mjKQ?i=6Ze8N" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/jayfields/mjKQ?a=hiNKn"&gt;&lt;img src="http://feeds.feedburner.com/~f/jayfields/mjKQ?i=hiNKn" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/jayfields/mjKQ?a=LKpvN"&gt;&lt;img src="http://feeds.feedburner.com/~f/jayfields/mjKQ?i=LKpvN" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/jayfields/mjKQ?a=vlE6n"&gt;&lt;img src="http://feeds.feedburner.com/~f/jayfields/mjKQ?i=vlE6n" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/jayfields/mjKQ?a=iw6Jn"&gt;&lt;img src="http://feeds.feedburner.com/~f/jayfields/mjKQ?i=iw6Jn" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/jayfields/mjKQ/~4/457488491" height="1" width="1"/&gt;</description><link>http://feeds.feedburner.com/~r/jayfields/mjKQ/~3/457488491/specialize-in-something-relevant.html</link><author>blogger@jayfields.com (Jay Fields)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">10</thr:total><feedburner:origLink>http://blog.jayfields.com/2008/11/specialize-in-something-relevant.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-12467669.post-879650131757836710</guid><pubDate>Tue, 21 Oct 2008 17:22:00 +0000</pubDate><atom:updated>2008-10-21T13:22:00.317-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">developers</category><category domain="http://www.blogger.com/atom/ns#">success</category><title>Language Specialization</title><description>&lt;blockquote&gt;Didn't you just totally sell out? -- &lt;a href="http://obiefernandez.com/"&gt;Obie Fernandez&lt;/a&gt; @ &lt;a href="http://site.locaweb.com.br/railssummit/default.asp?language=7"&gt;Rails Summit Latin America&lt;/a&gt;&lt;/blockquote&gt;Obie and I are good friends. He wasn't trying to insult me. I was talking about how much I liked my new job (at &lt;a href="http://www.drwtrading.com"&gt;DRW Trading&lt;/a&gt;), and the different aspects of the job. One aspect of my job is that I spend a fair amount of my time working with Java. I do some C# and some Ruby also, but these days it's more Java than anything else. I believe Obie was genuinely curious if I felt like I sold out since I'm not doing Ruby full-time anymore.&lt;br /&gt;&lt;br /&gt;It's an interesting question, but it comes packed with all kinds of assumptions. For the question to be valid, I would have had to trade something I truly care about for the combination of something I did and did not like. Luckily, that wasn't the case.&lt;br /&gt;&lt;br /&gt;Obie isn't the first person to be surprised that I'm no longer working full-time with Ruby. Truthfully, I find it a bit funny that people think I would base a career move on a language. Ruby is my favorite language, but it's not the correct choice for every problem that needs to be solved. And, languages have never been my primary concern when deciding what job to take.&lt;br /&gt;&lt;br /&gt;My first job primarily used Cold Fusion. When I joined AOL Time Warner I gave up Cold Fusion for PHP. When I joined IAG I gave up PHP for C#. And so on. As you can see, I've never been too tied to a language. I've always been most interested in learning and growing. I love jobs that help me improve my skills.&lt;br /&gt;&lt;br /&gt;Chad Fowler talks about something similar. In the section "Don’t Put All Your Eggs in Someone Else’s Basket" of &lt;span style="font-style:italic;"&gt;&lt;a href="http://www.pragprog.com/titles/mjwti/my-job-went-to-india"&gt;My Job Went to India&lt;/a&gt;&lt;/span&gt;, Chad says the following:&lt;blockquote&gt;While managing an application development group, I once asked one of my employees, “What do you want to do with your career? What do you want to be?” I was terribly disppointed by his answer: “I want to be a J2EE architect.” ...&lt;br /&gt;&lt;br /&gt;This guy wanted to build his career around a speciﬁc technology created by a speciﬁc company of which he was not an employee. What if the company goes out of business? What if it let its now-sexy technology become obsolete? Why would you want to trust a technology company with your career?&lt;/blockquote&gt;I think Chad got it right, but it's not just companies you shouldn't trust. I wouldn't base my career on any technology, whether it was produced by a company or an open source community.&lt;br /&gt;&lt;br /&gt;I prefer jobs that allow me to learn new things. Think of it as job security -- I shouldn't ever be out-of-date when it comes to technology experience. Think of it as an investment -- everything I learn creates a broader range of experience that I can leverage for future projects or jobs. Think of it as experimenting -- by trying many different solutions I may find ways to combine them and innovate.&lt;br /&gt;&lt;br /&gt;I've turned down several jobs that paid more or offered comfort. I've never regretted it. Your career is long and (as Chad says) you should treat it as a business. When you look at it from that perspective it obviously makes sense to spend the early years learning and deciding which is the best direction to take.&lt;br /&gt;&lt;br /&gt;The truth is, if you focus on one technology you'll never be as good as your teammates who have more experience mixing technologies to produce the best solution.&lt;br /&gt;&lt;br /&gt;As I told Obie, I definitely don't feel like I sold out. In fact, one of the reasons I joined DRW was because they use Java. I've never worked with Java, messaging, or the financial domain. Having experience with those 3 things will make me better. And, diversifying your experience will make you better as well.&lt;div class="blogger-post-footer"&gt;&lt;br/&gt;&lt;a href="http://www.jayfields.com"&gt;&amp;copy; Jay Fields - www.jayfields.com&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/jayfields/mjKQ?a=60Sx6S"&gt;&lt;img src="http://feeds.feedburner.com/~a/jayfields/mjKQ?i=60Sx6S" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/jayfields/mjKQ?a=HqypM"&gt;&lt;img src="http://feeds.feedburner.com/~f/jayfields/mjKQ?i=HqypM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/jayfields/mjKQ?a=qirJm"&gt;&lt;img src="http://feeds.feedburner.com/~f/jayfields/mjKQ?i=qirJm" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/jayfields/mjKQ?a=PLGoM"&gt;&lt;img src="http://feeds.feedburner.com/~f/jayfields/mjKQ?i=PLGoM" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/jayfields/mjKQ?a=rJKUm"&gt;&lt;img src="http://feeds.feedburner.com/~f/jayfields/mjKQ?i=rJKUm" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/jayfields/mjKQ?a=EhDem"&gt;&lt;img src="http://feeds.feedburner.com/~f/jayfields/mjKQ?i=EhDem" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/jayfields/mjKQ/~4/427684169" height="1" width="1"/&gt;</description><link>http://feeds.feedburner.com/~r/jayfields/mjKQ/~3/427684169/language-specialization.html</link><author>blogger@jayfields.com (Jay Fields)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">9</thr:total><feedburner:origLink>http://blog.jayfields.com/2008/10/language-specialization.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-12467669.post-8467322883386557608</guid><pubDate>Tue, 30 Sep 2008 15:09:00 +0000</pubDate><atom:updated>2008-09-30T11:09:00.093-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">javascript</category><category domain="http://www.blogger.com/atom/ns#">flex</category><category domain="http://www.blogger.com/atom/ns#">ria</category><category domain="http://www.blogger.com/atom/ns#">silverlight</category><category domain="http://www.blogger.com/atom/ns#">testing</category><title>Testing Dynamic Web Applications</title><description>At &lt;a href="http://www.railsconfeurope.com/"&gt;RailsConf Europe&lt;/a&gt;, in the Q &amp; A portion of &lt;a href="http://en.oreilly.com/railseurope2008/public/schedule/detail/2424"&gt;my talk&lt;/a&gt; on Functional Testing someone asked what I recommend for testing Javascript.&lt;br /&gt;&lt;br /&gt;Ugh. Testing Javascript. Is it possible to recommend something when everything you've seen is terrible? Usually I'm cool with picking the tool that sucks the least, but when it comes to Javascript testing the only words that come to mind are: epic fail.&lt;br /&gt;&lt;br /&gt;In the past I've failed in two different ways.&lt;ul&gt;&lt;li&gt;Selenium: Too slow and to brittle for any decent size test suite. There's &lt;a href="http://blog.jayfields.com/2008/07/immaturity-of-in-browser-testing.html"&gt;more&lt;/a&gt; on that if you wish.&lt;/li&gt;&lt;li&gt;Some javascript unit testing framework. I can't even remember the name. The syntax was ugly, the tests weren't easy to write, and the runner didn't integrate with any automated tools we used -- lame.&lt;/li&gt;&lt;/ul&gt;My response in Berlin was "The pivotal guys are smart, so if I were going to try something new it would be Screw Unit." Of course, I just googled and found the RubyForge project and two with the same name on GitHub. I'm sure one of those is the current trunk.&lt;br /&gt;&lt;br /&gt;A few days later it occurred to me what the correct answer was -- Don't use Javascript and you won't have to test it.&lt;br /&gt;&lt;br /&gt;No, I'm not suggesting that we should all go back to mostly static websites. Static content is fine for some things, but GMail is an obvious example of a site that is better done dynamically. &lt;br /&gt;&lt;br /&gt;However, Javascript isn't your only choice for highly dynamic websites.&lt;br /&gt;&lt;br /&gt;These days, if I were writing a website that required any dynamic interaction I would absolutely use &lt;a href="http://www.adobe.com/products/flex/"&gt;Flex&lt;/a&gt; or &lt;a href="http://silverlight.net/"&gt;Silverlight&lt;/a&gt;. I've done Flex, and it was nice to work with, but I must admit that I'm lured to Silverlight because it's going to (or does already?) support Ruby. &lt;br /&gt;&lt;br /&gt;I'm not sure what the Silverlight testing story is, but I found Flex (and ActionScript) to be quite testable. The single biggest win (&lt;a href="http://blog.jayfields.com/2008/06/flex-state-of-testing.html"&gt;as I've said before&lt;/a&gt;) is that I no longer need to do in-browser testing. Removing the browser from the equation is huge. No more IE bugs causing your tests to fail, no long start up times as the browser is run, etc.&lt;br /&gt;&lt;br /&gt;Testing with FlexUnit (with it's drawbacks) is an order of magnitude better than any experience I've had testing Javascript.&lt;br /&gt;&lt;br /&gt;I'm comfortable saying that I would still use Javascript for trivial features that provided so little business value that they did not warrant testing. However, any features that provide noticeable business value must be tested, and I would move to a &lt;a href="http://en.wikipedia.org/wiki/Rich_Internet_application"&gt;RIA&lt;/a&gt; solution instead. &lt;br /&gt;&lt;br /&gt;In my experience, the &lt;a href="http://blog.jayfields.com/2008/05/argument-for-ria.html"&gt;benefits&lt;/a&gt; of switching to a RIA solution are dramatic, one of the largest being: you no longer need to worry about testing Javascript.&lt;div class="blogger-post-footer"&gt;&lt;br/&gt;&lt;a href="http://www.jayfields.com"&gt;&amp;copy; Jay Fields - www.jayfields.com&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/jayfields/mjKQ?a=Stu1ra"&gt;&lt;img src="http://feeds.feedburner.com/~a/jayfields/mjKQ?i=Stu1ra" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/jayfields/mjKQ?a=f6b6L"&gt;&lt;img src="http://feeds.feedburner.com/~f/jayfields/mjKQ?i=f6b6L" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/jayfields/mjKQ?a=3G97l"&gt;&lt;img src="http://feeds.feedburner.com/~f/jayfields/mjKQ?i=3G97l" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/jayfields/mjKQ?a=2cWsL"&gt;&lt;img src="http://feeds.feedburner.com/~f/jayfields/mjKQ?i=2cWsL" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/jayfields/mjKQ?a=CSwUl"&gt;&lt;img src="http://feeds.feedburner.com/~f/jayfields/mjKQ?i=CSwUl" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/jayfields/mjKQ?a=iIbYl"&gt;&lt;img src="http://feeds.feedburner.com/~f/jayfields/mjKQ?i=iIbYl" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/jayfields/mjKQ/~4/407355556" height="1" width="1"/&gt;</description><link>http://feeds.feedburner.com/~r/jayfields/mjKQ/~3/407355556/testing-dynamic-web-applications.html</link><author>blogger@jayfields.com (Jay Fields)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">17</thr:total><feedburner:origLink>http://blog.jayfields.com/2008/09/testing-dynamic-web-applications.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-12467669.post-3133612297743495885</guid><pubDate>Tue, 23 Sep 2008 03:34:00 +0000</pubDate><atom:updated>2008-12-04T14:08:34.349-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">developers</category><category domain="http://www.blogger.com/atom/ns#">success</category><title>When To Retire Your Brand</title><description>&lt;a href="http://blog.jayfields.com/2008/08/be-your-start-up.html"&gt;Building a brand&lt;/a&gt; takes a lot of effort, but I think the payoff justifies the investment. Having a strong brand definitely helped me find a fun and very well paying job. So now that I have a dream job (&lt;a href="http://www.drwtrading.com/"&gt;@ DRW Trading&lt;/a&gt;), what should I do with my brand?&lt;br /&gt;&lt;br /&gt;I have to confess, I didn't start writing because I wanted share information. I started writing because I wanted to build a big brand, find a great job, and enjoy life. Somewhere along the way I began to enjoy writing and the positive results that came from knowledge sharing. Someone once said to me "I write better tests because of your blog". Obviously I was happy to hear that kind of feedback. At the same time it wasn't the reason I got started down this path.&lt;br /&gt;&lt;br /&gt;I love to program. I also love to be in shape (which I'm not) and learn other languages (which I haven't been doing lately).&lt;br /&gt;&lt;br /&gt;Now that I have my dream job, I've been spending more time doing the other things I love. Unfortunately, I found that between learning an &lt;a href="http://en.wikipedia.org/wiki/Proprietary_trading"&gt;interesting domain&lt;/a&gt;, going to the gym, and &lt;a href="http://www.rosettastone.com/personal/languages/italian"&gt;learning Italian&lt;/a&gt;, there's not much time left for blogging. I also find that since I'm doing all the things I love, I don't really like to be away presenting at conferences.&lt;br /&gt;&lt;br /&gt;I thought it might be time to declare success on the brand building project, and move on to new pursuits... But, I was wrong.&lt;br /&gt;&lt;br /&gt;The largest reason I can't quit writing and presenting is that I enjoy giving back to the community. Seeing &lt;a href="http://blog.jayfields.com/2007/12/is-being-niche-language-developer-good.html"&gt;a blog entry&lt;/a&gt; get 8,000 hits in one day causes an amazing feeling. Giving &lt;a href="http://en.oreilly.com/railseurope2008/public/schedule/detail/2424"&gt;a presentation&lt;/a&gt; and getting feedback that says "Probably the best presentation at the conference" definitely makes you feel good about what you are doing. Seeing &lt;a href="http://blog.jayfields.com/2006/09/testunit-test-creation.html"&gt;an idea&lt;/a&gt; become &lt;a href="http://github.com/rails/rails/commit/f74ba37f4e4175d5a1b31da59d161b0020b58e94"&gt;committed&lt;/a&gt; as the way to do something will definitely make you smile. I truly enjoy spreading ideas (or at least attempting to spread ideas) that help the community evolve.&lt;br /&gt;&lt;br /&gt;Blogging and presenting also help me personally improve. The easiest way to get feedback on something is to put it out there. I considered several of my testing ideas to be "the right way" for far too long. Putting them down as blog entries resulted in further evolution of the ideas as well as a greater understanding of how context determines the correct approach. Simply writing about my ideas improves them. One thing we aren't short of is &lt;a href="http://blog.jayfields.com/2008/09/passionate-not-dogmatic.html"&gt;people to tell you you're wrong&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Your brand is also valuable to your employer. Employing people with name recognition improves your organization's ability to recruit talented new hires. This also directly benefits you, since you'll be given the opportunity to work with more talented teammates. At the moment, &lt;a href="http://www.drwtrading.com/"&gt;DRW&lt;/a&gt; is looking to hire the absolute best people in the industry. I wish I had an even stronger brand, so I could help attract the top talent.&lt;br /&gt;&lt;br /&gt;Ultimately I came to the conclusion that building a brand is a career long activity. You can stop at any time, but getting that free time back comes at cost to your profession.&lt;div class="blogger-post-footer"&gt;&lt;br/&gt;&lt;a href="http://www.jayfields.com"&gt;&amp;copy; Jay Fields - www.jayfields.com&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/jayfields/mjKQ?a=hGlIYu"&gt;&lt;img src="http://feeds.feedburner.com/~a/jayfields/mjKQ?i=hGlIYu" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/jayfields/mjKQ?a=Z39pL"&gt;&lt;img src="http://feeds.feedburner.com/~f/jayfields/mjKQ?i=Z39pL" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/jayfields/mjKQ?a=SM1ml"&gt;&lt;img src="http://feeds.feedburner.com/~f/jayfields/mjKQ?i=SM1ml" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/jayfields/mjKQ?a=aeNAL"&gt;&lt;img src="http://feeds.feedburner.com/~f/jayfields/mjKQ?i=aeNAL" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/jayfields/mjKQ?a=M54nl"&gt;&lt;img src="http://feeds.feedburner.com/~f/jayfields/mjKQ?i=M54nl" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/jayfields/mjKQ?a=L7THl"&gt;&lt;img src="http://feeds.feedburner.com/~f/jayfields/mjKQ?i=L7THl" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/jayfields/mjKQ/~4/400421691" height="1" width="1"/&gt;</description><link>http://feeds.feedburner.com/~r/jayfields/mjKQ/~3/400421691/when-to-retire-your-brand.html</link><author>blogger@jayfields.com (Jay Fields)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">5</thr:total><feedburner:origLink>http://blog.jayfields.com/2008/09/when-to-retire-your-brand.html</feedburner:origLink></item></channel></rss>
