<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1959052963816936322</id><updated>2010-07-08T06:08:13.431-07:00</updated><title type='text'>Approval Tests</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://blog.approvaltests.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1959052963816936322/posts/default'/><link rel='alternate' type='text/html' href='http://blog.approvaltests.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Llewellyn Falco</name><uri>http://www.blogger.com/profile/11668997629228826023</uri><email>noreply@blogger.com</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>12</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1959052963816936322.post-273026940008320481</id><published>2009-09-12T14:27:00.001-07:00</published><updated>2009-09-12T14:41:41.216-07:00</updated><title type='text'>Hello JRack</title><content type='html'>Today &lt;a href="http://zuill.us/WoodyZuill/"&gt;Woody Zuill&lt;/a&gt; and myself put some of the finishing touches on a port of &lt;a title="Rack" href="http://rack.rubyforge.org/" id="ddds"&gt;Rack&lt;/a&gt; to Java, and published it to the world.  So let's do a quick show-and-tell to show you why we are so excited.&lt;br /&gt;&lt;br /&gt;JRack is an extremely simple yet extremely useful and powerful way to create web apps.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Simple To Create&lt;/b&gt;&lt;br /&gt;Let's look at how simple it is to create a "Hello World" web page.&lt;br /&gt;&lt;pre&gt;&lt;span style="color: rgb(153, 51, 153);font-family:courier new;" &gt;&lt;span style="font-weight: bold;"&gt;public class&lt;/span&gt; &lt;/span&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;HelloWorldRack &lt;/span&gt;&lt;span style="color: rgb(153, 51, 153); font-weight: bold;font-family:courier new;" &gt;implements &lt;/span&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;JRack&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(153, 51, 153); font-weight: bold;font-family:courier new;" &gt;  public &lt;/span&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;RackResponse &lt;/span&gt;&lt;span style="font-family:courier new;"&gt;call(&lt;span style="font-weight: bold;"&gt;Map&lt;/span&gt;&amp;lt;&lt;/span&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;String&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;, &lt;/span&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;Object&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;&amp;gt; input)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;      &lt;/span&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;&lt;span style="color: rgb(153, 51, 153);"&gt;return &lt;/span&gt;RackResponseUtils&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;.standardHtml(&lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);font-family:courier new;" &gt;"HelloWorld"&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;}&lt;/span&gt;&lt;div style="background: rgb(255, 255, 255) none repeat scroll 0% 0%; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; float: left; font-family: courier new;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;/pre&gt;Wasn't that simple? Just 1 line to pass back the html we want displayed.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Simple To Run&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Of course, this has just created it.  What if we actually want to have this running on a Web Server,  what would we have to do?&lt;br /&gt;&lt;br /&gt;We can simply harness it through &lt;a title="Jetty" href="http://www.eclipse.org/jetty/" id="osj9"&gt;Jetty&lt;/a&gt;&lt;i&gt; (you can also deploy on regular servers like tomcat)&lt;/i&gt;.  &lt;a title="Jetty" href="http://www.eclipse.org/jetty/" id="be95"&gt;Jetty&lt;/a&gt; is a simple, standalone Web Servlet container.  You can find out more about it &lt;a title="here" href="http://www.eclipse.org/jetty/" id="g6-c"&gt;here&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;We'll add a main method to our HelloWorldRack:&lt;br /&gt;&lt;pre&gt;&lt;span style="font-weight: bold; color: rgb(153, 51, 153);font-family:courier new;" &gt;public class &lt;/span&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;HelloWorldRack &lt;/span&gt;&lt;span style="font-weight: bold; color: rgb(153, 51, 153);font-family:courier new;" &gt;implements &lt;/span&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;JRack&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   ...&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt; &lt;/span&gt;&lt;span style="font-weight: bold; color: rgb(153, 51, 153);font-family:courier new;" &gt; public static void&lt;/span&gt;&lt;span style="font-family:courier new;"&gt; main(&lt;/span&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;String&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;[] args)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    &lt;/span&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;JettyUtils&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;.startJettyRack(80, &lt;/span&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;&lt;span style="color: rgb(153, 51, 153);"&gt;new &lt;/span&gt;HelloWorldRack&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;());  &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;  }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Now, if we run HelloWorldRack, we will have a fully running rack server serving the HelloWorld page.&lt;br /&gt;Nice and simple.  You are up and running with just two lines of code.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Simple To Test &amp;amp; Reuse&lt;/b&gt;&lt;br /&gt;But what if you unit test this code?  Don't you need a webserver to even run it? NO!&lt;br /&gt;You can call the RackApp directly. Simply pass in what in used by the environment (in this case, nothing). Whats more we've added &lt;a title="approval test" href="http://approvaltests.sourceforge.net/" id="cnk2"&gt;approval test&lt;/a&gt; support so you can simple approve the resulting html.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Put this code into a JUnit test class:&lt;br /&gt;&lt;pre&gt;&lt;span style="font-weight: bold; color: rgb(153, 51, 153);font-family:courier new;" &gt;public void &lt;/span&gt;&lt;span style="font-family:courier new;"&gt;testHelloWorld() &lt;/span&gt;&lt;span style="font-weight: bold; color: rgb(153, 51, 153);font-family:courier new;" &gt;throws &lt;/span&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;Exception&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    &lt;/span&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;Approvals&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;.approve(new &lt;/span&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;HelloWorldRack&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;().call(null));&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Okay - simple to write, simple to run, simply to test.  There are many sites extolling the virtues of &lt;a title="Rack" href="http://rack.rubyforge.org/" id="c8yy"&gt;Rack&lt;/a&gt;.  More and more, the Ruby community is migrating over to it.  And now, you can have the same simplicity in the Java world.  We'll write more about it later.  You can &lt;a title="download it here" href="https://sourceforge.net/projects/approvaltests/files/" id="p4d9"&gt;download it here&lt;/a&gt;.&lt;br /&gt;I also encourage you to look at the &lt;a title="test examples here" href="http://approvaltests.svn.sourceforge.net/viewvc/approvaltests/trunk/code/java/org/jrack/tests/" id="turu"&gt;test examples here&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1959052963816936322-273026940008320481?l=blog.approvaltests.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.approvaltests.com/feeds/273026940008320481/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1959052963816936322&amp;postID=273026940008320481' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1959052963816936322/posts/default/273026940008320481'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1959052963816936322/posts/default/273026940008320481'/><link rel='alternate' type='text/html' href='http://blog.approvaltests.com/2009/09/hello-jrack.html' title='Hello JRack'/><author><name>Llewellyn Falco</name><uri>http://www.blogger.com/profile/11668997629228826023</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='08608010092011158874'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1959052963816936322.post-8981060655433001748</id><published>2009-06-21T21:51:00.001-07:00</published><updated>2009-06-21T22:04:08.077-07:00</updated><title type='text'>Why Write Unit Tests?</title><content type='html'>Why Write Unit Tests?&lt;br /&gt;&lt;br /&gt;I've made a small video to go with this post&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;object width="425" height="344"&gt;&lt;param name="movie" value="http://www.youtube.com/v/k5Y_jo4Nn54&amp;amp;hl=en&amp;amp;fs=1&amp;amp;"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;embed src="http://www.youtube.com/v/k5Y_jo4Nn54&amp;amp;hl=en&amp;amp;fs=1&amp;amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Approval Tests have allowed us to focus on the parts of testing at a much higher level of abstraction.   Things that had been too hard to see have become visible. The benefits of Automated Tests are one of the areas that we can now more clearly appreciate.  There are 4 main areas programmers can benefit from using Automated Tests (Unit and otherwise)&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;b&gt;Specifications&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Feedback&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Regression&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Granularity&lt;/b&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Let's talk about each of these.&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;First, there is &lt;b&gt;Specifications&lt;/b&gt;. Everyone knows that good requirements help programmers to produce better software. Well, you can't do better than a running, failing unit test. This gives a clearly defined goal, and provides a executable document of the &lt;b&gt;Users Intent&lt;/b&gt;. Focusing on this particular area, has led to the emergence of &lt;b&gt;Behavior Driven Development (BDD).&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Fast &lt;b&gt;Feedback&lt;/b&gt;. After you know what you want to write, it's very helpful to know that you are fulfilling that requirement. Feedback allows you to know when you have made a mistake, or a wrong turn. Imagine you are driving to Disneyland and you miss your turn. When would you like to know that? Immediately afterwards? 10 minutes later? 6 hours later?  Or only when you reach the east coast? &lt;b&gt;Feedback &lt;/b&gt;from your test can tell you within seconds if you didn't code what you thought you did. Compare that to sending it to QA and getting a bug report back next week. Focusing on this particular area has led to &lt;b&gt;Test Driven Development (TDD)&lt;/b&gt;, and is what they are referring to when they speak of bouncing between the &lt;b&gt;red &amp;amp; green&lt;/b&gt; bars.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Regression Testing&lt;/b&gt; is what most people actually think of when they talk about testing. This is all about maintaining &amp;amp; assuring the quality of the code (by which I mean, is the code working). Focusing on this aspect of testing brings about &lt;b&gt;Acceptance Testing &lt;/b&gt;and products like &lt;b&gt;Selenium&lt;/b&gt; &amp;amp; &lt;b&gt;Fitness&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;And finally &lt;b&gt;Granularity&lt;/b&gt;. Imagine the following bug report: "The software has a bug." While this is sufficient to tell you whether or not you have bug free software, it's not at all useful in helping you to remove that bug. (If you've ever done a &lt;a title="google code jam" href="http://code.google.com/codejam/" id="sskv"&gt;google code jam&lt;/a&gt;, this is exactly what the bug reports look like by the way.) It's nice to have some &lt;b&gt;granularity pointing you to the problem. &lt;/b&gt;Something like "if you select user #6 and run a expense report for July 7th, line 15 says $34 when it should say $65". Now that's helpful! Again, &lt;b&gt;TDD&lt;/b&gt; is really the area most focused on small granular tests, partly because granularity and feedback are highly related.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Hopefully, you will start to see these 4 features of testing as you continue to unit test. I don't want to place any sort of hierarchy of value on them right now, just point out that they are all valuable. Of course, if you are using approval tests, you'll see how they can aid each and every one of these categories!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1959052963816936322-8981060655433001748?l=blog.approvaltests.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.approvaltests.com/feeds/8981060655433001748/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1959052963816936322&amp;postID=8981060655433001748' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1959052963816936322/posts/default/8981060655433001748'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1959052963816936322/posts/default/8981060655433001748'/><link rel='alternate' type='text/html' href='http://blog.approvaltests.com/2009/06/parts.html' title='Why Write Unit Tests?'/><author><name>Llewellyn Falco</name><uri>http://www.blogger.com/profile/11668997629228826023</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='08608010092011158874'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1959052963816936322.post-8129760928925378969</id><published>2009-04-25T18:45:00.001-07:00</published><updated>2009-04-25T18:53:25.638-07:00</updated><title type='text'>Approving the Weather</title><content type='html'>&lt;br&gt;&lt;b&gt;How can I test the weather?&lt;/b&gt; We have a project where we need to know the weather report. This is possible thru a web API that will give us the weather report. However, we have no control over either the API or the weather. So how do we test this? The traditional approach is to encapsulate all calls to the weather API and then mock it out. The unfortunate part is this doesn't actually test the weather at all. It 'only' allows us to test the entire rest of the app in hopes that the encapsulated piece will work. Let's take a look at a new way to actually test the Weather API using approvals.&lt;br&gt;&lt;br&gt;&lt;b&gt;Feedback, Regression &amp;amp; Granularity&lt;/b&gt; :Unit Tests bring us a variety of things that are important in writing software: &lt;b&gt;Feedback &lt;/b&gt;as we are writing the code, to know that we are writing what we wanted; &lt;b&gt;Regression Testing &lt;/b&gt;so that once it works, it doesn't get bugs; and &lt;b&gt;Granularity of Feedback&lt;/b&gt;, so when something goes wrong, we know exactly where and why it did.&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;b&gt;A new approach&lt;/b&gt;. Let's look at a new approach that can get us all of these things, quickly and easily.&lt;br&gt;&lt;br&gt;&lt;div style="margin-left: 40px;"&gt;&lt;b&gt;Feedback:&lt;/b&gt; First, we are going to need an encapsulated piece that loads the weather. &lt;br&gt;This is going to be a small class with two functions.&lt;br&gt;&lt;br&gt;&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New; color: rgb(0, 0, 255);"&gt;class WeatherLoader&lt;/span&gt;&lt;br style="font-family: Courier New; color: rgb(0, 0, 255);"&gt;&lt;span style="font-family: Courier New; color: rgb(0, 0, 255);"&gt;{&lt;/span&gt;&lt;br style="font-family: Courier New; color: rgb(0, 0, 255);"&gt;&lt;span style="font-family: Courier New; color: rgb(0, 0, 255);"&gt;&amp;nbsp; getQuery();&amp;nbsp; &lt;span style="color: rgb(56, 118, 29);"&gt;// returns the query that's used to get the weather&lt;/span&gt;&lt;/span&gt;&lt;br style="font-family: Courier New; color: rgb(0, 0, 255);"&gt;&lt;span style="font-family: Courier New; color: rgb(0, 0, 255);"&gt;&amp;nbsp; execute(query); &lt;span style="color: rgb(56, 118, 29);"&gt;// executes the given query to get the weather&lt;/span&gt;&lt;/span&gt;&lt;br style="font-family: Courier New; color: rgb(0, 0, 255);"&gt;&lt;span style="font-family: Courier New; color: rgb(0, 0, 255);"&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;/div&gt;Now we're going to write a test that exercises this.&lt;br&gt;&lt;br&gt;&lt;div style="margin-left: 40px;"&gt;&lt;span style="color: rgb(0, 0, 255); font-family: Courier New;"&gt;Approvals.approve(new WeatherLoader("&lt;span style="color: rgb(255, 0, 0);"&gt;San Diego&lt;/span&gt;"));&lt;/span&gt;&lt;br style="color: rgb(0, 0, 255); font-family: Courier New;"&gt;&lt;/div&gt;&lt;br&gt;When we run this it will fail as all approvals do the first time and we will see the results of using this API.&lt;br&gt;&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New;"&gt;Query:&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;GetCityWeather?city=San%20Diego&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New;"&gt;Result:&lt;/span&gt;&lt;br style="font-family: Courier New;"&gt;&lt;span style="font-family: Courier New; color: rgb(0, 0, 255);"&gt;&amp;lt;WeatherReturn&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New; color: rgb(0, 0, 255);"&gt;&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: Courier New; color: rgb(0, 0, 255);"&gt;&amp;lt;Success&amp;gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;true&lt;/span&gt;&lt;/b&gt;&amp;lt;/Success&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New; color: rgb(0, 0, 255);"&gt;&lt;span style="font-family: Courier New; color: rgb(0, 0, 255);"&gt;&amp;lt;ResponseText&amp;gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;City Found&lt;/span&gt;&lt;/b&gt;&amp;lt;/ResponseText&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New; color: rgb(0, 0, 255);"&gt;&lt;span style="font-family: Courier New; color: rgb(0, 0, 255);"&gt;&amp;lt;State&amp;gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;CA&lt;/span&gt;&lt;/b&gt;&amp;lt;/State&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New; color: rgb(0, 0, 255);"&gt;&lt;span style="font-family: Courier New; color: rgb(0, 0, 255);"&gt;&amp;lt;City&amp;gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;San Diego&lt;/span&gt;&lt;/b&gt;&amp;lt;/City&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New; color: rgb(0, 0, 255);"&gt;&lt;span style="font-family: Courier New; color: rgb(0, 0, 255);"&gt;&amp;lt;Temperature&amp;gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;62&lt;/span&gt;&lt;/b&gt;&amp;lt;/Temperature&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New; color: rgb(0, 0, 255);"&gt;&lt;span style="font-family: Courier New; color: rgb(0, 0, 255);"&gt;&amp;lt;Unit&amp;gt;&lt;b&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;Fahrenheit&lt;/span&gt;&lt;/b&gt;&amp;lt;/Unit&amp;gt;&lt;/span&gt;&lt;br style="font-family: Courier New; color: rgb(0, 0, 255);"&gt;&lt;/div&gt;&lt;span style="font-family: Courier New; color: rgb(0, 0, 255);"&gt;&amp;lt;/WeatherReturn&amp;gt;&lt;/span&gt;&lt;br&gt;&lt;/div&gt;&lt;br&gt;So now we have the &lt;b&gt;feedback &lt;/b&gt;that our API is working.&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;b&gt;Regression&lt;/b&gt;: Of course now that it's working we need it to work from this point on. Since we have no control over the weather, when we approve this test the only thing that will be approved will be the query, &lt;b&gt;not the result&lt;/b&gt;. From now on as long as the current query matches the old query this test will pass. This test will pass without actually running the query against the web service.&lt;br&gt;This is important so we'll say it again, &lt;b&gt;The test passes if the query hasn't changed&lt;/b&gt;.&lt;br&gt;&lt;br&gt;This means the approval artifact would look like this :&lt;br&gt;&lt;span style="font-family: Courier New; color: rgb(0, 0, 255);"&gt;GetCityWeather?city=San%20Diego&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;b&gt;Granularity&lt;/b&gt; &lt;b&gt;When Things Change&lt;/b&gt;: Of course all things change. Let's say in the future someone changes this call so that it returns the temperature in Celsius. Lets take a look at what would happen when you run that test.&lt;br&gt;&lt;br&gt;&lt;/div&gt;&lt;div style="margin-left: 40px; font-family: Times New Roman;"&gt;&lt;table class="" id="y:v6" border="1" bordercolor="#000000" cellpadding="3" cellspacing="0" width="585" height="220"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="font-family: Verdana;" width="50%"&gt;&lt;font size="1"&gt;Received&lt;br&gt;&lt;/font&gt;&lt;/td&gt;&lt;td style="font-family: Verdana;" width="50%"&gt;&lt;font size="1"&gt;Approved&lt;br&gt;&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="font-family: Verdana;" width="50%"&gt;&lt;font size="1"&gt;&lt;span style="background-color: rgb(255, 255, 0);"&gt;GetCityWeather?city=San%20Diego&lt;span style="background-color: rgb(255, 0, 0);"&gt;&amp;amp;unit=Celsius&lt;/span&gt;&lt;/span&gt;&lt;br style="background-color: rgb(255, 255, 0);"&gt;&lt;br&gt;Result:&lt;br&gt;&amp;lt;WeatherReturn&amp;gt;&lt;br&gt;&amp;lt;Success&amp;gt;true&amp;lt;/Success&amp;gt;&lt;br&gt;&amp;lt;ResponseText&amp;gt;City Found&amp;lt;/ResponseText&amp;gt;&lt;br&gt;&amp;lt;State&amp;gt;CA&amp;lt;/State&amp;gt;&lt;br&gt;&amp;lt;City&amp;gt;San Diego&amp;lt;/City&amp;gt;&lt;br&gt;&lt;span style="background-color: rgb(255, 255, 0);"&gt;&amp;lt;Temperature&amp;gt;&lt;span style="background-color: rgb(255, 0, 0);"&gt;29.4&lt;/span&gt;&amp;lt;/Temperature&amp;gt;&lt;/span&gt;&lt;br style="background-color: rgb(255, 255, 0);"&gt;&lt;span style="background-color: rgb(255, 255, 0);"&gt;&amp;lt;Unit&amp;gt;&lt;span style="background-color: rgb(255, 0, 0);"&gt;Celsius&lt;/span&gt;&amp;lt;/Unit&amp;gt;&lt;/span&gt;&lt;br&gt;&amp;lt;/WeatherReturn&amp;gt;&lt;/font&gt;&lt;/td&gt;&lt;td style="font-family: Verdana;" width="50%"&gt;&lt;font size="1"&gt;&lt;span style="background-color: rgb(255, 255, 0);"&gt;GetCityWeather?city=San%20Diego&lt;/span&gt;&lt;br&gt;&lt;br&gt;Result:&lt;br&gt;&amp;lt;WeatherReturn&amp;gt;&lt;br&gt;&amp;lt;Success&amp;gt;true&amp;lt;/Success&amp;gt;&lt;br&gt;&amp;lt;ResponseText&amp;gt;City Found&amp;lt;/ResponseText&amp;gt;&lt;br&gt;&amp;lt;State&amp;gt;CA&amp;lt;/State&amp;gt;&lt;br&gt;&amp;lt;City&amp;gt;San Diego&amp;lt;/City&amp;gt;&lt;br&gt;&lt;span style="background-color: rgb(255, 255, 0);"&gt;&amp;lt;Temperature&amp;gt;&lt;span style="background-color: rgb(255, 0, 0);"&gt;85&lt;/span&gt;&amp;lt;/Temperature&amp;gt;&lt;/span&gt;&lt;br style="background-color: rgb(255, 255, 0);"&gt;&lt;span style="background-color: rgb(255, 255, 0);"&gt;&amp;lt;Unit&amp;gt;&lt;span style="background-color: rgb(255, 0, 0);"&gt;Fahrenheit&lt;/span&gt;&amp;lt;/Unit&amp;gt;&lt;/span&gt;&lt;br&gt;&amp;lt;/WeatherReturn&amp;gt;&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br&gt;&lt;br&gt;&lt;b&gt;Both queries are re-run:&lt;/b&gt; Notice that the temperature of the approved file is &lt;b&gt;85&lt;/b&gt; not the &lt;b&gt;62&lt;/b&gt; when it was originally approved. This is because the query is the only thing that is persisted. The result of the query is re-executed at the time of failure giving us the current temperature in the approved section.&lt;br&gt;&lt;br&gt;Then notice that the query is re-executed for the received side. Through the beauty of diff tools not only do we get the large picture of what's going on but the details and granularity of everything that has now changed.&lt;br&gt;&lt;/div&gt;&lt;br&gt;&lt;b&gt;Testing the Indeterminate &lt;/b&gt;: This is a &lt;b&gt;one line test&lt;/b&gt; that runs against an external Indeterminate system. It required zero setup and we have zero control over it, yet, in the end we have tests that give us &lt;b&gt;Granularity&lt;/b&gt;, &lt;b&gt;Regression &lt;/b&gt;and &lt;b&gt;Feedback&lt;/b&gt;.&lt;br&gt;&lt;br&gt;&lt;b&gt;Other possible cases: &lt;/b&gt;Databases are another place where being deterministic can be a problem. Of course you can do a large amount of setup to force them to be deterministic. And, of course, this carries a high price in both writing the test and maintaining it. Let us suggest that you just accept that things aren't deterministic and use the above approach.&lt;br&gt;&lt;br&gt;As a final thought. Agile was created by accepting that requirements change. This approach was created by accepting that not everything we test is deterministic.&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1959052963816936322-8129760928925378969?l=blog.approvaltests.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.approvaltests.com/feeds/8129760928925378969/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1959052963816936322&amp;postID=8129760928925378969' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1959052963816936322/posts/default/8129760928925378969'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1959052963816936322/posts/default/8129760928925378969'/><link rel='alternate' type='text/html' href='http://blog.approvaltests.com/2009/04/approving-weather.html' title='Approving the Weather'/><author><name>Llewellyn Falco</name><uri>http://www.blogger.com/profile/11668997629228826023</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='08608010092011158874'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1959052963816936322.post-5065478808426599521</id><published>2009-03-29T10:21:00.001-07:00</published><updated>2009-03-29T10:32:48.462-07:00</updated><title type='text'>Use Reporter Annotations</title><content type='html'>Today I implemented a bit of dependency injection for the reporters in the Java version of approvaltests.&lt;br /&gt;&lt;br /&gt;The idea is that you might want your own reporters for your project. Things to take advantage of something we didn’t think of. While you could have always done this by calling:&lt;br /&gt;&lt;br /&gt;&lt;pre style="color:blue"&gt;&lt;br /&gt;Approvals.approve(ApprovalWriter, &lt;br /&gt;                  ApprovalNamer, &lt;br /&gt;                  ApprovalFailureReporter)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I wanted to make it a wee bit easier.&lt;br /&gt;&lt;br /&gt;Now you can do it by adding an annotation to any level of the stack calling. For example:&lt;br /&gt;&lt;br /&gt;&lt;pre style="color:blue"&gt;&lt;br /&gt;@UseReporter(FailedQuietApprovalReport.class)&lt;br /&gt;public class MyQuietTest extends TestCase&lt;br /&gt;{&lt;br /&gt;    public void testSomethingQuiet()&lt;br /&gt;    {&lt;br /&gt;    }            &lt;br /&gt;    @UseReporter(FailedDiffTextApprovalReport.class)&lt;br /&gt;    public void testWithDiff()&lt;br /&gt;    {&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This should make it easier in Java, and will probably appear soon in c#. You can download it now as part of&lt;br /&gt;&lt;a href="https://sourceforge.net/project/showfiles.php?group_id=242293"&gt;&lt;br /&gt;ApprovalTests Current 0.0.004 &lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1959052963816936322-5065478808426599521?l=blog.approvaltests.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.approvaltests.com/feeds/5065478808426599521/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1959052963816936322&amp;postID=5065478808426599521' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1959052963816936322/posts/default/5065478808426599521'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1959052963816936322/posts/default/5065478808426599521'/><link rel='alternate' type='text/html' href='http://blog.approvaltests.com/2009/03/use-reporter-annotations.html' title='Use Reporter Annotations'/><author><name>Llewellyn Falco</name><uri>http://www.blogger.com/profile/11668997629228826023</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='08608010092011158874'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1959052963816936322.post-7718964002223705335</id><published>2009-01-07T11:54:00.000-08:00</published><updated>2009-01-07T11:56:06.511-08:00</updated><title type='text'>"Let it BDD" and a mention about approvals</title><content type='html'>Here's a parody I wrote on testing code that mentions approvals.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.youtube.com/watch?v=pvJi1E730HA"&gt;Let it BDD&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1959052963816936322-7718964002223705335?l=blog.approvaltests.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.approvaltests.com/feeds/7718964002223705335/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1959052963816936322&amp;postID=7718964002223705335' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1959052963816936322/posts/default/7718964002223705335'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1959052963816936322/posts/default/7718964002223705335'/><link rel='alternate' type='text/html' href='http://blog.approvaltests.com/2009/01/let-it-bdd-and-mention-about-approvals.html' title='&quot;Let it BDD&quot; and a mention about approvals'/><author><name>Dan Gilkerson</name><uri>http://www.blogger.com/profile/07672335006879942771</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='08280337458693271807'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1959052963816936322.post-6943431783470044233</id><published>2008-10-31T19:03:00.000-07:00</published><updated>2008-11-03T12:20:02.575-08:00</updated><title type='text'>Talk at XPSD Thrusday Nov 6th</title><content type='html'>&lt;p class="MsoNormal" style="margin: 0in 0in 10pt;"&gt;&lt;span style=";font-family:arial;font-size:100%;"  &gt;we are giving a talk on approval tests at &lt;a href="http://www.xpsd.org/"&gt;XPSD&lt;/a&gt; Thursday Nov 6th at 6pm, here's the teaser...&lt;/span&gt;&lt;b style=""&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:Calibri;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;p class="MsoNormal" style="margin: 0in 0in 10pt;"&gt;&lt;b style=""&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:Calibri;"&gt;Approval  Based Tests&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt; &lt;p class="MsoNormal" style="margin: 0in 0in 10pt;"&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:Calibri;"&gt;&lt;i style=""&gt;Write your code, run it, see  that it works.&lt;/i&gt; This is a familiar process to all programmers. The addition  of 1 line of code can now make that a repeatable automated regression test!  &lt;/span&gt;&lt;/span&gt;&lt;/p&gt; &lt;p class="MsoNormal" style="margin: 0in 0in 10pt;"&gt;&lt;span style=";font-family:Calibri;font-size:100%;"  &gt; &lt;/span&gt;&lt;/p&gt; &lt;p class="MsoNormal" style="margin: 0in 0in 10pt;"&gt;&lt;span style=";font-family:Calibri;font-size:100%;"  &gt;Well  tested code has been shown, over and over, to improve the quality and  maintainability of software. Yet most projects are not well tested. Why is this?  Too often programmers feel that testing imposes too high of an overhead on  writing code.&lt;/span&gt;&lt;/p&gt; &lt;p class="MsoNormal" style="margin: 0in 0in 10pt;"&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:Calibri;"&gt;&lt;b style=""&gt;In this talk, our goal is  to make it easier and faster for you to write unit tests&lt;/b&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt; &lt;p class="MsoNormal" style="margin: 0in 0in 10pt;"&gt;&lt;span style=";font-family:Calibri;font-size:100%;"  &gt;We  will show how using approvals, in addition to asserts, will great increase not  only the ease and speed of writing a test, but the completeness and  maintainability of those tests; bridging the gap between people who don't write  tests, and test driven developers.&lt;/span&gt;&lt;/p&gt; &lt;p class="MsoNormal" style="margin: 0in 0in 10pt;"&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:Calibri;"&gt;&lt;i style=""&gt;"I feel like I have to write  my code twice…"&lt;/i&gt; Right now, unit tests impose a difficult step upfront of  knowing exactly what you want. Asserting this outcome then becomes cumbersome  the more robust &amp;amp; detailed it is. After that, maintaining the test becomes  equally cumbersome. Because of this, tests either do not get written, or get discarded,  leaving untested code which is fragile, error prone and leads to the nightmare  of maintenance so many experience.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt; &lt;p class="MsoNormal" style="margin: 0in 0in 10pt;"&gt;&lt;span style=";font-family:Calibri;font-size:100%;"  &gt;After  this talk, you should find yourself spending less time writing tests, yet having  better tested code, a proven way to increase successfulness of your  software.&lt;/span&gt;&lt;/p&gt; &lt;p class="MsoNormal" style="margin: 0in 0in 10pt;"&gt;&lt;span style=";font-family:Calibri;font-size:100%;"  &gt; &lt;/span&gt;&lt;/p&gt; &lt;p class="MsoNormal" style="margin: 0in 0in 10pt;"&gt;&lt;i style=""&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:Calibri;"&gt;"After I  heard Dan &amp;amp; Llewellyn talk about approval tests, I tried it out… in the  first 4 minutes I was testing my code" - C. Monkey&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;&lt;/p&gt; &lt;p class="MsoNormal" style="margin: 0in 0in 10pt;"&gt;&lt;i style=""&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:Calibri;"&gt;"I find  myself writing more code just so I can write more approval tests!" - Script  Kiddie&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;&lt;/p&gt; &lt;p class="MsoNormal" style="margin: 0in 0in 10pt; text-align: justify; font-style: italic;"&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:Calibri;"&gt;&lt;span style=""&gt; &lt;/span&gt;"All my life  I'd sought approval from other developers, now I can approve on my own" – Noself  E. Steam&lt;/span&gt;&lt;/span&gt;&lt;/p&gt; &lt;p class="MsoNormal" style="margin: 0in 0in 10pt;"&gt;&lt;i style=""&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-family:Calibri;"&gt;"With all  the time I saved, I actually learned to talk to women" &lt;span style=""&gt; &lt;/span&gt;- Mystery &lt;/span&gt;&lt;/span&gt;&lt;/i&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1959052963816936322-6943431783470044233?l=blog.approvaltests.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.approvaltests.com/feeds/6943431783470044233/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1959052963816936322&amp;postID=6943431783470044233' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1959052963816936322/posts/default/6943431783470044233'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1959052963816936322/posts/default/6943431783470044233'/><link rel='alternate' type='text/html' href='http://blog.approvaltests.com/2008/10/talk-at-xpsd-thrusday-nov-6th.html' title='Talk at XPSD Thrusday Nov 6th'/><author><name>Llewellyn Falco</name><uri>http://www.blogger.com/profile/11668997629228826023</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='08608010092011158874'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1959052963816936322.post-3038991761334813933</id><published>2008-10-30T01:44:00.000-07:00</published><updated>2008-10-30T01:49:31.969-07:00</updated><title type='text'>Approval Artifact Files</title><content type='html'>&lt;span style=";font-family:verdana;font-size:100%;"  &gt;One key element of approvals is the approved artifacts that are created, and I wanted to take some time to go into these. First off, it is worth mentioning that for xUnit type tests, what is created is a file of the name&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;MyClass.myMethod.approved.extention&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;... and ...&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;MyClass.myMethod.received.extention&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This file resides in the same directory as the source file for MyClass.&lt;br /&gt;&lt;br /&gt;Many times this is simply a text file. The output being approved being taken from the toString() method, or a similar printer. Sometimes it is an html file, which is really just a txt file, sometimes it is a Pdf file or Png image file.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(204, 0, 0);"&gt;Q: Are these files kept in source control?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Yes, the approved files reside in your source control. This has 2 big benefits&lt;br /&gt;&lt;br /&gt;1) The test are repeatable on different systems.&lt;br /&gt;&lt;br /&gt;2) You can flip back through easy to view output, to pinpoint when and where a bug got introduced.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(204, 0, 0);"&gt;Q: What configuration is needed?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;None.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(204, 0, 0);"&gt;Q: How can I write to a custom file format?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Simple, all Approvals.approve(object) calls simply construct an approver, and a reporter. The approver is normally a FileApprover, which takes a FileApprovalWriter and an ApprovalNamer.&lt;br /&gt;&lt;br /&gt;To do a custom file output simply make your own ApprovalWriter and your own convenience approve() function&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1959052963816936322-3038991761334813933?l=blog.approvaltests.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.approvaltests.com/feeds/3038991761334813933/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1959052963816936322&amp;postID=3038991761334813933' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1959052963816936322/posts/default/3038991761334813933'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1959052963816936322/posts/default/3038991761334813933'/><link rel='alternate' type='text/html' href='http://blog.approvaltests.com/2008/10/approval-artifact-files.html' title='Approval Artifact Files'/><author><name>Llewellyn Falco</name><uri>http://www.blogger.com/profile/11668997629228826023</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='08608010092011158874'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1959052963816936322.post-2937808270392664030</id><published>2008-10-21T08:26:00.000-07:00</published><updated>2008-10-21T08:27:32.882-07:00</updated><title type='text'>Downloads on source forge!</title><content type='html'>&lt;div&gt;This weekend we got the Java and C# versions packaged up on source forge. &lt;/div&gt;&lt;div&gt;Download them, try them out. Tell us what you think.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="https://sourceforge.net/projects/approvaltests/"&gt;https://sourceforge.net/projects/approvaltests/&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1959052963816936322-2937808270392664030?l=blog.approvaltests.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.approvaltests.com/feeds/2937808270392664030/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1959052963816936322&amp;postID=2937808270392664030' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1959052963816936322/posts/default/2937808270392664030'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1959052963816936322/posts/default/2937808270392664030'/><link rel='alternate' type='text/html' href='http://blog.approvaltests.com/2008/10/downloads-on-source-forge.html' title='Downloads on source forge!'/><author><name>Llewellyn Falco</name><uri>http://www.blogger.com/profile/11668997629228826023</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='08608010092011158874'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1959052963816936322.post-9216724152509079605</id><published>2008-10-16T14:59:00.000-07:00</published><updated>2008-10-18T15:15:38.021-07:00</updated><title type='text'>I know exactly what I want!</title><content type='html'>Well...sometimes&lt;br /&gt;&lt;br /&gt;When creating software, customers don't usually know exactly what they want at the beginning. Agile has checkpoints that allow for quick feedback; while the product is under development, customers can see features as soon as they are completed, giving them an opportunity to accept it or to suggest changes.&lt;br /&gt;&lt;br /&gt;Approvals give developers the same opportunity. As a developer, you may not know exactly what you want. The more insight you can get from a result, the more you understand where you want the design to go. That tends to lead us to a more natural flow of coding. You start off with a design in your head, code up an example usage, and implement it. When the result is what you expect, you approve it. With your approved result, you also have a regression test that ensures your expectations don't get violated.&lt;br /&gt;&lt;br /&gt;Here's an example test from a bowling game without approvals:&lt;pre name="code" class="c-sharp:nogutter:nocontrols"&gt;public void TestFourThrows()&lt;br /&gt;{&lt;br /&gt;game.Add(5);&lt;br /&gt;game.Add(4);&lt;br /&gt;game.Add(7);&lt;br /&gt;game.Add(2);&lt;br /&gt;Assert.AreEqual(18, game.Score);&lt;br /&gt;Assert.AreEqual(9, game.ScoreForFrame(1));&lt;br /&gt;Assert.AreEqual(18, game.ScoreForFrame(2));&lt;br /&gt;Assert.AreEqual(3, game.CurrentFrame);&lt;br /&gt;}&lt;/pre&gt;This is nice; we can see some of the usages for the game object. Now lets take a look at the approval version:&lt;pre name="code" class="c-sharp:nogutter:nocontrols"&gt;public void TestFourThrows()&lt;br /&gt;{&lt;br /&gt;game.Add(5);&lt;br /&gt;game.Add(4);&lt;br /&gt;game.Add(7);&lt;br /&gt;game.Add(2);&lt;br /&gt;Approvals.Approve(game);&lt;br /&gt;}&lt;/pre&gt;The approval line doesn’t show us any usages of game like the first example. Glancing at the code we don’t even know what we expect either. When we look at the content of the approval we see:&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:blue;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;Frame 1: 9&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="color:blue;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:blue;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;Frame 2: 18&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="color:blue;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:blue;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;Current Frame: 3&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="color:blue;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:blue;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;Total Score: 18&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;or&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:blue;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;|  1  |  2  |  3* |  Total  |&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-style-span"  style="color:blue;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:blue;"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;|  9  |  18 |     |   18  |&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This output is much more expressive and gives us an understanding of the state of the game object. It allows us to change our internal design without having to change our test code. As we move forward we may find the need to add more information to the output. We make the change, fail the approval, then look it over; if we like the new result we approve it.&lt;br /&gt;&lt;br /&gt;Those of us who push a design by writing tests first may have issues with this approach. Instead of creating assertions against primitive types for our expectation just trust the one in your head. While we code our expectations might change. Again, Approvals make it easier for us to change our code without changing the test code. As a discipline we still need to work in small units and design as we go. Our code can also skip those rare artifacts we sometimes need to create for testing. Because we've spent the time up front working out a visual for our code we can easily verify it.&lt;br /&gt;&lt;br /&gt;When it comes to pairing, this allows both developers to come up with a common representation of the result they expect. When something fails, instead of double checking if our assertions were correct, we can look at the approval and discuss the expectation as a whole. We spend more time talking about the design instead of how to test it.&lt;br /&gt;&lt;br /&gt;There are many ways to test code and they provide different solutions. Some methods push a design, some confirm them, some are used for regression testing. When you write tests, you need to decide if describing the interface is more important or the outcome. Approvals is another tool to help you write better code and get you closer to exactly what you want.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1959052963816936322-9216724152509079605?l=blog.approvaltests.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.approvaltests.com/feeds/9216724152509079605/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1959052963816936322&amp;postID=9216724152509079605' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1959052963816936322/posts/default/9216724152509079605'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1959052963816936322/posts/default/9216724152509079605'/><link rel='alternate' type='text/html' href='http://blog.approvaltests.com/2008/10/i-know-exactly-what-i-want.html' title='I know exactly what I want!'/><author><name>Dan Gilkerson</name><uri>http://www.blogger.com/profile/07672335006879942771</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='08280337458693271807'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1959052963816936322.post-231573975146652504</id><published>2008-10-14T21:38:00.000-07:00</published><updated>2008-10-15T11:52:30.804-07:00</updated><title type='text'>Approve is the new Assert</title><content type='html'>&lt;pre name="code" class="java:nogutter:nocontrols"&gt;assertEquals(5, person.age());&lt;br /&gt;assertTrue(person.isFemale());&lt;br /&gt;assertEquals("jane", person.getName());&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;Asserts are a great way of checking primitives. However, they get cumbersome when you want to assert an object. Even the above example really is asking for&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;pre name="code" class="java:nogutter:nocontrols"&gt;assertPerson(person, "jane doe, female age 5");&lt;br /&gt;&lt;/pre&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;Of course this quickly becomes a nightmare of trying to describe the person object. This is where approvals come in. &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;pre name="code" class="java:nogutter:nocontrols"&gt;Approvals.approve(person.toString());&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style=" ;font-family:verdana;"&gt;Now you can get a test with nicely formatted output&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;br /&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;Name : jane doe&lt;br /&gt;Age : 5&lt;br /&gt;Sex : Female &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;br /&gt;The more complex the object, the greater the task of writing &amp;amp; maintaining the asserts becomes. While approvals always stay the same one line: &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 255);"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;pre name="code" class="java:nogutter:nocontrols"&gt;Approvals.approve(yourObject);&lt;/pre&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style=" ;font-family:verdana;"&gt;So whether it’s a single object, a tree of objects, a Gui Component, an Html page, a pdf document, an email, etc… if you can output it to a file, you can approve it. Then you can always view that output in whatever manner you wish. So there’s no need to find a fancy way to describe a pdf: just view it in acrobat, and if it’s good approve it.&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1959052963816936322-231573975146652504?l=blog.approvaltests.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.approvaltests.com/feeds/231573975146652504/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1959052963816936322&amp;postID=231573975146652504' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1959052963816936322/posts/default/231573975146652504'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1959052963816936322/posts/default/231573975146652504'/><link rel='alternate' type='text/html' href='http://blog.approvaltests.com/2008/10/approve-is-new-assert.html' title='Approve is the new Assert'/><author><name>Llewellyn Falco</name><uri>http://www.blogger.com/profile/11668997629228826023</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='08608010092011158874'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1959052963816936322.post-7301493795673883891</id><published>2008-10-14T10:52:00.000-07:00</published><updated>2008-10-15T12:03:32.923-07:00</updated><title type='text'>Approval Tests (a pictures worth a 1000 tests) [repost]</title><content type='html'>&lt;style&gt; &lt;!--  /* Font Definitions */  @font-face  {font-family:Helvetica;  panose-1:2 11 6 4 2 2 2 2 2 4;  mso-font-charset:0;  mso-generic-font-family:swiss;  mso-font-pitch:variable;  mso-font-signature:536881799 -2147483648 8 0 511 0;} @font-face  {font-family:"Cambria Math";  panose-1:2 4 5 3 5 4 6 3 2 4;  mso-font-charset:1;  mso-generic-font-family:roman;  mso-font-format:other;  mso-font-pitch:variable;  mso-font-signature:0 0 0 0 0 0;} @font-face  {font-family:"ヒラギノ角ゴ Pro W3";  mso-font-charset:0;  mso-generic-font-family:roman;  mso-font-pitch:auto;  mso-font-signature:0 0 0 0 0 0;}  /* Style Definitions */  p.MsoNormal, li.MsoNormal, div.MsoNormal  {mso-style-unhide:no;  mso-style-qformat:yes;  mso-style-parent:"";  margin:0in;  margin-bottom:.0001pt;  mso-pagination:widow-orphan;  font-size:12.0pt;  font-family:"Times New Roman","serif";  mso-fareast-font-family:"Times New Roman";} p.HeaderFooter, li.HeaderFooter, div.HeaderFooter  {mso-style-name:"Header &amp; Footer";  mso-style-unhide:no;  mso-style-parent:"";  margin:0in;  margin-bottom:.0001pt;  mso-pagination:widow-orphan;  tab-stops:right 6.5in;  font-size:10.0pt;  font-family:"Helvetica","sans-serif";  mso-fareast-font-family:"ヒラギノ角ゴ Pro W3";  mso-bidi-font-family:"Times New Roman";  color:black;} p.Body, li.Body, div.Body  {mso-style-name:Body;  mso-style-unhide:no;  mso-style-parent:"";  margin:0in;  margin-bottom:.0001pt;  mso-pagination:widow-orphan;  font-size:12.0pt;  mso-bidi-font-size:10.0pt;  font-family:"Helvetica","sans-serif";  mso-fareast-font-family:"ヒラギノ角ゴ Pro W3";  mso-bidi-font-family:"Times New Roman";  color:black;} .MsoChpDefault  {mso-style-type:export-only;  mso-default-props:yes;  font-size:10.0pt;  mso-ansi-font-size:10.0pt;  mso-bidi-font-size:10.0pt;} @page Section1  {size:8.5in 11.0in;  margin:1.0in 1.0in 1.0in 1.0in;  mso-header-margin:.5in;  mso-footer-margin:.6in;  mso-paper-source:0;} div.Section1  {page:Section1;} --&gt; &lt;/style&gt;&lt;span style="font-size: 180%;"&gt; &lt;br /&gt;&lt;/span&gt;    &lt;br /&gt;&lt;div class="Body" style="color: #993399; font-family: arial; font-weight: bold;"&gt;&lt;span style="font-size: 180%;"&gt;Scenario 1 [Testing a User Interface]&lt;/span&gt;&lt;/div&gt;&lt;div class="Body"&gt;&lt;b&gt;Core Concept :&lt;/b&gt;&lt;/div&gt;&lt;div class="Body"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/div&gt;&lt;pre name="code" class="java:nogutter:nocontrols"&gt;Component gui = createGui();&lt;br /&gt;Approvals.approve(gui);&lt;/pre&gt;&lt;div class="Body"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/div&gt;&lt;div class="Body"&gt;This creates a snap shot of the gui:  gui.received.png&lt;/div&gt;&lt;div class="Body"&gt;This passes if gui.received.png == gui.approved.png&lt;/div&gt;&lt;div class="Body"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/div&gt;&lt;div class="Body"&gt;If you like the result, simply rename  gui.received.png -&amp;gt; gui.approved.png and the test will pass.&lt;/div&gt;&lt;div class="Body"&gt;&lt;b&gt;Could you explain that in a diagram?&lt;o:p&gt;&lt;/o:p&gt;&lt;/b&gt;&lt;/div&gt;&lt;div class="Body"&gt;yes.&lt;/div&gt;&lt;div class="Body"&gt;&lt;a href="http://1.bp.blogspot.com/_s2oZS5jFv1g/SPN27KCzUDI/AAAAAAAAAA8/W3_Rm7Nnlw8/s1600-h/Approval-Diagram.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5256675948751966258" src="http://1.bp.blogspot.com/_s2oZS5jFv1g/SPN27KCzUDI/AAAAAAAAAA8/W3_Rm7Nnlw8/s320/Approval-Diagram.png" style="cursor: pointer; display: block; margin: 0px auto 10px; text-align: center;" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;b&gt; &lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;div class="Body"&gt;&lt;b&gt;Why is this awesome?&lt;/b&gt;&lt;/div&gt;&lt;div class="Body"&gt;&lt;b&gt; &lt;/b&gt; “a picture is worth a 1000 tests”.  Ever find that your unit tests aren’t giving you enough security? Have you started making lots &amp;amp; lots of asserts? Ever find your tests test too many things and the maintenance required to change anything is actually reducing your agility?&lt;/div&gt;&lt;div class="Body"&gt;Approval Testing gives you 100% lock down on your gui, yet changes simply require a click of a button.&lt;/div&gt;&lt;div class="Body"&gt;&lt;b&gt;Where are the approved images stored?&lt;o:p&gt;&lt;/o:p&gt;&lt;/b&gt;&lt;/div&gt;&lt;div class="Body"&gt;&lt;b&gt; &lt;/b&gt;Approved images are stored in your testing folder and in your source control. This makes the test repeatable on different systems &amp;amp; you can actually browse a visual of how your gui’s have changed over time!&lt;/div&gt;&lt;div class="Body"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/div&gt;&lt;div class="Body"&gt;&lt;b&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/b&gt;&lt;/div&gt;&lt;div class="Body"&gt;&lt;b&gt;How does it work for a web app?&lt;/b&gt;&lt;/div&gt;&lt;div class="Body"&gt;&lt;b&gt; &lt;/b&gt;String html = createWebPage();&lt;/div&gt;&lt;div class="Body"&gt;Approvals.approve(html);&lt;/div&gt;&lt;div class="Body"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/div&gt;&lt;div class="Body"&gt;Instead of an image, now a text file (page.received.html) is created.&lt;/div&gt;&lt;div class="Body"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Body"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="Body" style="color: #993399; font-weight: bold;"&gt;&lt;span style="font-size: 180%;"&gt;Scenario 2 [Behavior Driven Development]&lt;/span&gt;&lt;/div&gt;&lt;div class="Body"&gt;&lt;b&gt;Core Concept :&lt;/b&gt;&lt;/div&gt;&lt;pre name="code" class="java:nogutter:nocontrols"&gt;Object myObject = createObject();&lt;br /&gt;&lt;br /&gt;/*temp*/ Approvals.approve(myObject.toString());&lt;br /&gt;doSomething1();&lt;br /&gt;/*temp*/ Approvals.approve(myObject.toString());&lt;br /&gt;doSomething2();&lt;br /&gt;/*temp*/ Approvals.approve(myObject.toString());&lt;br /&gt;doSomething3();&lt;br /&gt;/*temp*/ Approvals.approve(myObject.toString());&lt;br /&gt;doSomething4();&lt;br /&gt;/*temp*/ Approvals.approve(myObject.toString());&lt;br /&gt;doSomething5();&lt;br /&gt;Approvals.approve(myObject.toString());&lt;/pre&gt;&lt;div class="Body"&gt;As the code is created, the approval will move down, so That the final code is&lt;/div&gt;&lt;pre name="code" class="java:nogutter:nocontrols"&gt;Object myObject = createObject();&lt;br /&gt;doSomething1();&lt;br /&gt;doSomething2();&lt;br /&gt;doSomething3();&lt;br /&gt;doSomething4();&lt;br /&gt;doSomething5();&lt;br /&gt;Approvals.approve(myObject.toString());&lt;/pre&gt;&lt;div class="Body" style="font-family: courier new;"&gt;&lt;span style="font-size: 85%;"&gt; &lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="Body"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/div&gt;&lt;div class="Body"&gt;&lt;b&gt;Why is this awesome?&lt;o:p&gt;&lt;/o:p&gt;&lt;/b&gt;&lt;/div&gt;&lt;div class="Body"&gt;&lt;b&gt;            &lt;/b&gt;Many times a unit test is scattered with spot testing to assure things are done correctly. This creates a barrier to readability, and can lead to unneeded code. &lt;/div&gt;&lt;div class="Body"&gt;Approval tests reduce the need to spot check, making the test cleaner and simpler.&lt;/div&gt;&lt;div class="Body"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/div&gt;&lt;div class="Body"&gt;&lt;b&gt;What if I don’t want to change my toString?&lt;o:p&gt;&lt;/o:p&gt;&lt;/b&gt;&lt;/div&gt;&lt;div class="Body"&gt;No problem, create a toOtherString(), or a ObjectWritter, or Inspect the object. Sometimes we even create a ObjectVisualizer when an image is a better way to show the state.&lt;/div&gt;&lt;div class="Body"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/div&gt;&lt;div class="Body"&gt;&lt;b&gt;What if there’s a bug in my code?&lt;o:p&gt;&lt;/o:p&gt;&lt;/b&gt;&lt;/div&gt;&lt;div class="Body"&gt;The first thing to do is to try to walk through your code and get an idea of the state of the object, so you can see where it went wrong... if only you had a nice way of visualizing the state of your object.... oh wait! that’s the first thing you created! I guess it will be pretty easy to debug.&lt;/div&gt;&lt;div class="Body"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Body"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Body"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="Body"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/div&gt;&lt;div class="Body" style="color: #993399; font-weight: bold;"&gt;&lt;span style="font-size: 180%;"&gt;Scenario 3 [The lock down]&lt;/span&gt;&lt;/div&gt;&lt;div class="Body"&gt;&lt;b&gt;Core Concept :&lt;o:p&gt;&lt;/o:p&gt;&lt;/b&gt;&lt;/div&gt;&lt;div class="Body"&gt;Say I have a web page that displays a user profile. I want to refactor it, but I have no tests. However, I do have 300 users in my current database.&lt;/div&gt;&lt;pre name="code" class="java:nogutter:nocontrols"&gt;String allPages = getAllUserProfilePages();&lt;br /&gt;Approvals.approve(allPages);&lt;/pre&gt;&lt;div class="Body"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/div&gt;&lt;div class="Body"&gt;&lt;b&gt;Why is this awesome?&lt;o:p&gt;&lt;/o:p&gt;&lt;/b&gt;&lt;/div&gt;&lt;div class="Body"&gt;&lt;b&gt;            &lt;/b&gt;2 lines of code to completely lock down a legacy process. That is the definition of awesome!&lt;/div&gt;&lt;div class="Body"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/div&gt;&lt;div class="Body"&gt;&lt;b&gt;Won’t this test be kinda slow?&lt;o:p&gt;&lt;/o:p&gt;&lt;/b&gt;&lt;/div&gt;&lt;div class="Body"&gt;Yes. But after you are done safely refactoring, you can/should remove the tests.&lt;/div&gt;&lt;div class="Body"&gt;&lt;b&gt;Is this test data independent? Will it be repeatable tomorrow?&lt;o:p&gt;&lt;/o:p&gt;&lt;/b&gt;&lt;/div&gt;&lt;div class="Body"&gt;No. But after you are done safely refactoring, you can/should remove the tests.&lt;/div&gt;&lt;div class="Body"&gt;&lt;b&gt;Should I keep this test after the refactoring?&lt;/b&gt;&lt;/div&gt;&lt;div class="Body"&gt;No!&lt;/div&gt;&lt;div class="Body"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/div&gt;&lt;div class="Body"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1959052963816936322-7301493795673883891?l=blog.approvaltests.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.approvaltests.com/feeds/7301493795673883891/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1959052963816936322&amp;postID=7301493795673883891' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1959052963816936322/posts/default/7301493795673883891'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1959052963816936322/posts/default/7301493795673883891'/><link rel='alternate' type='text/html' href='http://blog.approvaltests.com/2008/10/approval-tests-pictures-worth-1000.html' title='Approval Tests (a pictures worth a 1000 tests) [repost]'/><author><name>Llewellyn Falco</name><uri>http://www.blogger.com/profile/11668997629228826023</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='08608010092011158874'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_s2oZS5jFv1g/SPN27KCzUDI/AAAAAAAAAA8/W3_Rm7Nnlw8/s72-c/Approval-Diagram.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1959052963816936322.post-7768083974978608986</id><published>2008-10-14T09:14:00.000-07:00</published><updated>2008-10-14T09:15:51.147-07:00</updated><title type='text'>Approve(this.blog)</title><content type='html'>We wanted a centralized place to put all of our thoughts on how to use approval tests.&lt;br /&gt;Here it is.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1959052963816936322-7768083974978608986?l=blog.approvaltests.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.approvaltests.com/feeds/7768083974978608986/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=1959052963816936322&amp;postID=7768083974978608986' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1959052963816936322/posts/default/7768083974978608986'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1959052963816936322/posts/default/7768083974978608986'/><link rel='alternate' type='text/html' href='http://blog.approvaltests.com/2008/10/approvethisblog.html' title='Approve(this.blog)'/><author><name>Llewellyn Falco</name><uri>http://www.blogger.com/profile/11668997629228826023</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='08608010092011158874'/></author><thr:total>0</thr:total></entry></feed>