{"id":573,"date":"2013-02-07T17:53:38","date_gmt":"2013-02-08T01:53:38","guid":{"rendered":"http:\/\/angryweasel.com\/blog\/?p=573"},"modified":"2013-02-07T18:18:11","modified_gmt":"2013-02-08T02:18:11","slug":"can-you-get-me-a-repro","status":"publish","type":"post","link":"https:\/\/angryweasel.com\/blog\/can-you-get-me-a-repro\/","title":{"rendered":"Can you get me a repro?"},"content":{"rendered":"<blockquote><p>&#8220;Hey \u2013 can you set up a repro of that bug for me?&#8221;<\/p><\/blockquote>\n<p>As a tester, how many times have you heard this phrase? How many times have you walked through the steps you outlined in the bug report so someone could look at an error for you? Or \u2013 how many times have you seen a test error, and immediately re-run the test to see if you could reproduce the error yourself?<\/p>\n<p>Is it a big number? If it is, you&#8217;re not going to like what I have to say. If you need to reproduce all of your bugs to figure out what&#8217;s going on, you screwed up. Your logging is bad. Your diagnostics don&#8217;t exist. You wrote crummy code. You&#8217;re wasting time!<\/p>\n<p>I sometimes see code like this:<br \/>\n<span style=\"color: blue; font-family: Consolas; font-size: 9pt; background-color: white;\">int<span style=\"color: black;\"> status = CreateSomethingCool(object);<\/span><\/span><\/p>\n<p><span style=\"color: blue; font-family: Consolas; font-size: 9pt; background-color: white;\">if<span style=\"color: black;\"> (status != COOL_SUCCESS)<\/span><\/span><\/p>\n<p><span style=\"color: black; font-family: Consolas; font-size: 9pt; background-color: white;\">{<br \/>\n<\/span><span style=\"color: black; font-family: Consolas; font-size: 9pt; background-color: white;\">\u00a0\u00a0\u00a0\u00a0<span style=\"color: blue;\">return<span style=\"color: black;\"> -1;<br \/>\n<\/span><\/span><\/span><span style=\"color: black; font-family: Consolas; font-size: 9pt; background-color: white;\">}<br \/>\n<\/span><span style=\"color: black; font-family: Consolas; font-size: 9pt; background-color: white;\">status = MakeItWayCool(object);<br \/>\n<\/span><span style=\"color: blue; font-family: Consolas; font-size: 9pt; background-color: white;\">if<span style=\"color: black;\"> (status != COOL_SUCCESS)<br \/>\n<\/span><\/span><span style=\"color: black; font-family: Consolas; font-size: 9pt; background-color: white;\">{<br \/>\n<\/span><span style=\"color: black; font-family: Consolas; font-size: 9pt; background-color: white;\">\u00a0\u00a0\u00a0\u00a0<span style=\"color: blue;\">return<span style=\"color: black;\"> -1;<br \/>\n<\/span><\/span><\/span><span style=\"color: black; font-family: Consolas; font-size: 9pt;\"><span style=\"background-color: white;\">}<\/span><br \/>\n<\/span><\/p>\n<p>The next time the test is run, Joe Tester (assuming some sort of automation around the automation) gets an email saying his test failed. Of course, Joe doesn&#8217;t have a freakin&#8217; clue why his test failed. It could have failed for either case above (assuming those are the only two failure points), so he needs to run it \u2013 perhaps under a debugger to see what happened.<\/p>\n<p>Joe writes horrible test code.<\/p>\n<p>But \u2013 Joe wants to improve, so he writes this:<\/p>\n<p><span style=\"color: blue; font-family: Consolas; font-size: 9pt; background-color: white;\">int<span style=\"color: black;\"> status = CreateSomethingCool(object);<br \/>\n<\/span><\/span><\/p>\n<p><span style=\"color: blue; font-family: Consolas; font-size: 9pt; background-color: white;\">if<span style=\"color: black;\"> (status != COOL_SUCCESS)<br \/>\n<\/span><\/span><span style=\"color: black; font-family: Consolas; font-size: 9pt; background-color: white;\">{<br \/>\n<\/span><span style=\"color: black; font-family: Consolas; font-size: 9pt; background-color: white;\">\u00a0\u00a0\u00a0\u00a0<span style=\"color: blue;\">return<span style=\"color: black;\"> -1;<br \/>\n<\/span><\/span><\/span><span style=\"color: black; font-family: Consolas; font-size: 9pt; background-color: white;\">}<br \/>\n<\/span><span style=\"color: black; font-family: Consolas; font-size: 9pt; background-color: white;\">status = MakeItWayCool(object);<br \/>\n<\/span><\/p>\n<p><span style=\"color: blue; font-family: Consolas; font-size: 9pt; background-color: white;\">if<span style=\"color: black;\"> (status != COOL_SUCCESS)<br \/>\n<\/span><\/span><span style=\"color: black; font-family: Consolas; font-size: 9pt; background-color: white;\">{<br \/>\n<\/span><span style=\"color: black; font-family: Consolas; font-size: 9pt; background-color: white;\">\u00a0\u00a0\u00a0\u00a0<span style=\"color: blue;\">return<span style=\"color: black;\"> -2;<br \/>\n<\/span><\/span><\/span><span style=\"color: black; font-family: Consolas; font-size: 9pt;\"><span style=\"background-color: white;\">}<\/span><br \/>\n<\/span><\/p>\n<p>Now Joe has different return values, but he still writes crappy code. At least now he knows why his test failed; but he doesn&#8217;t know why the <em>product<\/em> failed.<\/p>\n<p>So, I fired Joe, and hired Sally. Sally wrote this instead.<\/p>\n<p><span style=\"color: black; font-family: Consolas; font-size: 9pt; background-color: white;\">LOG(<span style=\"color: #a31515;\">&#8220;Calling CreateSomethingCool with object = %s&#8221;<span style=\"color: black;\">, object.ToString());<br \/>\n<\/span><\/span><\/span><span style=\"color: blue; font-family: Consolas; font-size: 9pt; background-color: white;\">int<span style=\"color: black;\"> status = CreateSomethingCool(object);<br \/>\n<\/span><\/span><\/p>\n<p><span style=\"color: black; font-family: Consolas; font-size: 9pt; background-color: white;\">VERIFY_COOLSUCCESS((status), <span style=\"color: #a31515;\">&#8220;CreateSomethingCool Failed. status=%d, objectData=%d&#8221;<span style=\"color: black;\">, status, DumpObject(object));<br \/>\n<\/span><\/span><\/span><\/p>\n<p><span style=\"color: black; font-family: Consolas; font-size: 9pt; background-color: white;\">LOG(<span style=\"color: #a31515;\">&#8220;Calling MakeItWayCool with object == %s&#8221;<span style=\"color: black;\">, object.ToString());<br \/>\n<\/span><\/span><\/span><span style=\"color: black; font-family: Consolas; font-size: 9pt; background-color: white;\">status = MakeItWayCool(object);<\/span><\/p>\n<p><span style=\"color: black; font-family: Consolas; font-size: 9pt;\"><span style=\"background-color: white;\">VERIFY_COOLSUCCESS((status), <span style=\"color: #a31515;\">&#8220;CreateSomethingCool Failed. status=%d, objectData=%d&#8221;<span style=\"color: black;\">, status, DumpObject(object));<\/span><\/span><\/span><br \/>\n<\/span><\/p>\n<p>To be fair, Sally&#8217;s version was a little easier to read, and contained some comments (or it would if Sally was a real person), but when her test failed, instead of needing to set up a repro, the automation system sent her this mail.<\/p>\n<p><strong>Test Failed<\/strong><\/p>\n<p><span style=\"color: black; font-family: Consolas; font-size: 9pt;\">CoolTest failed with a verify failure. Log follows:<br \/>\n<\/span><span style=\"color: black; font-family: Consolas; font-size: 9pt;\"><span style=\"background-color: white;\">Calling CreateSomethingCool with object =<\/span> LittleRedCorvette<br \/>\n<\/span><span style=\"color: black; font-family: Consolas; font-size: 9pt;\">CreateSomethingCool Failed. status=5, objectData=<br \/>\n<\/span><span style=\"color: black; font-family: Consolas; font-size: 9pt;\">\u00a0\u00a0\u00a0 Name=LittleRedCorvette<br \/>\n<\/span><span style=\"color: black; font-family: Consolas; font-size: 9pt;\">Size=0x100<br \/>\n<\/span><span style=\"color: black; font-family: Consolas; font-size: 9pt;\">Active=false<br \/>\n<\/span><span style=\"color: black; font-family: Consolas; font-size: 9pt;\">Running=false<br \/>\n<\/span><span style=\"color: black; font-family: Consolas; font-size: 9pt;\">LastError=5<br \/>\n<\/span><\/p>\n<p>Even here, there may not be enough information, but chances are that if Sally (or her teammates know that), &#8220;CoolTest is failing with object LittleRedCorvette, and it&#8217;s likely because the object was inactive and not running, and that the error code was 5&#8221;, that someone familiar with the code would know exactly where to look.<\/p>\n<p>And \u2013 in the case where Sally (or a teammate) has to hook up a debugger anyway, they should add additional debug information to the log file for the next time a similar error happens. Setting up a repro wastes time. Doing it for every issue you find is irresponsible and wasteful. Be a professional, and stop setting up repros, and start writing tests (and code) that make your job easier and make your team better.<span style=\"color: black; font-family: Consolas; font-size: 9pt;\"><br \/>\n<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>&#8220;Hey \u2013 can you set up a repro of that bug for me?&#8221; As a tester, how many times have you heard this phrase? How many times have you walked through the steps you outlined in the bug report so someone could look at an error for you? Or \u2013 how many times have you&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_kad_post_classname":"","_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[1],"tags":[],"class_list":["post-573","post","type-post","status-publish","format-standard","hentry","category-allposts"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_likes_enabled":true,"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/angryweasel.com\/blog\/wp-json\/wp\/v2\/posts\/573","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/angryweasel.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/angryweasel.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/angryweasel.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/angryweasel.com\/blog\/wp-json\/wp\/v2\/comments?post=573"}],"version-history":[{"count":0,"href":"https:\/\/angryweasel.com\/blog\/wp-json\/wp\/v2\/posts\/573\/revisions"}],"wp:attachment":[{"href":"https:\/\/angryweasel.com\/blog\/wp-json\/wp\/v2\/media?parent=573"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/angryweasel.com\/blog\/wp-json\/wp\/v2\/categories?post=573"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/angryweasel.com\/blog\/wp-json\/wp\/v2\/tags?post=573"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}