<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/atom10full.xsl" type="text/xsl" media="screen"?><?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/itemcontent.css" type="text/css" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0"><id>tag:blogger.com,1999:blog-15045980</id><updated>2008-07-04T17:14:01.092-07:00</updated><title type="text">Google Testing Blog</title><link rel="alternate" type="text/html" href="http://googletesting.blogspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default?start-index=26&amp;max-results=25&amp;redirect=false" /><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://googletesting.blogspot.com/feeds/posts/default" /><author><name>A Googler</name><email>noreply@blogger.com</email></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>71</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><subtitle type="html">If it ain't broke, you're not trying hard enough.</subtitle><link rel="self" href="http://feeds.feedburner.com/blogspot/RLXA" type="application/atom+xml" /><feedburner:emailServiceId>1337274</feedburner:emailServiceId><feedburner:feedburnerHostname>http://www.feedburner.com</feedburner:feedburnerHostname><entry><id>tag:blogger.com,1999:blog-15045980.post-4596842432845665451</id><published>2008-07-03T17:02:00.000-07:00</published><updated>2008-07-03T17:07:07.484-07:00</updated><title type="text">Announcing: New Google C++ Testing Framework</title><content type="html">&lt;span class="byline-author"&gt;Posted by Zhanyong Wan, Software Engineer&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;We all know the importance of writing automated tests to cover our code. To make it easier for everyone to write good C++ tests, today we have open-sourced &lt;a href="http://code.google.com/p/googletest/" id="fl82" target="_blank"&gt;Google C++ Testing Framework&lt;/a&gt; (Google Test for short), a library that thousands of Googlers have been using in our C++ programs.  Highlights of the project include:&lt;br /&gt; &lt;ul id="fl821"&gt;&lt;li id="fl822"&gt;     Google Test is &lt;i id="fl823"&gt;portable&lt;/i&gt;: it works on a variety of platforms (Linux, Windows, Mac OS X, and more), with several versions of GCC and MSVC compilers, and with or without exceptions. You can even use it in embedded systems like Windows CE and Symbian. Build tools and test runners for many of these are under active development, with Linux &lt;a title="Autotools" href="http://www.gnu.org/software/autoconf/" id="aq27"&gt;Autotools&lt;/a&gt; support already in place.&lt;br /&gt;   &lt;/li&gt;&lt;li id="fl824"&gt;     It supports both &lt;a href="http://code.google.com/p/googletest/wiki/GoogleTestPrimer#Basic_Concepts" id="fl825" target="_blank"&gt;fatal and nonfatal&lt;/a&gt; assertions. The test will continue after a nonfatal failure. This allows more problems to be uncovered and fixed in a single edit-compile-test cycle. &lt;/li&gt;&lt;li id="fl826"&gt;     It provides many &lt;a href="http://code.google.com/p/googletest/wiki/GoogleTestPrimer#Assertions" id="fl827" target="_blank"&gt;assertions&lt;/a&gt; for common testing needs, and lets you easily &lt;a href="http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide#Predicate_Assertions" id="fl828" target="_blank"&gt;define new assertions&lt;/a&gt; for less common cases.   &lt;/li&gt;&lt;li id="fl829"&gt;     On Linux, you can write &lt;a href="http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide#Death_Tests" id="fl8210" target="_blank"&gt;death tests&lt;/a&gt; to ensure that your code crashes with expected errors.   &lt;/li&gt;&lt;li id="fl8211"&gt;Because it's based on the popular &lt;a href="http://en.wikipedia.org/wiki/XUnit" id="fl8212" target="_blank"&gt;xUnit&lt;/a&gt; architecture, Google Test is easy to learn if you've used any testing framework in this family before.   &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;It will take you about 10 minutes to learn &lt;a href="http://code.google.com/p/googletest/wiki/GoogleTestPrimer" id="fl8213" target="_blank"&gt;the basics&lt;/a&gt; and get started. Stay tuned to this blog for helpful Google Test information in upcoming Testing on the Toilet episodes.&lt;br /&gt;&lt;br /&gt;Please send questions and feedback to &lt;a title="googletestframework@googlegroups.com" href="mailto:googletestframework@googlegroups.com" id="bx9o"&gt;googletestframework@googlegroups.com&lt;/a&gt; (the &lt;a href="http://groups.google.com/group/googletestframework" id="fl8215" target="_blank"&gt;Google Test Discussion Group&lt;/a&gt;). See you there!&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/blogspot/RLXA?a=QK58hJ"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/RLXA?i=QK58hJ" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/blogspot/RLXA?a=5n0PLj"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/RLXA?i=5n0PLj" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/RLXA/~4/326216948" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/blogspot/RLXA/~3/326216948/announcing-new-google-c-testing.html" title="Announcing: New Google C++ Testing Framework" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=15045980&amp;postID=4596842432845665451" title="9 Comments" /><link rel="replies" type="application/atom+xml" href="http://googletesting.blogspot.com/feeds/4596842432845665451/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default/4596842432845665451" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default/4596842432845665451" /><author><name>niceredfrog</name><uri>http://www.blogger.com/profile/14235034496701411386</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://googletesting.blogspot.com/2008/07/announcing-new-google-c-testing.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-15045980.post-4591414625061290830</id><published>2008-06-26T09:43:00.003-07:00</published><updated>2008-06-26T09:49:10.737-07:00</updated><title type="text">Defeat "Static Cling"</title><content type="html">You're pair programming and, as many brilliant people are apt to do, talking out loud.  "I'll make a mock, inject it, and rerun the test. It should pa- ...D'OH"   Your partner notices the exception &lt;i&gt;"ConnectionFactory not initialized"&lt;/i&gt;.  "What?" she says, "Something is using the database? Dang, and this was supposed to be a small test."&lt;br /&gt;&lt;br /&gt;Upon inspection you find that your class is calling a &lt;b&gt;&lt;font color=#800000&gt;static&lt;/font&gt;&lt;/b&gt; method on some other class.  You've got &lt;b&gt;&lt;font color=#800000&gt;Static Cling&lt;/font&gt;&lt;/b&gt;! If you're (ab)using a data persistence layer that generates code which relies on static methods, &lt;i&gt;and weren't careful&lt;/i&gt;, your code might look something like this:&lt;br /&gt;&lt;br /&gt;&lt;p style="BORDER:1px solid #808080; PADDING:0.1in; BACKGROUND:#e6f5ff none repeat scroll 0% 50%; MARGIN-LEFT:0.39in; MARGIN-RIGHT:0.39in; MARGIN-BOTTOM:0pt"&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;public class MyObject {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;public int doSomething(int id) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return TheirEntity.selectById(id).getSomething();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;As a result, you can't call doSomething without calling &lt;font face="Courier New, monospace"&gt;TheirEntity&lt;/font&gt;'s static method. This code is hard to test because static methods are &lt;b&gt;&lt;font color=#800000&gt;impossible&lt;/font&gt;&lt;/b&gt; to mock in Java.&lt;br /&gt;&lt;br /&gt;So, how do you get rid of this form of Static Cling and get that small test to pass?  You can use a technique sometimes known as the &lt;b&gt;&lt;font color=#800000&gt;Repository Pattern&lt;/font&gt;&lt;/b&gt;, a form of Abstract Factory.  Create an interface and an implementation with the unmockable static method calls:&lt;br /&gt;&lt;br /&gt;&lt;p style="BORDER:1px solid #808080; PADDING:0.1in; BACKGROUND:#e6f5ff none repeat scroll 0% 50%; MARGIN-LEFT:0.39in; MARGIN-RIGHT:0.39in; MARGIN-BOTTOM:0pt"&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;interface TheirEntityRepository {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;TheirEntity selectById(int id);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;// other static methods on TheirEntity can be&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;// represented here too&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;public class TheirEntityStaticRepository&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;implements TheirEntityRepository {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;public TheirEntity selectById(int id) { // non-static&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return TheirEntity.selectById(id);    // calls static method&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;Next, inject a &lt;font face="Courier New, monospace"&gt;TheirEntityRepository&lt;/font&gt; into &lt;font face="Courier New, monospace"&gt;MyObject&lt;/font&gt; and use it instead of calls to the static method:&lt;br /&gt;&lt;br /&gt;&lt;p style="BORDER:1px solid #808080; PADDING:0.1in; BACKGROUND:#e6f5ff none repeat scroll 0% 50%; MARGIN-LEFT:0.39in; MARGIN-RIGHT:0.39in; MARGIN-BOTTOM:0pt"&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;public class MyObject {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;private final TheirEntityRepository repository;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;public MyEntity(TheirEntityRepository arg) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.repository = arg;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;public int doSomething(int id) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return repository.selectById(id).getSomething();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;You can do this even if you don't have access to source code for &lt;font face="Courier New, monospace"&gt;TheirEntity&lt;/font&gt;, since you're not changing the source itself, but merely encapsulating its static methods in an injectable interface.  The techniques shown here generalize to the case where a static method acts as a Factory of objects.&lt;br /&gt;&lt;br /&gt;Now you can inject different implementations of the repository for different tests, such as "never finds anything," "always throws an exception," "only returns a &lt;font face="Courier New, monospace"&gt;TheirEntity&lt;/font&gt; if the id is a prime," and so forth.  These kinds of tests would've been impossible before this refactoring.&lt;br /&gt;&lt;br /&gt;Remember to download &lt;a href="http://code.google.com/testing/TotT-2008-06-26.pdf"&gt;this episode&lt;/a&gt; of Testing on the Toilet and post it in your office.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/blogspot/RLXA?a=rSbGgI"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/RLXA?i=rSbGgI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/blogspot/RLXA?a=9M71bi"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/RLXA?i=9M71bi" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/RLXA/~4/320652945" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/blogspot/RLXA/~3/320652945/defeat-static-cling.html" title="Defeat &quot;Static Cling&quot;" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=15045980&amp;postID=4591414625061290830" title="3 Comments" /><link rel="replies" type="application/atom+xml" href="http://googletesting.blogspot.com/feeds/4591414625061290830/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default/4591414625061290830" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default/4591414625061290830" /><author><name>dastels</name><uri>http://www.blogger.com/profile/07735664941682371671</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://googletesting.blogspot.com/2008/06/defeat-static-cling.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-15045980.post-1564984214103146003</id><published>2008-06-24T13:40:00.000-07:00</published><updated>2008-06-24T13:49:05.028-07:00</updated><title type="text">Test Engineering Class Project at UC-Irivine</title><content type="html">&lt;span class="byline-author"&gt;&lt;/span&gt;&lt;span id="egxw"  style="font-size:100%;"&gt;Posted by George Pirocanac, Test Engineering Manager&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;For the past nine months it has been my pleasure to work with a group of undergrad students from UC-Irvine as part of their senior class project. The course was run by professor Hadar Ziv and teaching assistant Sameer Patil. It focused on providing students industry experience by working with customers (in this case us) to formulate product requirements and deliver working software. Jason Robbins from the Google Irvine office was the lead for another project and several other local companies also participated.&lt;br /&gt;&lt;br /&gt;Our team members included Michelle Alvaraz, Jason Dramby, Peter Lee and Gabriela Marcu. It was the only project dealing directly with test engineering and one of our goals was specifically to create a plan and framework for testing the Google Mashup Editor (GME) tag language.&lt;br /&gt;&lt;br /&gt;For those unfamiliar with the GME, it is a framework for developing simple web applications and mashups using a custom set of XML tags, Javascript, CSS and HTML. More information about the GME can be found &lt;a title="GME documentation" target="_blank" href="http://code.google.com/gme/" id="mh2."&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The first three months of the class were spent learning about the the GME and performing exploratory testing. The team became very familiar with the editor and created several mashups (You can try one of them &lt;a title="sample mashup" target="_blank" href="http://digikitchen2.googlemashups.com/" id="ytlv"&gt;here.&lt;/a&gt;). They also created a traditional test plan which focused on testing the tag language. Later they executed this test plan by compiling and running their sample mashups on a variety of browsers.&lt;br /&gt;&lt;br /&gt;After a couple of iterations of this test plan they quickly encountered some of the typical challenges associated with the traditional approach - namely human resource oversubscription in test execution and insufficient coverage.&lt;br /&gt;&lt;br /&gt;We addressed with the first issue through automation and the team learned to automate their manual tests of the mashups with &lt;a title="Selenium" target="_blank" href="http://www.openqa.org/selenium/" id="e9ra"&gt;Selenium&lt;/a&gt;. They first used Selenium IDE to learn the basic Selenium commands and concepts such as locators. Afterwards they used the "Export Test As..." feature in IDE to create Python tests that would be run under a local server with Selenium-RC. The latter got them to a point where they could execute the existing test plan&lt;br /&gt;automatically on three different platforms (Windows, Linux, MacOS).&lt;br /&gt;&lt;br /&gt;Expanding coverage was less straightforward. The traditional approach would be to use the existing resources to write more tests. We, however, decided to create a framework that would itself generate more tests. This dovetailed nicely with the classroom material which was product-centric and focused on gathering customer requirements, creating a design document and delivering the software. In our case, the group's product was to be a &lt;i id="da2_"&gt;GME Test Suite Creator&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;As a starting point we looked at the following simple Python script which creates a simple cross product on lists of strings:&lt;span id="x3ry" style="font-family: Courier New;"&gt;&lt;br /&gt;&lt;br /&gt;#!/usr/bin/python&lt;/span&gt;&lt;span id="x3ry0" style="font-family: Courier New;"&gt;&lt;br /&gt;&lt;br /&gt;def cross(args):&lt;/span&gt;&lt;span id="x3ry1" style="font-family: Courier New;"&gt;&lt;br /&gt;  ans = [[]]&lt;/span&gt;&lt;span id="x3ry2" style="font-family: Courier New;"&gt;&lt;br /&gt;  for arg in args:&lt;/span&gt;&lt;span id="x3ry3" style="font-family: Courier New;"&gt;&lt;br /&gt;     ans = [x+[y] for x in ans for y in arg]&lt;/span&gt;&lt;span id="x3ry4" style="font-family: Courier New;"&gt;&lt;br /&gt;  return ans&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span id="x3ry5" style="font-family: Courier New;"&gt;def pprint(lists):&lt;/span&gt;&lt;span id="x3ry6" style="font-family: Courier New;"&gt;&lt;br /&gt;  for list in lists:&lt;/span&gt;&lt;span id="x3ry7" style="font-family: Courier New;"&gt;&lt;br /&gt;    a = ''&lt;/span&gt;&lt;span id="x3ry8" style="font-family: Courier New;"&gt;&lt;br /&gt;    for s in list:&lt;/span&gt;&lt;span id="x3ry9" style="font-family: Courier New;"&gt;&lt;br /&gt;       a = a + s&lt;/span&gt;&lt;span id="x3ry10" style="font-family: Courier New;"&gt;&lt;br /&gt;    print a&lt;/span&gt;&lt;span id="x3ry12" style="font-family: Courier New;"&gt;&lt;br /&gt;&lt;br /&gt;tags = [ ['&lt;'],&lt;/span&gt;&lt;span id="x3ry14" style="font-family: Courier New;"&gt;&lt;br /&gt;         ['gm:page '],&lt;/span&gt;&lt;span id="x3ry16" style="font-family: Courier New;"&gt;&lt;br /&gt;         ['', 'authenticate=true', 'authenticate=false',&lt;br /&gt;          'authenticate=invalid'],&lt;/span&gt;&lt;span id="x3ry18" style="font-family: Courier New;"&gt;&lt;br /&gt;       ['/&gt;'] ]&lt;/span&gt;&lt;span id="x3ry21" style="font-family: Courier New;"&gt;&lt;br /&gt; &lt;br /&gt;lists = cross(tags)&lt;/span&gt;&lt;span id="x3ry23" style="font-family: Courier New;"&gt;&lt;br /&gt;pprint(lists)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Running the script yields the following combination of tags:&lt;span id="gqx9" style="font-family: Courier New;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&amp;lt; &lt;span id="gqx9" style="font-family: Courier New;"&gt;gm:page /&lt;/span&gt;&amp;gt;&lt;span id="gqx90" style="font-family: Courier New;"&gt;&lt;br /&gt;&lt;/span&gt;&amp;lt; &lt;span id="gqx9" style="font-family: Courier New;"&gt;&lt;/span&gt;&lt;span id="gqx90" style="font-family: Courier New;"&gt;gm:page authenticate=true&lt;/span&gt;&lt;span id="gqx9" style="font-family: Courier New;"&gt;/&lt;/span&gt;&amp;gt;&lt;span id="gqx90" style="font-family: Courier New;"&gt;&lt;/span&gt;&lt;span id="gqx91" style="font-family: Courier New;"&gt;&lt;br /&gt;&lt;/span&gt;&amp;lt; &lt;span id="gqx9" style="font-family: Courier New;"&gt;&lt;/span&gt;&lt;span id="gqx91" style="font-family: Courier New;"&gt;gm:page authenticate=false&lt;/span&gt;&lt;span id="gqx9" style="font-family: Courier New;"&gt;/&lt;/span&gt;&amp;gt;&lt;span id="gqx90" style="font-family: Courier New;"&gt;&lt;/span&gt;&lt;span id="gqx92" style="font-family: Courier New;"&gt;&lt;br /&gt;&lt;/span&gt;&amp;lt; &lt;span id="gqx92" style="font-family: Courier New;"&gt;gm:page authenticate=invalid&lt;/span&gt;&lt;span id="gqx9" style="font-family: Courier New;"&gt;/&lt;/span&gt;&amp;gt;&lt;span id="gqx90" style="font-family: Courier New;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Each one could be used in a mashup that used the page tag. Likewise, the other tags from the GME tag language could be expanded with various combinations of valid and invalid attributes. These tag combinations could then be individually inserted into &lt;i id="sz8:"&gt;skeleton&lt;/i&gt; mashups producing a large number of both positive and negative tests which would be performed under Selenium-RC.&lt;br /&gt;&lt;br /&gt;This was the basic idea of the &lt;i id="bebb"&gt;GME Test Suite Creator&lt;/i&gt; and the team implemented a GUI to facilitate the three steps in creating and running a testsuite:&lt;br /&gt;&lt;br /&gt;&lt;div id="bulp0" style="margin-left: 40px;"&gt;&lt;ul id="fg1-"&gt;&lt;li id="fg1-0"&gt;Code Generation - The selection of tags and creation of tests.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div id="fg1-1" style="margin-left: 40px;"&gt;&lt;ul id="fg1-2"&gt;&lt;li id="fg1-3"&gt;Code Preview - The examination and execution of created tests&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div id="fg1-4" style="margin-left: 40px;"&gt;&lt;ul id="fg1-5"&gt;&lt;li id="fg1-6"&gt;Test Reporting - The examination of test results.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;br /&gt;The figure below shows the Code Generation tab of the &lt;i id="vto8"&gt;GME Test Suite Creator.&lt;/i&gt; It displays a hierarchical view of the tabs and allows the user to select which tags to include in the sample tests. The sample test is generated from a &lt;i id="yr4r"&gt;skeleton &lt;/i&gt;test modeled after the documentation example scraped from the code.google.com website. This was a nice idea which added testing of the documentation to the process.&lt;br /&gt;&lt;br /&gt;&lt;div id="p_9m" style="padding: 1em 0pt; text-align: left;"&gt;&lt;img id="w.qq" style="width: 613px; height: 465px;" src="https://docs.google.com/a/google.com/File?id=chbtmb2v_60hrsvk3gc_b" /&gt;&lt;/div&gt;An interesting problem that these types of automatic test generation frameworks can encounter is the combinatorial explosion of generated tests. For example, if each tag attribute can have 8 possible values and a sample mashup contains 10 tags, enumerating each combination would take roughly 1 billion (8&lt;sup id="aip2"&gt;10&lt;/sup&gt; = 2&lt;sup id="aip20"&gt;30&lt;/sup&gt;) tests! To address this, the team created an Options dialog box that would allow the user to specify different test suite sizes in addition to the test suite name and type. A further refinement, allowing the user to select which set of specific values to use for tag attributes would have been implemented if the team had more time.&lt;br /&gt;&lt;div id="i8gb" style="padding: 1em 0pt; text-align: left;"&gt;&lt;img id="mip9" style="width: 192px; height: 264px;" src="https://docs.google.com/a/google.com/File?id=chbtmb2v_64wtg679fs_b" /&gt;&lt;/div&gt;&lt;br /&gt;The next figure shows the Code Preview tab of the &lt;i id="kck1"&gt;GME Test Suite Creator. &lt;/i&gt;It shows the list of tests created under a given test suite and allows the user to manage and execute the test suite.&lt;br /&gt;&lt;div id="errr" style="padding: 1em 0pt; text-align: left;"&gt;&lt;img id="tr1h" style="width: 574px; height: 439px;" src="https://docs.google.com/a/google.com/File?id=chbtmb2v_65fswffchr_b" /&gt;&lt;/div&gt;&lt;br /&gt;Finally, the Test Report Tab shows the results of the tests executed under Selenium-RC.&lt;br /&gt;&lt;br /&gt;&lt;div id="taso" style="padding: 1em 0pt; text-align: left;"&gt;&lt;img id="hupi" style="width: 611px; height: 469px;" src="https://docs.google.com/a/google.com/File?id=chbtmb2v_62czwfhgc2_b" /&gt;&lt;/div&gt;&lt;i id="zwf_"&gt;GME Test Suite Creator &lt;/i&gt;was itself written in Python and hosted on Windows, Linux and MacOS.&lt;br /&gt;The team presented and demonstrated the &lt;i id="zwf_0"&gt;GME Test Suite Creator&lt;/i&gt; to faculty and other student/industry teams as part of the UC-Irvine ICS Student Show Case. Over the next few weeks I will be kicking the tires and evaluating the battle worthiness of the &lt;i id="z.p1"&gt;GME Test Suite Creator&lt;/i&gt; delivery which included source code and a complete set of documentation.&lt;br /&gt;&lt;br /&gt;I certainly had a wonderful time interacting with the team and participating in this program!&lt;br /&gt;&lt;br /&gt;&lt;div id="ubqj" style="padding: 1em 0pt; text-align: left;"&gt;&lt;img id="x:l6" style="width: 432px; height: 290px;" src="https://docs.google.com/a/google.com/File?id=chbtmb2v_63crvhfvcq_b" /&gt;&lt;/div&gt;The GME Test Suite Creator Team (from left to right: Gabriela Marcu, Peter Lee, &lt;br /&gt;Michelle Alvarez, Jason Dramby and George Pirocanac)&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/blogspot/RLXA?a=mnzsZI"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/RLXA?i=mnzsZI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/blogspot/RLXA?a=6NSnbi"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/RLXA?i=6NSnbi" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/RLXA/~4/319171001" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/blogspot/RLXA/~3/319171001/test-engineering-class-project-at-uc.html" title="Test Engineering Class Project at UC-Irivine" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=15045980&amp;postID=1564984214103146003" title="3 Comments" /><link rel="replies" type="application/atom+xml" href="http://googletesting.blogspot.com/feeds/1564984214103146003/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default/1564984214103146003" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default/1564984214103146003" /><author><name>Patrick Copeland</name><uri>http://www.blogger.com/profile/02362734812961509270</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://googletesting.blogspot.com/2008/06/test-engineering-class-project-at-uc.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-15045980.post-660789245724190864</id><published>2008-06-21T18:18:00.000-07:00</published><updated>2008-06-21T22:01:45.850-07:00</updated><title type="text">Productivity Games – Using Games to Improve Quality</title><content type="html">Editor's note (Pat Copeland, Engineering Productivity Director, Google): On occasion we ask a special guest to post on an interesting topic. Ross has some really interesting ideas about how to use games to influence behavior. I'm a big fan. Enjoy!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Ross Smith, Director of Test, Microsoft Windows Core Security&lt;br /&gt;&lt;i&gt;&lt;br /&gt;“Quality takes you out of yourself, makes you aware of the world around you.” [1]&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;p class="MsoNormal"&gt;The “Gamer Generation” is here. &lt;span style="font-size:0;"&gt;&lt;/span&gt;According to the &lt;a href="http://www.washingtonpost.com/wp-dyn/content/article/2006/05/07/AR2006050700172.html"&gt;Washington Post&lt;/a&gt;, in 2006 at least 40% of Americans play video games on a computer or a console. The largest demographic is 18-34 year-&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;olds&lt;/span&gt;, many of whom are working as our friends and peers as software developers and testers. &lt;span style="font-size:0;"&gt;&lt;/span&gt;There is a great book, &lt;a href="http://books.google.com/books?id=uxz6UU_AW3cC"&gt;Got Game&lt;/a&gt;, which describes the impact of games on the workforce of today and in the future.&lt;/p&gt;&lt;p class="MsoNormal"&gt;Many businesses are wondering these days how to use simple concepts popular in video games and apply them to work.&lt;/p&gt;&lt;p class="MsoNormal"&gt;It’s happening already. From a construction site with a sign posted with “days since last accident” to the car dealer with &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;salespersons&lt;/span&gt; leader board scrawled out in chalk. Simple competition helps work get done in all kinds of industries. The success of sales contests is a great example of how well competition works.&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;i&gt;“In every job that must be done, there is an element of fun. You find the fun and—SNAP—the job’s a game!” —Mary Poppins&lt;/i&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;A company called &lt;a href="http://www.seriosity.com/products.html"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;Seriosity&lt;/span&gt;&lt;/a&gt; has made interesting use of video game concepts at work with their application of virtual currency to email. To help with information overload from an overflowing inbox, email senders can “spend” virtual currency (&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;Serios&lt;/span&gt;) to help prioritize their messages. Spending to denote the importance of a message is not a whole lot different than buying new golf clubs with virtual money earned in a Tiger Woods game, buying new tires in a car racing game – or using gamer points to upgrade your armor in an &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;RPG&lt;/span&gt; (Role-playing Game). Wired Magazine had a &lt;a href="http://www.wired.com/wired/archive/14.04/learn.html"&gt;great article&lt;/a&gt; on the use of WOW as a leadership training game. Playing games at work is more than just a quick game of online Hearts with one finger on the “&lt;a href="http://en.wikipedia.org/wiki/Boss_key"&gt;boss key&lt;/a&gt;”. Games at work can have real impact.&lt;/p&gt;&lt;p class="MsoNormal"&gt;With other industries using productivity games, what about software development?&lt;span style="font-size:0;"&gt; &lt;/span&gt;How can productivity games help testers improve the quality of the products they test?&lt;span style="font-size:0;"&gt; &lt;/span&gt;One of the more famous test techniques is the bug bash. Teams pick a certain date, and everyone bangs on a certain area of the product to find bugs. At the end, prizes are awarded while everyone enjoys pizza and drinks. That sounds a lot like game, doesn't it?&lt;span style="font-size:0;"&gt; &lt;/span&gt;It’s also a perfect example of a simple productivity game.&lt;/p&gt;&lt;p class="MsoNormal"&gt;As the world of software gets more complex and the test matrix grows, there is no shortage of opportunities for testers to do more testing. Quality is always “improved”, it’s never completed, fixed or finished. Therefore, testers must choose from a variety of techniques and activities to pursue tasks with the highest return and value. In 1990, &lt;a href="http://nobelprize.org/nobel_prizes/economics/laureates/1990/index.html"&gt;Harry &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;Markowitz&lt;/span&gt;&lt;/a&gt; won the Nobel Prize for his work on &lt;a href="http://cowles.econ.yale.edu/P/cm/m16/m16-all.pdf"&gt;Portfolio Selection&lt;/a&gt; (that he began in the 1950’s). The theory, familiar in financial markets and mutual funds, is that a portfolio of diverse assets with varying risk and returns actually reduces risk in time uncertain conditions. Testers can benefit from the work on portfolio selection by varying the techniques they use to find defects. However, some techniques are more expensive, more difficult, or less attractive than others. Some teams, in some situations, can rely on the altruism and volunteer efforts – &lt;a href="http://en.wikipedia.org/wiki/Organizational_citizenship_behavior"&gt;organizational citizenship behaviors&lt;/a&gt; – of their members to take on the more difficult tasks. However, that doesn't always work, and other incentives may be required. That’s where productivity games can help.&lt;/p&gt;&lt;p class="MsoNormal"&gt;When a project needs a bit of a push towards a certain behavior, building a game around it can help.&lt;span style="font-size:0;"&gt; &lt;/span&gt;For example, if a test team wants to improve the usage of unit tests by developers, encourage the team to “&lt;a href="http://en.wikipedia.org/wiki/Eating_one"&gt;eat their own &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;dogfood&lt;/span&gt;&lt;/a&gt;” or run automated tests on personal machines overnight, then creating a game will help people’s motivation can motivate people to participate in those activities. &lt;/p&gt;&lt;p class="MsoNormal"&gt;Productivity games differ from traditional games in a few distinct ways. The goal of a productivity game is to attract players. &lt;b&gt;These games don’t need winners as much as they need players. &lt;/b&gt;In many cases, productivity games don’t even need prizes. Productivity games can be simple. There’s no need to invest in expensive graphics or 3-D modeling – people play the game to compete around a work activity, not because of the appeal of the user interface. A simple leader board might be all that’s needed. &lt;/p&gt;&lt;p class="MsoNormal"&gt;Using games at work is a powerful and effective method to influence change in organizational behavior, and therefore requires care in the design and use. It is possible to overdo the use of games to a point where they are counter-productive or ineffective. Successful game design is best achieved through experience and experimentation, and the goal should be to keep things interesting enough to always attract players. A game where one player leaps out to an insurmountable lead is not effective, because that will discourage others from playing. When a team wants to encourage testers to invest in fault injection techniques, setting up a leader board with bug totals found via fault injection techniques will attract attention of other testers, often just by word-of-mouth. You should encourage team-wide competition, smack talk, and public embarrassment as a means to draw attention. Games should be short in duration.&lt;span style="font-size:0;"&gt; &lt;/span&gt;Many testers remember the Dilbert “I’m gonna write me a new minivan” from 11/13/95. This is what results from a poorly designed productivity game.&lt;/p&gt;&lt;p class="MsoNormal"&gt;Productivity games are great at motivating people to do things and change behavior. And as Uncle Ben said to &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;Spiderman&lt;/span&gt;, “With great power comes great responsibility”. It’s critical to have specific goals for the games, and to understand the impact before deploying a game – it’s pretty likely that people will play, at least initially, and the impact may not be what you intended. Keep the duration of games short in order to be able to adjust. And finally, keep the games focused on volunteer or “extra” activities. A game designed around an individual’s job or portions of everyone’s regular job can introduce unusual feelings when it comes to rewards and performance evaluation. It’s easier to steer clear of that than to try to figure out the right balance.&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;Shigeru&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;Miyamoto&lt;/span&gt;, who designed Super Mario Bros., talks about games as “miniature gardens”, metaphorically representing the cultural values, humanity, and challenges of everyday life the way a miniature garden might represent a real one. &lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;i&gt;The whole idea, for me, is about the exploration of a &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;hakoniwa&lt;/span&gt;, a miniature garden. It's like a garden in a box, where if you look at it from different angles, you can see different plants and arrangements. And you have that sense of surprise and exploration. There's always things you can find. &lt;/i&gt;[2]&lt;br /&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;Games are a lot like testing.&lt;span style="font-size:0;"&gt; &lt;/span&gt;Software quality assurance and testing efforts represent a proxy for real users in much the same way that games are a proxy for the real world. The challenges that Mario faces with fire-breathing dragons and knife throwing turtles are balanced by the allure of coins and princesses.&lt;span style="font-size:0;"&gt; &lt;/span&gt;A testing organization has a good idea of the tools available in their portfolio to improve quality and eliminate those “fire-breathing dragons” for their customers. Productivity games allow teams to offer coins and position rewards around their equivalents of &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;Markowitz&lt;/span&gt;’s “diverse assets” at their disposal, in the form of defect detection and removal techniques, to improve quality. &lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span style="font-size:0;"&gt;&lt;/span&gt;For the players, productivity games offer people the ability to learn, solve problems, and earn a reward. They offer a way to challenge players to compete, to explore and discover, and to establish a surrogate identity or status via a leader board. There are many fundamental motivations to play a game. “&lt;i&gt;If you build it, they will come [3]." &lt;/i&gt;A good productivity game designer can build a game around “work that needs to be done that no one wants to do” – and like the lone teenager who plays Halo for weeks on end, people will take on that work. Experiment and explore – the results can be surprising.&lt;/p&gt;&lt;p class="MsoNormal"&gt;I’d be interested in any &lt;a href="mailto:rosss@defectprevention.org?subject=Comments%20on%20Productivity%20Games"&gt;comments about Productivity Games&lt;/a&gt; that you might have.&lt;/p&gt;&lt;p class="MsoNormal" style="MARGIN-BOTTOM: 0pt"&gt;Thanks,&lt;/p&gt;&lt;p class="MsoNormal" style="MARGIN-BOTTOM: 0pt"&gt;Ross Smith&lt;/p&gt;&lt;p class="MsoNormal" style="MARGIN-BOTTOM: 0pt"&gt;&lt;a href="http://www.defectprevention.org/"&gt;http://www.defectprevention.org/&lt;/a&gt; &lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;b&gt;&lt;?xml:namespace prefix = o /&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/b&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;b&gt;Interesting Links: &lt;span style="TEXT-DECORATION: underline"&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://news.bbc.co.uk/2/hi/technology/7030234.stm" target="_blank"&gt;&lt;span style="font-family:Calibri;font-size:100%;color:#0000ff;"&gt;&lt;u&gt;When Work becomes a Game&lt;/u&gt;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://seriousgames.org/index2.html" target="_blank"&gt;&lt;span style="font-family:Calibri;font-size:100%;color:#0000ff;"&gt;&lt;u&gt;Serious Games Initiative&lt;/u&gt;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.e-learningguru.com/books/gotgame.pdf" target="_blank"&gt;&lt;span style="font-family:Calibri;font-size:100%;color:#0000ff;"&gt;&lt;u&gt;Got Game - How the Gamer Generation is Reshaping Business Forever&lt;/u&gt;&lt;/span&gt;&lt;/a&gt;&lt;span style="font-family:Calibri;font-size:100%;"&gt; &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.defectprevention.org/book.aspx" target="_blank"&gt;&lt;span style="font-family:Calibri;font-size:100%;color:#0000ff;"&gt;&lt;u&gt;Chapter 5 – Productivity Games - The Practical Guide to Defect Prevention&lt;/u&gt;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.defectprevention.org/downloads/bug+hunter.pdf" target="_blank"&gt;&lt;span style="font-family:Calibri;font-size:100%;color:#0000ff;"&gt;&lt;u&gt;2008 Serious Games Summit presentation&lt;/u&gt;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.gamasutra.com/education/theses/20030901/gingold_01.shtml" target="_blank"&gt;&lt;span style="font-family:Calibri;font-size:100%;color:#0000ff;"&gt;&lt;u&gt;Miniature Gardens and Magic Crayons: Games, Spaces, &amp;amp; Worlds&lt;/u&gt;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://harvardbusinessonline.hbsp.harvard.edu/hbsp/hbr/articles/article.jsp?ml_subscriber=true&amp;amp;ml_action=get-article&amp;amp;&amp;amp;articleID=R0805C&amp;amp;pageNumber=1" target="_blank"&gt;&lt;span style="font-family:Calibri;font-size:100%;color:#0000ff;"&gt;&lt;u&gt;HBR Leadership’s Online Labs&lt;/u&gt;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.npr.org/templates/story/story.php?storyId=91573868" target="_blank"&gt;&lt;span style="font-family:Calibri;font-size:100%;color:#0000ff;"&gt;&lt;u&gt;NPR: Software lets users assign value to email&lt;/u&gt;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.edery.org/" target="_blank"&gt;&lt;span style="font-family:Calibri;font-size:100%;color:#0000ff;"&gt;&lt;u&gt;Game Tycoon blog&lt;/u&gt;&lt;/span&gt;&lt;/a&gt;&lt;span style="font-family:Calibri;font-size:100%;"&gt; (How Video Games are transforming the Business World) &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://productivitygames.blogspot.com/" target="_blank"&gt;&lt;span style="font-family:Calibri;font-size:100%;color:#0000ff;"&gt;&lt;u&gt;Productivity Games Blog&lt;/u&gt;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;a href="http://www.levityeffect.com/" target="_blank"&gt;&lt;span style="font-family:Calibri;font-size:100%;color:#0000ff;"&gt;&lt;u&gt;The Levity Effect&lt;/u&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;p class="MsoNormal"&gt;&lt;b&gt;&lt;span style="TEXT-DECORATION: underline"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="LINE-HEIGHT: 115%;font-size:85%;" &gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span style="LINE-HEIGHT: 115%;font-size:85%;" &gt;Special thanks to Joshua Williams for his help with this post.&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;hr align="left" width="33%"  style="font-size:78;"&gt;&lt;br /&gt;&lt;div id="edn1"&gt;&lt;p class="MsoEndnoteText"&gt;[1] Robert &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;Pirsig&lt;/span&gt;, Zen and the Art of Motorcycle Maintenance&lt;br /&gt;[2] Wired Magazine Interview &lt;a title="" href="http://www.blogger.com/post-create.g?blogID=15045980#_ednref3" name="_edn3"&gt;http://blog.wired.com/games/2007/12/interview-super.html&lt;br /&gt;&lt;/a&gt;[3] Field of Dreams, 1989&lt;/p&gt;&lt;/div&gt;&lt;div id="edn2"&gt;&lt;/div&gt;&lt;div id="edn3"&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/blogspot/RLXA?a=ZwDKAI"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/RLXA?i=ZwDKAI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/blogspot/RLXA?a=mirxii"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/RLXA?i=mirxii" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/RLXA/~4/317179055" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/blogspot/RLXA/~3/317179055/productivity-games-using-games-to.html" title="Productivity Games – Using Games to Improve Quality" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=15045980&amp;postID=660789245724190864" title="2 Comments" /><link rel="replies" type="application/atom+xml" href="http://googletesting.blogspot.com/feeds/660789245724190864/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default/660789245724190864" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default/660789245724190864" /><author><name>Patrick Copeland</name><uri>http://www.blogger.com/profile/02362734812961509270</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://googletesting.blogspot.com/2008/06/productivity-games-using-games-to.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-15045980.post-2632154988414933193</id><published>2008-06-13T21:55:00.000-07:00</published><updated>2008-06-13T22:00:00.417-07:00</updated><title type="text">Taming the Beast (a.k.a. how to test AJAX applications) : Part 1</title><content type="html">Posted by Markus Clermont, John Thomas          &lt;br /&gt;&lt;br /&gt;This is the first in a two part blog series titled 'Taming the Beast: How to test AJAX applications". In this part we discuss some philosophies around web application testing and how it should be done the 'right' way. In part 2, we walk through a real example of designing a test strategy for an AJAX application by going 'beyond the GUI.'&lt;br /&gt;&lt;br /&gt;&lt;b id="v8mx1"&gt;Background&lt;br /&gt;&lt;/b&gt;Typically we address the problem of testing an AJAX application through a plethora of big end-to-end tests and (hopefully) high unit-test coverage. Here we outline the main problems with this approach and demonstrate an effective testing strategy for a sample GWT-based application which goes beyond "testing just through the GUI."&lt;br /&gt;&lt;br /&gt;&lt;b id="ho:b"&gt;Problems with GUI-only testing&lt;/b&gt;&lt;br /&gt;&lt;div id="ji6d"&gt;In general testing through the GUI:&lt;br /&gt;&lt;ul id="hyz_1"&gt;&lt;li id="hyz_2"&gt;is expensive (takes long to write the tests and execution is resource-intensive)&lt;br /&gt;&lt;/li&gt;&lt;li id="hyz_3"&gt;gives limited insight into the system&lt;/li&gt;&lt;li id="hyz_4"&gt;often take only the 'happy paths' into account&lt;/li&gt;&lt;li id="hyz_5"&gt;combines multiple aspects in a single test&lt;br /&gt;&lt;/li&gt;&lt;li id="hyz_7"&gt;is slow and brittle&lt;/li&gt;&lt;li id="hyz_7"&gt;needs a lot of maintenance&lt;br /&gt;&lt;/li&gt;&lt;li id="hyz_7"&gt;is hard to debug&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;And while unit tests don't suffer from many of these problems, they alone are not sufficient mainly because they:&lt;br /&gt;&lt;ul id="ji6d2"&gt;&lt;li id="ji6d3"&gt;give little insight how the components interact with each other&lt;/li&gt;&lt;li id="ji6d4"&gt;don't give confidence that the business logic and functionality of the system meets the requirements&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;br /&gt;&lt;b id="xup3"&gt;Solution&lt;/b&gt;&lt;br /&gt;Although there is no 'one size fits all' solution, there are some basic principles we can use to solve the testing problem for web applications:&lt;br /&gt;&lt;div id="weg5"  style="font-size:0.9em;"&gt;&lt;ul id="j9-b"&gt;&lt;li id="j9-b2"&gt;&lt;span id="j9-b3"  style="font-size:100%;"&gt;Invest in integration tests (identify the smallest sub-system)&lt;/span&gt;&lt;/li&gt;&lt;li id="j9-b6"&gt;&lt;span id="j9-b7"  style="font-size:100%;"&gt;Separation of Concerns (don't do the set-up through the interface you are testing)&lt;/span&gt;&lt;/li&gt;&lt;li id="j9-b10"&gt;&lt;span id="j9-b11"  style="font-size:100%;"&gt;Test each interface separately (mock out everything that you are not testing)&lt;/span&gt;&lt;/li&gt;&lt;li id="j9-b14"&gt;&lt;span id="j9-b15"  style="font-size:100%;"&gt;Consider dependencies in production (figure out how dependencies can fail, and test that)&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li id="j9-b18"&gt;&lt;span id="j9-b19"  style="font-size:100%;"&gt;Use a mix of strategies and tools. There is no silver bullet.&lt;/span&gt;&lt;/li&gt;&lt;li id="j9-b20"&gt;&lt;span id="j9-b21"  style="font-size:100%;"&gt;&lt;b id="weg518"&gt;And no... you cannot scrap all of your end-to-end tests&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;br /&gt;&lt;b id="xup3"&gt;A recipe for testing goodness&lt;/b&gt;&lt;br /&gt;Using the principles above we can build up a recipe for testing web applications. In the second part of our blog we will walk through each of these steps for a real web application.&lt;br /&gt;&lt;ol id="i1ex1"&gt;&lt;li id="i1ex2"&gt;Explore the system's functionality&lt;/li&gt;&lt;li id="i1ex3"&gt;Identify the system's architecture&lt;/li&gt;&lt;li id="i1ex4"&gt;Identify the interfaces between components&lt;/li&gt;&lt;li id="i1ex4"&gt;Identify dependencies and fault conditions&lt;/li&gt;&lt;li id="i1ex4"&gt;For each function:&lt;/li&gt;&lt;/ol&gt;&lt;ul style="margin-left: 40px;"&gt;&lt;li&gt;Identify the participating components&lt;/li&gt;&lt;li&gt;Identify potential problems&lt;/li&gt;&lt;li&gt;Test in isolation for problems&lt;/li&gt;&lt;li&gt;Create a 'happy path' test&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b id="ikfc"&gt;End note: value of a test&lt;/b&gt;&lt;br /&gt;A question commonly asked by developers when writing tests is, "is this really worth my time?" The short answer is "always!". Since fixing a bug is way more expensive than preventing it in the first place, writing good tests is always worth the time.&lt;br /&gt;&lt;br /&gt;While there are many different classifications of tests, the most common way of classifying them is based on their size and the areas of a product they test. Each test answers specific questions about the product:&lt;br /&gt;&lt;ul id="ge75"&gt;&lt;li id="ge750"&gt;Unit test: is the method fulfilling its contract?&lt;/li&gt;&lt;li id="ge751"&gt;Small integration test: Can two classes interact with each other?&lt;/li&gt;&lt;li id="ge752"&gt; Medium integration test: Is a class interacting properly with all its dependencies? Does it anticipate and handle errors correctly? Are the needed functions exposed on an API/GUI?&lt;/li&gt;&lt;li id="ge752"&gt; Sub-system test: Can two sub-systems interact with each other? Does one of them anticipate all errors of the other and does it deal with them appropriately?&lt;br /&gt;&lt;/li&gt;&lt;li id="ge752"&gt;System test: Does the entire system behave as expected?&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Keeping this questions in mind, testing at various levels allows us to write more focused and meaningful tests. Remember that effective tests are those that provide quick &lt;i id="m.5_"&gt;and&lt;/i&gt; useful feedback, i.e. quickly identify issues and pin point the exact location of the issue.&lt;br /&gt;&lt;br /&gt;In the next episode we will walk through the recipe proposed above using a real web application.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/blogspot/RLXA?a=tPTL6I"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/RLXA?i=tPTL6I" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/blogspot/RLXA?a=VpUUii"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/RLXA?i=VpUUii" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/RLXA/~4/311617447" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/blogspot/RLXA/~3/311617447/taming-beast-aka-how-to-test-ajax.html" title="Taming the Beast (a.k.a. how to test AJAX applications) : Part 1" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=15045980&amp;postID=2632154988414933193" title="5 Comments" /><link rel="replies" type="application/atom+xml" href="http://googletesting.blogspot.com/feeds/2632154988414933193/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default/2632154988414933193" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default/2632154988414933193" /><author><name>Patrick Copeland</name><uri>http://www.blogger.com/profile/02362734812961509270</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://googletesting.blogspot.com/2008/06/taming-beast-aka-how-to-test-ajax.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-15045980.post-7184144255017647866</id><published>2008-06-12T09:51:00.000-07:00</published><updated>2008-06-12T10:07:21.836-07:00</updated><title type="text">TotT: Friends You Can Depend On</title><content type="html">&lt;p&gt;When you want to test code that depends on something that is too difficult or slow to use in a test environment, swap in a test double for the dependency.&lt;br /&gt;A Dummy passes bogus input values around to satisfy an API.&lt;/p&gt;&lt;br /&gt;&lt;p style="BORDER:1px solid #808080; PADDING:0.1in; BACKGROUND:#e6f5ff none repeat scroll 0% 50%; MARGIN-LEFT:0.39in; MARGIN-RIGHT:0.39in; MARGIN-BOTTOM:0pt"&gt;&lt;span style=" ;font-family:courier new, monospace;font-size:100%;"&gt;Item item = new Item(ITEM_NAME);&lt;/span&gt;&lt;br /&gt;&lt;span style=" ;font-family:courier new, monospace;font-size:100%;"&gt;ShoppingCart cart = new ShoppingCart();&lt;/span&gt;&lt;br /&gt;&lt;span style=" ;font-family:courier new, monospace;font-size:100%;"&gt;cart.add(item, QUANTITY);&lt;/span&gt;&lt;br /&gt;&lt;span style=" ;font-family:courier new, monospace;font-size:100%;"&gt;assertEquals(QUANTITY, cart.getItem(ITEM_NAME));  &lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;A Stub overrides the real object and returns hard-coded values. Testing with stubs only is state-based testing; you exercise the system and then assert that the system is in an expected state.  &lt;/p&gt;&lt;br /&gt;&lt;p style="BORDER:1px solid #808080; PADDING:0.1in; BACKGROUND:#e6f5ff none repeat scroll 0% 50%; MARGIN-LEFT:0.39in; MARGIN-RIGHT:0.39in; MARGIN-BOTTOM:0pt"&gt;&lt;span style=" ;font-family:courier new, monospace;font-size:100%;"&gt;ItemPricer pricer = new ItemPricer() { &lt;br /&gt;&lt;span style=" ;font-family:courier new, monospace;font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;public BigDecimal getPrice(String name){ return PRICE; }&lt;/span&gt;&lt;br /&gt;&lt;span style=" ;font-family:courier new, monospace;font-size:100%;"&gt;};&lt;/span&gt;&lt;br /&gt;&lt;span style=" ;font-family:courier new, monospace;font-size:100%;"&gt;ShoppingCart cart = new ShoppingCart(pricer);&lt;/span&gt;&lt;br /&gt;&lt;span style=" ;font-family:courier new, monospace;font-size:100%;"&gt;cart.add(dummyItem, QUANTITY);&lt;/span&gt;&lt;br /&gt;&lt;span style=" ;font-family:courier new, monospace;font-size:100%;"&gt;assertEquals(QUANTITY*PRICE, cart.getCost(ITEM_NAME));&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;A Mock can return values, but it also cares about the way its methods are called (“strict mocks” care about the order of method calls, whereas “lenient mocks” do not.)  Testing with mocks is interaction-based testing; you set expectations on the mock, and the mock verifies the expectations as it is exercised.  This example uses JMock to generate the mock (EasyMock is similar):&lt;/p&gt;&lt;br /&gt;&lt;p style="BORDER:1px solid #808080; PADDING:0.1in; BACKGROUND:#e6f5ff none repeat scroll 0% 50%; MARGIN-LEFT:0.39in; MARGIN-RIGHT:0.39in; MARGIN-BOTTOM:0pt"&gt;&lt;span style=" ;font-family:courier new, monospace;font-size:100%;"&gt;Mockery context = new Mockery();&lt;/span&gt;&lt;br /&gt;&lt;span style=" ;font-family:courier new, monospace;font-size:100%;"&gt;final ItemPricer pricer = context.mock(ItemPricer.class);&lt;/span&gt;&lt;br /&gt;&lt;span style=" ;font-family:courier new, monospace;font-size:100%;"&gt;context.checking(new Expectations() {{&lt;/span&gt;&lt;br /&gt;&lt;span style=" ;font-family:courier new, monospace;font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;one(pricer).getPrice(ITEM_NAME);&lt;/span&gt;&lt;br /&gt;&lt;span style=" ;font-family:courier new, monospace;font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;will(returnValue(PRICE));&lt;/span&gt;&lt;br /&gt;&lt;span style=" ;font-family:courier new, monospace;font-size:100%;"&gt;}});&lt;/span&gt;&lt;br /&gt;&lt;span style=" ;font-family:courier new, monospace;font-size:100%;"&gt;ShoppingCart cart = new ShoppingCart(pricer);&lt;/span&gt;&lt;br /&gt;&lt;span style=" ;font-family:courier new, monospace;font-size:100%;"&gt;cart.add(dummyItem, QUANTITY);&lt;/span&gt;&lt;br /&gt;&lt;span style=" ;font-family:courier new, monospace;font-size:100%;"&gt;cart.getCost(ITEM_NAME);    &lt;/span&gt;    &lt;br /&gt;&lt;span style=" ;font-family:courier new, monospace;font-size:100%;"&gt;context.assertIsSatisfied();&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;A Spy serves the same purpose as a mock: returning values and recording calls to its methods.  However, tests with spies are state-based rather than interaction-based, so the tests look more like stub style tests. &lt;/p&gt;&lt;br /&gt;&lt;p style="BORDER:1px solid #808080; PADDING:0.1in; BACKGROUND:#e6f5ff none repeat scroll 0% 50%; MARGIN-LEFT:0.39in; MARGIN-RIGHT:0.39in; MARGIN-BOTTOM:0pt"&gt;&lt;span style=" ;font-family:courier new, monospace;font-size:100%;"&gt;TransactionLog log = new TransactionLogSpy();&lt;/span&gt;&lt;br /&gt;&lt;span style=" ;font-family:courier new, monospace;font-size:100%;"&gt;ShoppingCart cart = new ShoppingCart(log);&lt;/span&gt;&lt;br /&gt;&lt;span style=" ;font-family:courier new, monospace;font-size:100%;"&gt;cart.add(dummyItem, QUANTITY);&lt;/span&gt;&lt;br /&gt;&lt;span style=" ;font-family:courier new, monospace;font-size:100%;"&gt;assertEquals(1, logSpy.getNumberOfTransactionsLogged()); &lt;/span&gt;&lt;br /&gt;&lt;span style=" ;font-family:courier new, monospace;font-size:100%;"&gt;assertEquals(QUANTITY*PRICE, log.getTransactionSubTotal(1));&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;A Fake swaps out a real implementation with a simpler, fake implementation. The classic example is implementing an in-memory database. &lt;/p&gt;&lt;br /&gt;&lt;p style="BORDER:1px solid #808080; PADDING:0.1in; BACKGROUND:#e6f5ff none repeat scroll 0% 50%; MARGIN-LEFT:0.39in; MARGIN-RIGHT:0.39in; MARGIN-BOTTOM:0pt"&gt;&lt;span style=" ;font-family:courier new, monospace;font-size:100%;"&gt;Repository&lt;Transaction&gt; repo = new InMemoryRepository&lt;Transaction&gt;();&lt;/span&gt;&lt;br /&gt;&lt;span style=" ;font-family:courier new, monospace;font-size:100%;"&gt;ShoppingCart cart = new ShoppingCart(repo);&lt;/span&gt;&lt;br /&gt;&lt;span style=" ;font-family:courier new, monospace;font-size:100%;"&gt;cart.add(dummyItem, QUANTITY);&lt;/span&gt;&lt;br /&gt;&lt;span style=" ;font-family:courier new, monospace;font-size:100%;"&gt;assertEquals(1, repo.getTransactions(cart).Count); &lt;/span&gt;&lt;br /&gt;&lt;span style=" ;font-family:courier new, monospace;font-size:100%;"&gt;assertEquals(QUANTITY, repo.getById(cart.id()).getQuantity(ITEM_NAME));&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;While this episode used Java for its examples, all of the above “friends” certainly exist in C++, Python, JavaScript, and probably in YOUR favorite language as well.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Remember to download &lt;a href="http://code.google.com/testing/TotT-2008-06-12.pdf"&gt;this episode&lt;/a&gt; of Testing on the Toilet and post it in your office.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/blogspot/RLXA?a=IAwaAI"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/RLXA?i=IAwaAI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/blogspot/RLXA?a=o3grSi"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/RLXA?i=o3grSi" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/RLXA/~4/310530151" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/blogspot/RLXA/~3/310530151/tott-friends-you-can-depend-on.html" title="TotT: Friends You Can Depend On" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=15045980&amp;postID=7184144255017647866" title="4 Comments" /><link rel="replies" type="application/atom+xml" href="http://googletesting.blogspot.com/feeds/7184144255017647866/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default/7184144255017647866" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default/7184144255017647866" /><author><name>dastels</name><uri>http://www.blogger.com/profile/07735664941682371671</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://googletesting.blogspot.com/2008/06/tott-friends-you-can-depend-on.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-15045980.post-958832703938991511</id><published>2008-06-03T20:44:00.000-07:00</published><updated>2008-06-03T20:45:55.935-07:00</updated><title type="text">3 days left for GTAC Proposals!</title><content type="html">A brief reminder that there are only three days left to submit proposals for this year's Google Test Automation Conference. The proposal deadline is June 6th, after which the selection process will begin.&lt;br /&gt;&lt;br /&gt;The Call For Proposals announcement is available at the Google Testing Blog &lt;a href="http://googletesting.blogspot.com/2008/04/gtac-call-for-proposals.html"&gt;here&lt;/a&gt;.&lt;a href="http://googletesting.blogspot.com/2008/04/gtac-call-for-proposals.html" target="_blank"&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;See you in October!&lt;br /&gt;&lt;span style="color:#888888;"&gt;Lydia Ash&lt;br /&gt;GTAC Conference Chair - 2008&lt;/span&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/blogspot/RLXA?a=u7YtcI"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/RLXA?i=u7YtcI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/blogspot/RLXA?a=0AgQgi"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/RLXA?i=0AgQgi" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/RLXA/~4/304233178" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/blogspot/RLXA/~3/304233178/3-days-left-for-gtac-proposals.html" title="3 days left for GTAC Proposals!" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=15045980&amp;postID=958832703938991511" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://googletesting.blogspot.com/feeds/958832703938991511/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default/958832703938991511" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default/958832703938991511" /><author><name>Patrick Copeland</name><uri>http://www.blogger.com/profile/02362734812961509270</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://googletesting.blogspot.com/2008/06/3-days-left-for-gtac-proposals.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-15045980.post-2800658145359865745</id><published>2008-05-31T09:23:00.000-07:00</published><updated>2008-05-31T09:26:16.452-07:00</updated><title type="text">Performance Testing of Distributed File Systems at Google</title><content type="html">&lt;span class="byline-author"&gt;&lt;/span&gt;&lt;div style="text-align: left;"&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: rgb(0, 0, 0); font-family: Verdana; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;b id="eolb1"&gt;&lt;i id="lqfm0"&gt;Posted by Rajat Jain and Marc Kaplan, Infrastructure Test Engineering &lt;/i&gt;&lt;/b&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: rgb(0, 0, 0); font-family: Verdana; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: rgb(0, 0, 0); font-family: Verdana; font-size: 13px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;br /&gt;Google is unique in that we develop most of our software infrastructure from scratch inside the company. Distributed filesystems are no exception, and we have several here at Google that all serve different purposes. One such filesystem is the&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;&lt;a id="eolb4" href="http://labs.google.com/papers/gfs.html"&gt;Google File System&lt;/a&gt;&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;(GFS) which is used to store almost all data at Google. Although, GFS is the ultimate endpoint for much of the data at Google, there are many other distributed file systems built on top of GFS for a variety of purposes (see&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;&lt;a title="Bigtable" href="http://labs.google.com/papers/bigtable.html" id="xfih"&gt;Bigtable&lt;/a&gt;, for example -- but several others also exist) with developers constantly trying to improve performance to meet the ever-increasing demands of serving data at Google. The challenge to the teams testing performance of these filesystems is that running performance tests, analyzing the results, and repeating over and over is very time consuming. Also, since each filesystem is different, we  have traditionally had different performance testing tools for the different filesystems, which made it difficult to compare performance between the filesystems, and led to a lot of unnecessary maintenance work on the tools.&lt;br /&gt;&lt;br /&gt;In order to streamline testing of these filesystems, we wanted to create a new framework that is capable of easily performance testing the filesystems at Google. The goals of this system were as follows:&lt;br /&gt;&lt;ul id="eolb6" style="margin-top: 0px; margin-bottom: 0px;"&gt;&lt;li id="eolb7" style="margin-top: 0px; margin-bottom: 0px;"&gt;&lt;b id="j-6t"&gt;Generic:&lt;/b&gt;&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;The testing framework should be generic enough to test any type of file-system inside Google. In having a generic framework, it will be easier to compare the performance of different filesystems across many operations.&lt;/li&gt;&lt;li id="eolb7" style="margin-top: 0px; margin-bottom: 0px;"&gt;&lt;b id="j-6t0"&gt;Ease of use:&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;&lt;/b&gt;The framework should be easy enough to use so that software developers can design and run their own tests without any help from the test team.&lt;br /&gt;&lt;/li&gt;&lt;li id="eolb9" style="margin-top: 0px; margin-bottom: 0px;"&gt;&lt;b id="j-6t1"&gt;Scalable:&lt;/b&gt;&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;Testing can be done at various scales depending on the scalability of the FS. The framework can issue any number of operations simultaneously. So, for a testing a Linux file system, we might only issue 1000 parallel requests, while for the Google File System, we might want to issue requests at a much larger scale.&lt;/li&gt;&lt;li id="eolb10" style="margin-top: 0px; margin-bottom: 0px;"&gt;&lt;b id="j-6t2"&gt;Extensible:&lt;/b&gt;&lt;/li&gt;&lt;ul id="gj1q" style="margin-top: 0px; margin-bottom: 0px;"&gt;&lt;li id="eolb10" style="margin-top: 0px; margin-bottom: 0px;"&gt;Firstly, it should be easy to add a new kind of&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;&lt;i id="o0-d0"&gt;operation&lt;/i&gt;&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;in the framework, if its developed in future (For example,&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;&lt;i id="o0-d1"&gt;RecordAppend&lt;/i&gt;&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;operation in GFS).&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;ul id="gj1q0" style="margin-top: 0px; margin-bottom: 0px;"&gt;&lt;li id="eolb12" style="margin-top: 0px; margin-bottom: 0px;"&gt;Also, the framework should allow the user to easily generate complex types of load&lt;i id="xnbf0"&gt;scenarios&lt;/i&gt;&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;on the server. For example, we might want to have a scenario in which we issue File&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;&lt;i id="z3.:0"&gt;Create&lt;/i&gt;&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;operations simultaneously with&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;&lt;i id="cqbz0"&gt;Read&lt;/i&gt;,&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;&lt;i id="auk2"&gt;Write&lt;/i&gt;, and&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;&lt;i id="auk20"&gt;Delete&lt;/i&gt;&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;operations. Thus, we want a good mix of operations but not in a randomized way, so that we can have benchmark results.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li id="eolb13" style="margin-top: 0px; margin-bottom: 0px;"&gt;&lt;b id="auk21"&gt;Unified testing:&lt;/b&gt;&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;The framework should be stand-alone or independent&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;&lt;i id="sc_50"&gt;ie&lt;/i&gt;&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;it should be a one-stop solution to setup, run the tests and monitor the results.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;We developed a framework which allows us to achieve all the above mentioned goals. We used the Google's generic&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;&lt;span id="hnr:0" style="font-family: 'Courier New';"&gt;File&lt;/span&gt;&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;API for writing the framework, since every file system can be tested just by changing the&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;&lt;i id="hz040"&gt;file namespace&lt;/i&gt;&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;in which the testing data will be generated (e.x. /gfs vs. /bigtable). Following Google's standard, we developed a&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;&lt;i id="uexb0"&gt;Driver&lt;/i&gt;&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;+&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;&lt;i id="uexb1"&gt;Worker&lt;/i&gt;&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;system. The&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;&lt;i id="uexb2"&gt;Driver&lt;/i&gt;&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;co-ordinates the overall test, by reading configuration files to set up the test, automatically launching different number of workers depending on the load, monitoring the health of workers, collecting performance data from each worker and calculating the overall performance. The&lt;i id="b15j0"&gt;Worker&lt;/i&gt;&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;class is the one which loads the file systems with appropriate operations. A worker is an abstract class and a new child class can be created for each file operation, which gives us the flexibility to add any operation we want in the future. A separate&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;&lt;i id="e-t.0"&gt;Worker&lt;/i&gt;&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;instance is launched on a different machine depending on the load that we want to generate. It is simple to run more or less workers on remote machines simply by changing the config file.&lt;br /&gt;&lt;br /&gt;&lt;span id="yutr0" style="color: rgb(0, 0, 0);" &gt;The test is divided into various phases. In a phase, we can run a single operation N number of times (with a given concurrency) and collect performance data. So, we can run a create phase followed by a write phase followed by a read phase. We can also have multiple sub-phases inside a phase, which gives us the ability to generate many different simultaneous operations on the system. For example, in a phase, we might add three subphases create, write and delete, which will issue all the different kinds of operations simultaneously on remote client machines against the distributed filesystem.&lt;br /&gt;&lt;br /&gt;It is instructive to look at an example config file for an idea of how the load is specified against this filesystem:&lt;br /&gt;&lt;br /&gt;&lt;span id="l:wy0" style="color: rgb(61, 133, 198);"&gt;# Example of create&lt;/span&gt;&lt;br /&gt;&lt;span id="l:wy2" style="color: rgb(61, 133, 198);"&gt;phase {&lt;/span&gt;&lt;br /&gt;&lt;span id="l:wy4" style="color: rgb(61, 133, 198);"&gt;  label: "create"&lt;/span&gt;&lt;br /&gt;&lt;span id="l:wy6" style="color: rgb(61, 133, 198);"&gt;  shards: 200&lt;/span&gt;&lt;br /&gt;&lt;span id="l:wy8" style="color: rgb(61, 133, 198);"&gt;  create {&lt;/span&gt;&lt;br /&gt;&lt;span id="l:wy10" style="color: rgb(61, 133, 198);"&gt;    file_prefix: "metadata_perf"&lt;/span&gt;&lt;br /&gt;&lt;span id="l:wy13" style="color: rgb(61, 133, 198);"&gt;  }&lt;/span&gt;&lt;br /&gt;&lt;span id="l:wy16" style="color: rgb(61, 133, 198);"&gt;  count: 100&lt;/span&gt;&lt;br /&gt;&lt;span id="l:wy18" style="color: rgb(61, 133, 198);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span id="bor50"  style="color:#000000;"&gt;So in the example above, we launch 200 shards (which all run of different client machines) that all do creates of files with a prefix of metadata_perf, and suffixes based upon the index of the worker shard. In practice, the user of the performance test passes a flag into the performance test binary that specifies a base path to use: i.e. /gfs/cell1/perftest_path, and the resulting files will be /gfs/cell1/perftest_path/worker.i/metadata_perf.j, for i=1 until i=#shards, and j=1, until j=count.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span id="l:wy21" style="color: rgb(61, 133, 198);"&gt;# Example of using subphases&lt;/span&gt;&lt;br /&gt;&lt;span id="l:wy23" style="color: rgb(61, 133, 198);"&gt;phase {&lt;/span&gt;&lt;br /&gt;&lt;span id="l:wy25" style="color: rgb(61, 133, 198);"&gt;  label: "subphase_test"&lt;/span&gt;&lt;br /&gt;&lt;span id="l:wy27" style="color: rgb(61, 133, 198);"&gt;  subphase {&lt;/span&gt;&lt;br /&gt;&lt;span id="l:wy29" style="color: rgb(61, 133, 198);"&gt;    shards: 200&lt;/span&gt;&lt;br /&gt;&lt;span id="l:wy31" style="color: rgb(61, 133, 198);"&gt;    label: "stat_subphase"&lt;/span&gt;&lt;br /&gt;&lt;span id="l:wy33" style="color: rgb(61, 133, 198);"&gt;    stat {&lt;/span&gt;&lt;br /&gt;&lt;span id="l:wy35" style="color: rgb(61, 133, 198);"&gt;      file_prefix: "metadata_perf"&lt;/span&gt;&lt;br /&gt;&lt;span id="l:wy37" style="color: rgb(61, 133, 198);"&gt;   &lt;span class="Apple-converted-space"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span id="l:wy39" style="color: rgb(61, 133, 198);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span id="l:wy43" style="color: rgb(61, 133, 198);"&gt;    count: 100&lt;/span&gt;&lt;br /&gt;&lt;span id="l:wy45" style="color: rgb(61, 133, 198);"&gt;  }&lt;/span&gt;&lt;br /&gt;&lt;span id="l:wy47" style="color: rgb(61, 133, 198);"&gt;  subphase {&lt;/span&gt;&lt;br /&gt;&lt;span id="l:wy49" style="color: rgb(61, 133, 198);"&gt;    shards: 200&lt;/span&gt;&lt;br /&gt;&lt;span id="l:wy51" style="color: rgb(61, 133, 198);"&gt;    label: "open_subphase"&lt;/span&gt;&lt;br /&gt;&lt;span id="l:wy53" style="color: rgb(61, 133, 198);"&gt;    open {&lt;/span&gt;&lt;br /&gt;&lt;span id="l:wy55" style="color: rgb(61, 133, 198);"&gt;      file_prefix: "metadata_perf"&lt;/span&gt;&lt;br /&gt;&lt;span id="l:wy57" style="color: rgb(61, 133, 198);"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span id="l:wy61" style="color: rgb(61, 133, 198);"&gt;    count: 100&lt;/span&gt;&lt;br /&gt;&lt;span id="l:wy63" style="color: rgb(61, 133, 198);"&gt;  }&lt;/span&gt;&lt;br /&gt;&lt;span id="l:wy65" style="color: rgb(61, 133, 198);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In the example above, we simultaneously do stats and opens of the files that were initially created in the create phase. Different workers execute these, and then report their results to the driver.&lt;br /&gt;&lt;br /&gt;On conclusion of the test, the driver prints a performance test results report that details the aggregate results of all of the clients, in terms of MB/s for data intensive ops, ops/s for metadata intensive ops, and latency measures of central tendency and dispersion.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;In conclusion, Google's generic&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;&lt;span id="ey1o0" style="font-family: 'Courier New';"&gt;File&lt;/span&gt;&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;API, use of Driver &amp;amp; Workers and&lt;span class="Apple-converted-space"&gt; &lt;/span&gt;&lt;span id="xkqi0" style="color: rgb(0, 0, 0);" &gt;the concept of phases&lt;/span&gt;have been very useful in the development of the performance testing framework and hence making performance testing easier. Almost as important, the fact that this is a simple script-driven method of testing complex distributed filesystems has resulted in an ease of use that has given both developers and testers, the ability to quickly experiment and iterate, resulting in faster code development and better performance overall.&lt;/span&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/blogspot/RLXA?a=VScJ0H"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/RLXA?i=VScJ0H" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/blogspot/RLXA?a=SVa7ih"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/RLXA?i=SVa7ih" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/RLXA/~4/301923393" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/blogspot/RLXA/~3/301923393/performance-testing-of-distributed-file.html" title="Performance Testing of Distributed File Systems at Google" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=15045980&amp;postID=2800658145359865745" title="4 Comments" /><link rel="replies" type="application/atom+xml" href="http://googletesting.blogspot.com/feeds/2800658145359865745/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default/2800658145359865745" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default/2800658145359865745" /><author><name>Patrick Copeland</name><uri>http://www.blogger.com/profile/02362734812961509270</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://googletesting.blogspot.com/2008/05/performance-testing-of-distributed-file.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-15045980.post-7408541936845962351</id><published>2008-05-28T15:19:00.000-07:00</published><updated>2008-05-28T15:25:38.022-07:00</updated><title type="text">TotT: The Invisible Branch</title><content type="html">&lt;p&gt;Full statement coverage may be necessary for good testing coverage, but it isn't sufficient. Two places where statement coverage will be inadequate are branches and loops. In this episode, we'll look at branches, and specifically the differences between &lt;b&gt;&lt;font color=#800000&gt;statement coverage&lt;/font&gt;&lt;/b&gt; and &lt;b&gt;&lt;font color=#800000&gt;branch coverage&lt;/font&gt;&lt;/b&gt;.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Let's consider a case where branch coverage and statement coverage aren't the same.  Suppose we test the following snippet.  We can get complete statement coverage with a single test by using a berserk EvilOverLord:&lt;/p&gt;&lt;br /&gt;&lt;p style="BORDER:1px solid #808080; PADDING:0.1in; BACKGROUND:#e6f5ff none repeat scroll 0% 50%; MARGIN-LEFT:0.39in; MARGIN-RIGHT:0.39in; MARGIN-BOTTOM:0pt"&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;bool DeathRay::ShouldFire(EvilOverLord&amp; o, Target&amp; t) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;double accumulated_rage = 0.0;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;if (o.IsBerserk())&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;accumulated_rage += kEvilOverlordBerserkRage;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;accumulated_rage += o.RageFeltTowards(t);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;return (accumulated_rage &gt; kDeathRayRageThreshold);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;But what if DeathRay should fire at this Target even with a non-berserk Overlord?  Well, we need another test for that.  What should the test be?  Let's rewrite the code a little bit.  We would never see code like this in the real world, but it'll help us clarify an important point.&lt;/p&gt;&lt;br /&gt;&lt;p style="BORDER:1px solid #808080; PADDING:0.1in; BACKGROUND:#e6f5ff none repeat scroll 0% 50%; MARGIN-LEFT:0.39in; MARGIN-RIGHT:0.39in; MARGIN-BOTTOM:0pt"&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;bool DeathRay::ShouldFire(EvilOverLord&amp; o, Target&amp; t) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;double accumulated_rage = 0.0;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;if (o.IsBerserk()) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;accumulated_rage += kEvilOverlordBerserkRage;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;} else {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;accumulated_rage += o.RageFeltTowards(t);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;return (accumulated_rage &gt; kDeathRayRageThreshold);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Why do we add an else clause if it doesn't actually do anything?  If you were to &lt;b&gt;&lt;font color=#800000&gt;draw a flowchart&lt;/font&gt;&lt;/b&gt; of both snippets (left as an exercise – and we recommend against using the paper provided), the flowcharts would be identical.  The fact that the else isn't there in the first snippet is simply a convenience for us as coders – we generally don't want to write code to do nothing special – but &lt;b&gt;&lt;font color=#800000&gt;the branch still exists&lt;/font&gt;&lt;/b&gt;...  put another way, &lt;b&gt;&lt;font color=#800000&gt;every &lt;i&gt;if&lt;/i&gt; has an &lt;i&gt;else&lt;/i&gt;&lt;/font&gt;&lt;/b&gt;.  Some of them just happen to be invisible.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;When you're testing, then, it isn't enough to cover all the statements – you should &lt;b&gt;&lt;font color=#800000&gt;cover all the the edges in the control flow graph&lt;/font&gt;&lt;/b&gt; – which can be even more complicated with loops and nested ifs.  In fact, part of the art of large-scale white-box testing is finding the minimum number of tests to cover the maximum number of paths.  So the lesson here is, just because you can't see a branch doesn't mean it isn't there – or that you shouldn't test it.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Remember to download &lt;a href="http://code.google.com/testing/TotT-2008-05-29.pdf"&gt;this episode&lt;/a&gt; of Testing on the Toilet and post it in your office.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/blogspot/RLXA?a=GX8lRH"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/RLXA?i=GX8lRH" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/blogspot/RLXA?a=iAaMEh"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/RLXA?i=iAaMEh" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/RLXA/~4/300129924" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/blogspot/RLXA/~3/300129924/tott-invisible-branch.html" title="TotT: The Invisible Branch" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=15045980&amp;postID=7408541936845962351" title="3 Comments" /><link rel="replies" type="application/atom+xml" href="http://googletesting.blogspot.com/feeds/7408541936845962351/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default/7408541936845962351" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default/7408541936845962351" /><author><name>dastels</name><uri>http://www.blogger.com/profile/07735664941682371671</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://googletesting.blogspot.com/2008/05/tott-invisible-branch.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-15045980.post-1807437612826603243</id><published>2008-05-24T20:37:00.000-07:00</published><updated>2008-05-24T20:43:30.820-07:00</updated><title type="text">Intro to Ad Quality Test Challenges</title><content type="html">&lt;span class="byline-author"&gt;Alek Icev Ads Quality Test Engineering Manager&lt;br /&gt;&lt;br /&gt;I'd like to take a second and introduce you to the team testing the ads ranking algorithms. We'd like to think that we had a hand in the webs shift to a "content meritocracy". As you know the Google search results are unbiased by human editors, and we don't allow buying a spot at the top of the results list. This idea builds trust with users and allows the community to decide what's important.&lt;br /&gt;&lt;br /&gt;Recently, we started applying the same concept to the online advertising. We asked ourselves how to bring the same level of "content meritocracy" to the online advertising where everybody pays to have ads being displayed on Google and on our partner sites. In other words, we needed to change a system that was predominately driven by human influence into one that build its merit based on feedback from the community. The idea was that we would penalize the ranking of paid ads in several circumstances: few users were clicking on a particular ads, an ad's landing page was not relevant, or if users don't like an ad's content.  We want to provide our users with absolutely the most relevant ads for their click. In order to make our vision a reality we are building one of the largest online and real time machine learning labs in the world. We learn from everything: clicks, queries, ads, landing pages, conversions... hundreds of signals.&lt;br /&gt;&lt;br /&gt;The Google Ad Prediction System brought new challenges to Test Engineering. The problem is that we needed to build the abstraction layers and metrics systems that allow us to understand if the system is organically getting better or regressing. Put another way, we started off lacking the decision tree or a perceptron that a bank or credit card company have embedded into their risk analysis, or the neural net that's behind all broken speech recognition, or the latest tweaks on expectation-maximization algorithms needed to predict the protein transcription in the cells. The amount and versatility of the data that Google Ad Prediction models learn is immense. The amount of time needed to make the prediction is counted in milliseconds. The amount of computing resources, ads databases and infrastructure needed to serve predictions on every ad that is showing today is beyond imagination. Our challenge is to train and test learning models, that span clusters of servers and databases, simulate ads traffic and having everything compiled and running from the latest code changes submitted to the huge source depot. And the icing on the cake is to run that on 24/7 schedule.&lt;br /&gt;&lt;br /&gt;On top of all of the technical challenges, we are also challenging the industry definition of "testing" and are believers in automated tests that are incorporated upstream into the development process and run on continuous basis. Ads Quality Test Engineering Group at Google, works on a bleeding edge testing infrastructure to test, simulate and train Google Ads Prediction systems in real time.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/blogspot/RLXA?a=iEmw4H"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/RLXA?i=iEmw4H" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/blogspot/RLXA?a=aKPHGh"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/RLXA?i=aKPHGh" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/RLXA/~4/297545265" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/blogspot/RLXA/~3/297545265/intro-to-ad-quality-test-challenges.html" title="Intro to Ad Quality Test Challenges" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=15045980&amp;postID=1807437612826603243" title="6 Comments" /><link rel="replies" type="application/atom+xml" href="http://googletesting.blogspot.com/feeds/1807437612826603243/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default/1807437612826603243" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default/1807437612826603243" /><author><name>Patrick Copeland</name><uri>http://www.blogger.com/profile/02362734812961509270</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://googletesting.blogspot.com/2008/05/intro-to-ad-quality-test-challenges.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-15045980.post-2215416487122195898</id><published>2008-05-20T17:30:00.000-07:00</published><updated>2008-05-20T18:02:51.442-07:00</updated><title type="text">Exploratory Testing on Chat</title><content type="html">&lt;span class="byline-author"&gt;Posted by Joel Hynoski, Test Manager, Chat Clients&lt;/span&gt;&lt;br /&gt;&lt;p class="MsoNormal"&gt;Testing Google Talk is challenging -- we have multiple client implementations, between the Google Talk client, the Google Talk Gadget, and Gmail chat, while also managing new features and development. We rely heavily on automation. Yet there's still a need to do manual testing before the release of the product to the public.&lt;br /&gt;&lt;br /&gt;We've found that one of the best ways to unearth interesting bugs in the product is to use Exploratory Testing (&lt;a href="http://www.satisfice.com/articles/et-article.pdf" target="_blank"&gt;http://www.satisfice.com&lt;wbr&gt;/articles/et-article.pdf&lt;/a&gt;) The trouble with ET is that while there appears to be a genetic disposition to be naturally good at exploring the product effectively, it's very easy to miss great swathes of the product when one follows their intuition through the product rather than focusing on coverage metrics. And speaking of coverage, how do we measure how well a team is doing finding bugs and getting coverage over the functional use cases for the product? All of the things that we rely on to measure the quality of the product, boundary and edge cases being covered? Plus, if not everyone is proficient at ET, how do we solve the overhead of having an experienced team member looking over people's shoulders to make sure they are executing well?&lt;br /&gt;&lt;br /&gt;To do this, we start with the definition of a &lt;b&gt;Test Strategy&lt;/b&gt;. This is where we outline the approach we are taking to the testing of the product as a whole. It's not super-detailed -- instead it mentions the overarching areas that need to be tested, whether automation can be used to test the area, and what role manual testing needs to play. This information lets developers and PMs know what we think we need to test for the product, and allows them to add unit tests etc to cover more ground.&lt;br /&gt;&lt;br /&gt;Some basic test case definition go into the &lt;b&gt;Test Plan&lt;/b&gt;. The aim of the test plan (and any test artifacts generated) is not to specify a set of actions to be followed in a rote manner, but instead a rough guide that encourages creative exploration. The test plan also acts as the virtual test expert, providing some framework under which exploratory testing can be executed effectively by the team. The plan decomposes the application into different areas of responsibility, that are doled out to members of the team in sessions that are one-working-day or less duration. By guiding people's thinking, we can cover the basics, fuzzy cases, and avoids a free-for-all, duplication, and missed areas.&lt;br /&gt;&lt;br /&gt;Finally we get a &lt;b&gt;status report&lt;/b&gt; from the testers every day, that describes the testing that was performed that day, any bugs raised, and blocking issues identified. The reports acts as an execution of the "contract" and gives traceability, and the ability to tweak exploratory testing that has gone off track from where we've determined we need to concentrate efforts. We can use these status reports along with bug statistics to gauge the effectiveness of the test sessions.&lt;br /&gt;&lt;br /&gt;This is approach is fairly simple, but sometimes simple works best. Using this method has allowed us to make the best use of test engineers and maximized the effectiveness of each test pass. It's proven itself to be a fruitful approach and balances the need for reporting and accountability with the agility of exploratory testing.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/blogspot/RLXA?a=cYrW2H"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/RLXA?i=cYrW2H" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/blogspot/RLXA?a=Z2lozh"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/RLXA?i=Z2lozh" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/RLXA/~4/294663403" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/blogspot/RLXA/~3/294663403/exploratory-testing-on-chat.html" title="Exploratory Testing on Chat" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=15045980&amp;postID=2215416487122195898" title="7 Comments" /><link rel="replies" type="application/atom+xml" href="http://googletesting.blogspot.com/feeds/2215416487122195898/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default/2215416487122195898" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default/2215416487122195898" /><author><name>Patrick Copeland</name><uri>http://www.blogger.com/profile/02362734812961509270</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://googletesting.blogspot.com/2008/05/exploratory-testing-on-chat.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-15045980.post-3417901443265400654</id><published>2008-05-15T23:16:00.000-07:00</published><updated>2008-05-15T23:17:03.386-07:00</updated><title type="text">TotT: Using Dependancy Injection to Avoid Singletons</title><content type="html">&lt;b&gt;&lt;font color=#800000&gt;It's hard to test code that uses singletons.&lt;/font&gt;&lt;/b&gt;   Typically, the code you want to test is coupled strongly with the singleton instance.  You can't control the creation of the singleton object because often it is created in a static initializer or static method.  As a result, you also can't mock out the behavior of that Singleton instance.&lt;br /&gt;&lt;br /&gt;If changing the implementation of a singleton class is not an option, but changing the &lt;b&gt;&lt;font color=#800000&gt;client&lt;/font&gt;&lt;/b&gt; of a singleton is, a simple refactoring can make it easier to test.  Let's say you had a method that uses a &lt;font face="Courier New, monospace"&gt;Server&lt;/font&gt; as a singleton instance:&lt;br /&gt;&lt;p style="BORDER:1px solid #808080; PADDING:0.1in; BACKGROUND:#e6f5ff none repeat scroll 0% 50%; MARGIN-LEFT:0.39in; MARGIN-RIGHT:0.39in; MARGIN-BOTTOM:0pt"&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;public class Client {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;public int process(Params params) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Server server = Server.getInstance();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Data data = server.retrieveData(params);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;...&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;You can refactor &lt;font face="Courier New, monospace"&gt;Client&lt;/font&gt; to use &lt;b&gt;&lt;font color=#800000&gt;Dependency Injection&lt;/font&gt;&lt;/b&gt; and avoid its use of the singleton pattern altogether.  You have not lost any functionality, and have also not lost the requirement that only a singleton instance of &lt;font face="Courier New, monospace"&gt;Server&lt;/font&gt; must exist.  The only difference is that instead of getting the &lt;font face="Courier New, monospace"&gt;Server&lt;/font&gt; instance from the static &lt;font face="Courier New, monospace"&gt;getInstance&lt;/font&gt; method, &lt;font face="Courier New, monospace"&gt;Client&lt;/font&gt; receives it in its constructor.  You have made the class easier to test!&lt;br /&gt;&lt;br /&gt;&lt;p style="BORDER:1px solid #808080; PADDING:0.1in; BACKGROUND:#e6f5ff none repeat scroll 0% 50%; MARGIN-LEFT:0.39in; MARGIN-RIGHT:0.39in; MARGIN-BOTTOM:0pt"&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;public class Client {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;private final Server server;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;public Client(Server server) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;this.server = server;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;public int process(Params params){&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Data data = this.server.retrieveData(params);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;...&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;When testing, you can create a mock &lt;font face="Courier New, monospace"&gt;Server&lt;/font&gt; with whatever expected behavior you need and pass it into the &lt;font face="Courier New, monospace"&gt;Client&lt;/font&gt; under test:&lt;br /&gt;&lt;br /&gt;&lt;p style="BORDER:1px solid #808080; PADDING:0.1in; BACKGROUND:#e6f5ff none repeat scroll 0% 50%; MARGIN-LEFT:0.39in; MARGIN-RIGHT:0.39in; MARGIN-BOTTOM:0pt"&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;public void testProcess() {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;Server mockServer = createMock(Server.class);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;Client c = new Client(mockServer);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;assertEquals(5, c.process(params));&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;Remember to download &lt;a href="http://code.google.com/testing/TotT-2008-05-15.pdf"&gt;this episode&lt;/a&gt; of Testing on the Toilet and post it in your office.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/blogspot/RLXA?a=3LS59H"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/RLXA?i=3LS59H" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/blogspot/RLXA?a=CzEjLh"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/RLXA?i=CzEjLh" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/RLXA/~4/291445610" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/blogspot/RLXA/~3/291445610/tott-using-dependancy-injection-to.html" title="TotT: Using Dependancy Injection to Avoid Singletons" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=15045980&amp;postID=3417901443265400654" title="5 Comments" /><link rel="replies" type="application/atom+xml" href="http://googletesting.blogspot.com/feeds/3417901443265400654/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default/3417901443265400654" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default/3417901443265400654" /><author><name>dastels</name><uri>http://www.blogger.com/profile/07735664941682371671</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://googletesting.blogspot.com/2008/05/tott-using-dependancy-injection-to.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-15045980.post-8794245154286217763</id><published>2008-05-01T10:06:00.000-07:00</published><updated>2008-05-01T10:10:30.213-07:00</updated><title type="text">TotT: Testable Contracts Make Exceptional Neighbors</title><content type="html">Consider the following function, which modifies a client-supplied object:&lt;br /&gt;&lt;br /&gt;&lt;p style="BORDER:1px solid #808080; PADDING:0.1in; BACKGROUND:#e6f5ff none repeat scroll 0% 50%; MARGIN-LEFT:0.39in; MARGIN-RIGHT:0.39in; MARGIN-BOTTOM:0pt"&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&lt;b&gt;bool&lt;/b&gt; SomeCollection::&lt;b&gt;GetObjects(vector&lt;Object*&gt;* objects)&lt;/b&gt; const {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&lt;b&gt;objects-&gt;clear();&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;typedef vector&lt;Object*&gt;::const_iterator Iterator;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;for (Iterator i = collection_.begin(); &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;i != collection_.end(); &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;++i) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;b&gt;if ((*i)-&gt;IsFubarred()) return false;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;b&gt;objects-&gt;push_back(*i);&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&lt;b&gt;return true;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;Consider when &lt;font face="Courier New, monospace"&gt;GetObjects()&lt;/font&gt; is called.  What if the caller doesn't check the return value, and assumes the data is in a valid state when it actually is not?  If the caller does check the return value, &lt;b&gt;&lt;font color=#800000&gt;what can it assume about the state of its objects in the failure case&lt;/font&gt;&lt;/b&gt;?  When &lt;font face="Courier New, monospace"&gt;GetObjects()&lt;/font&gt; fails, it would be much better if either all the objects were collected or none of them.  This can help avoid introducing hard to find bugs.&lt;br /&gt;&lt;br /&gt;By using good design contracts and a solid implementation, it is reasonably easy to make functions like &lt;font face="Courier New, monospace"&gt;GetObjects()&lt;/font&gt; behave like transactions.  By following Sutter's rule of &lt;b&gt;&lt;font color=#800000&gt;modifying externally-visible state only after completing all operations which could possibly fail&lt;/font&gt;&lt;/b&gt; [1], and mixing in Meyers's “swap trick” [2], we move from the realm of undefined behavior to what Abrahams defines as the strong guarantee [3]:&lt;br /&gt;&lt;br /&gt;&lt;p style="BORDER:1px solid #808080; PADDING:0.1in; BACKGROUND:#e6f5ff none repeat scroll 0% 50%; MARGIN-LEFT:0.39in; MARGIN-RIGHT:0.39in; MARGIN-BOTTOM:0pt"&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&lt;b&gt;bool&lt;/b&gt; SomeCollection::&lt;b&gt;GetObjects(vector&lt;Object*&gt;* objects)&lt;/b&gt; const {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&lt;b&gt;vector&lt;Object*&gt; known_good_objects;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;typedef vector&lt;Object*&gt;::const_iterator Iterator;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;for (Iterator i = collection_.begin(); &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;i != collection_.end(); &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;++i) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if ((*i)-&gt;IsFubarred()) return false;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;b&gt;known_good_objects-&gt;push_back(*i);&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&lt;b&gt;objects-&gt;swap(known_good_objects);&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&lt;b&gt;return true;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;At the cost of one temporary and a pointer swap, we've strengthened the contract of our interface such that, at best, the caller received a complete, new collection of valid objects; at worst, the state of the caller's objects remains unchanged.   The caller might not verify the return value, but will not suffer from undefined results.  This allows us to reason much more clearly about the program state, making it much easier to verify the intended outcome with automated tests as well as recreate, pinpoint, and banish bugs with regression tests.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://www.gotw.ca/publications"&gt;http://www.gotw.ca/publications&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Scott Meyers, Effective C++&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.boost.org/more/generic_exception_safety.html"&gt;http://www.boost.org/more/generic_exception_safety.html&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Remember to download &lt;a href="http://code.google.com/testing/TotT-2008-05-01.pdf"&gt;this episode&lt;/a&gt; of Testing on the Toilet and post it in your office.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/blogspot/RLXA?a=TEbYPH"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/RLXA?i=TEbYPH" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/blogspot/RLXA?a=R63qwh"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/RLXA?i=R63qwh" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/RLXA/~4/281571760" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/blogspot/RLXA/~3/281571760/tott-testable-contracts-make.html" title="TotT: Testable Contracts Make Exceptional Neighbors" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=15045980&amp;postID=8794245154286217763" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://googletesting.blogspot.com/feeds/8794245154286217763/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default/8794245154286217763" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default/8794245154286217763" /><author><name>dastels</name><uri>http://www.blogger.com/profile/07735664941682371671</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://googletesting.blogspot.com/2008/05/tott-testable-contracts-make.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-15045980.post-8692159891577440658</id><published>2008-04-29T15:51:00.000-07:00</published><updated>2008-04-29T15:55:06.003-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="GTAC" /><title type="text">GTAC: Call for Proposals</title><content type="html">&lt;span style="color: rgb(0, 0, 0);" class="byline-author"&gt;Posted by &lt;/span&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;Lydia Ash - GTAC Conference Chair&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Overview&lt;/b&gt;&lt;br /&gt;The Test Automation Conference has been hosted by Google over the past several years bringing together a select set of industry practitioners as speakers and participants around the topic of software testing and automation. The annual conference provides a forum for presentations on important topics in our field connecting professions with others in their field through collaboration and targeted breakout sessions, but also has served the testing community by bringing the presentations public allowing anyone access to the information.&lt;br /&gt;&lt;br /&gt;GTAC conference participants are typically software engineers who are actively working on problems of software quality, automated testing, and testing techniques. GTAC conferences cover a number of areas, but many presentations focus on themes such as advanced techniques in quality evaluation, advanced approaches to automating software testing, and experiences and findings from quality efforts on software projects.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The Conference&lt;/b&gt;&lt;br /&gt;The conference is a two day event comprised of a single track of presentations. The philosophy is to engage a small set of active participants who all experience the same topics carrying the discussions into lightning talks, speaker Q&amp;amp;A, and topical discussion groups. The emphasis for the 2008 GTAC conference is solving the hard engineering problems in the quality of our software. Each year we have worked to identify a location that has a unique profile of technology professionals. This year the conference will be held in Seattle, WA, USA on October 23 and 24.&lt;br /&gt;&lt;br /&gt;Presentations are targeted at experienced engineers actively working on software quality. We encourage innovative ideas, controversial experiences, problems, and solutions that further the discussion of engineering and software quality. Presentations are generally 45 min in length and speakers should be prepared for an active question and answer session following their presentation.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Process of Selection&lt;/b&gt;&lt;br /&gt;All presentation submissions will be handled electronically. Presentation proposals should be a relatively detailed extended abstract including the topic, outline, and details of what will be presented. Presentation proposals should be emailed to &lt;a href="mailto:gtac@google.com" target="_blank"&gt;gtac@google.com&lt;/a&gt;&lt;br /&gt;All presentation proposals must be received by June 6, 2008. Where employer or disclosure authorization is needed, the author(s) will need to obtain this prior to submitting their proposal.&lt;br /&gt;&lt;br /&gt;The program committee will evaluate proposals based on the quality and relevance. All submissions will be held confidentially prior to contacting the selected presenters and the publication in the proceedings.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Notification&lt;/b&gt;&lt;br /&gt;Accepted proposal authors will be contacted on or before July 10 to confirm their availability and travel needs. Authors of proposals not selected will be notified on or before July 10. Accepted proposals will be presented at the conference and made available to the public on YouTube.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Copyright&lt;/b&gt;&lt;br /&gt;TAC requires presenters to present at the conference and permit their presentation to be made available on YouTube.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Important Dates for Presentations&lt;/b&gt;&lt;br /&gt;June 6 - Final deadline for proposal submissions for presentations&lt;br /&gt; July 10 - Deadline for selected presenters to be contacted by the selection committee and notified of their acceptance&lt;br /&gt;October 23 and 24 - GTAC conference in Seattle&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Attendees&lt;/b&gt;&lt;br /&gt;TAC conference has worked to invite a select audience, each member applies to the conference for committee selection. This is to ensure active participation from each attendee and provide a variety of technical perspectives to interact, discuss, and network.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Important Dates for Attendees&lt;/b&gt;&lt;br /&gt;July 7 - Call for attendee profile submissions&lt;br /&gt;July 25 - Deadline for attendee profiles&lt;br /&gt;August 11 - Selected attendees to be notified by the conference committee, registration opens&lt;br /&gt; August 29 - Registration deadline, wait-list opens&lt;br /&gt;September 19 - Wait list notifications and attendee closure&lt;br /&gt;October 23 and 24 - GTAC conference in Seattle&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Questions&lt;/b&gt;&lt;br /&gt;If you have questions about the submission process or potential topics please send a mail to us at: &lt;a href="mailto:gtac@google.com" target="_blank"&gt;gtac@google.com&lt;/a&gt;&lt;br /&gt; Please see the Google Testing blog for more information: &lt;a href="http://googletesting.blogspot.com/search/label/GTAC" target="_blank"&gt;http://googletesting.blogspot&lt;wbr&gt;.com/search/label/GTAC&lt;/a&gt;&lt;span style="color: rgb(136, 136, 136);"&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/blogspot/RLXA?a=3p7C2G"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/RLXA?i=3p7C2G" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/blogspot/RLXA?a=MdXNGg"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/RLXA?i=MdXNGg" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/RLXA/~4/280380801" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/blogspot/RLXA/~3/280380801/gtac-call-for-proposals.html" title="GTAC: Call for Proposals" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=15045980&amp;postID=8692159891577440658" title="1 Comments" /><link rel="replies" type="application/atom+xml" href="http://googletesting.blogspot.com/feeds/8692159891577440658/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default/8692159891577440658" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default/8692159891577440658" /><author><name>Patrick Copeland</name><uri>http://www.blogger.com/profile/02362734812961509270</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://googletesting.blogspot.com/2008/04/gtac-call-for-proposals.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-15045980.post-8797924969745988223</id><published>2008-04-19T09:36:00.000-07:00</published><updated>2008-04-19T23:16:46.162-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="GTAC" /><title type="text">GTAC 2008 in Seattle</title><content type="html">Before the end of our last &lt;a href="http://youtube.com/results?search_query=GTAC+google"&gt;Google Test Automation Conference&lt;/a&gt; in August 2007, we were already getting questions from participants and blog readers wondering about the next conference. Now we can tell you when and where that will happen (drum roll please)... the 2008 Test Automation Conference will be held &lt;span style="color: rgb(255, 0, 0);"&gt;October 23 and 24 in Seattle&lt;/span&gt;. More details will be coming shortly...&lt;br /&gt;&lt;br /&gt;As with previous years, the focus of the conference will be solving software engineering challenges using tools and automation, with special focus on &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;SaaS&lt;/span&gt;. Engineers in the testing world are frequently so busy shipping software that they do not take the time to share the technical details of the work they are doing, the approaches that are working, and the lessons they have learned. There will be a call for proposals in late April.&lt;br /&gt;&lt;br /&gt;As has been the precedent in previous years, our conference is for active and vocal participation, not quiet attendance. &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;GTAC&lt;/span&gt; is a place to share great ideas and to get challenged. As we have done previously, attendants will apply by proposing what they will bring to the conference and how they can further the discussions. Applications for attendance will be opened in late June.&lt;br /&gt;&lt;br /&gt;We are hard at work developing the conference. Please send suggestions, questions and recommendations to: &lt;a href="mailto:gtac@google.com" target="_blank"&gt;gtac@google.com&lt;/a&gt; or post your comments here to the blog.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/blogspot/RLXA?a=jNrMRI"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/RLXA?i=jNrMRI" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/blogspot/RLXA?a=fqrIqi"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/RLXA?i=fqrIqi" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/RLXA/~4/273740567" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/blogspot/RLXA/~3/273740567/gtac-2008-in-seattle.html" title="GTAC 2008 in Seattle" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=15045980&amp;postID=8797924969745988223" title="4 Comments" /><link rel="replies" type="application/atom+xml" href="http://googletesting.blogspot.com/feeds/8797924969745988223/comments/default" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default/8797924969745988223" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/15045980/posts/default/8797924969745988223" /><author><name>Patrick Copeland</name><uri>http://www.blogger.com/profile/02362734812961509270</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://googletesting.blogspot.com/2008/04/gtac-2008-in-seattle.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-15045980.post-4366529983057271760</id><published>2008-04-17T09:05:00.000-07:00</published><updated>2008-04-22T15:04:01.274-07:00</updated><title type="text">TotT: Avoiding Flakey Tests</title><content type="html">Flaky tests make your life more difficult. You get failure notifications that aren't helpful. You might become numb to failures and miss an actual failure condition. Your changes might get unfairly blamed for causing a flaky test to fail. &lt;br /&gt;&lt;br /&gt;Unfortunately, &lt;b&gt;&lt;font color=#800000&gt;a myriad of factors can make a test flaky&lt;/font&gt;&lt;/b&gt;. Today, we tackle a simple example: file access from a unit test. Take this function and its test:&lt;br /&gt;&lt;br /&gt;&lt;p style="BORDER:1px solid #808080; PADDING:0.1in; BACKGROUND:#e6f5ff none repeat scroll 0% 50%; MARGIN-LEFT:0.39in; MARGIN-RIGHT:0.39in; MARGIN-BOTTOM:0pt"&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;def CreateGapLease(self):&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;data_file = open('/leases/gap', 'w+')&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;data_file.write(contract_data)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;data_file.close()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;def testCreateGapLease(self):&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;contract_writer.CreateGapLease()&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;self.assertEqual(ReadFileContents('/leases/gap'),&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; contract_data)&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;What if &lt;font face="Courier New, monospace"&gt;/leases/gap&lt;/font&gt; already exists and contains some data? &lt;font face="Courier New, monospace"&gt;testCreateGapLease&lt;/font&gt; will fail. This is a general problem where preconditions are assumed to be correct. This could just as easily happen by assuming a database contains the proper information (or no information). &lt;b&gt;&lt;font color=#800000&gt;What if another test that uses that file was running concurrently?&lt;/font&gt;&lt;/b&gt; &lt;br /&gt;&lt;br /&gt;If you really want to test your code using live resources, always check your assumptions. In this case, clearing the file at the start of the test can reduce its brittleness:&lt;br /&gt;&lt;br /&gt;&lt;p style="BORDER:1px solid #808080; PADDING:0.1in; BACKGROUND:#e6f5ff none repeat scroll 0% 50%; MARGIN-LEFT:0.39in; MARGIN-RIGHT:0.39in; MARGIN-BOTTOM:0pt"&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;def testCreateGapLease(self):&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&lt;b&gt;if os.path.exists(lease_file):&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;b&gt;RemoveFile(lease_file)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;...&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;Unfortunately, this doesn't completely eliminate the flakiness of our test. If &lt;font face="Courier New, monospace"&gt;/leases/gap&lt;/font&gt; is an NFS path or can be written to by a different test, our test can still fail unexpectedly. It's better for the test to use a unique resource. This can be accomplished with a small refactoring of &lt;font face="Courier New, monospace"&gt;CreateGapLease&lt;/font&gt;:&lt;br /&gt;&lt;br /&gt;&lt;p style="BORDER:1px solid #808080; PADDING:0.1in; BACKGROUND:#e6f5ff none repeat scroll 0% 50%; MARGIN-LEFT:0.39in; MARGIN-RIGHT:0.39in; MARGIN-BOTTOM:0pt"&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;def CreateGapLease(self&lt;b&gt;, lease_path=None&lt;/b&gt;):&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;if lease_path is None:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;lease_path = '/leases/gap'&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;...&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;The callers of &lt;font face="Courier New, monospace"&gt;CreateGapLease&lt;/font&gt; can continue invoking it as usual, but the unit test can pass in a different path: &lt;br /&gt;&lt;br /&gt;&lt;p style="BORDER:1px solid #808080; PADDING:0.1in; BACKGROUND:#e6f5ff none repeat scroll 0% 50%; MARGIN-LEFT:0.39in; MARGIN-RIGHT:0.39in; MARGIN-BOTTOM:0pt"&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;def testCreateGapLease(self):&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&lt;b&gt;lease_file = os.path.join(FLAGS.test_tmpdir, 'gap')&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;contract_writer.CreateGapLease(lease_path=lease_file)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;self.assertEqual(ReadFileContents(lease_file),&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new, monospace; font-size:100%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; contract_data)&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;Of course, to make your test as fast as possible, it would be better to forgo disk access altogether by using a mock file system.&lt;br /&gt;&lt;br /&gt;Remember to download &lt;a href="http://code.google.com/testing/TotT-2008-04-17.pdf"&gt;this episode&lt;/a&gt; of Testing on the Toilet and post it in your office.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Due to illness availability of the PDF will be slightly delayed