{"id":340,"date":"2011-09-07T21:15:22","date_gmt":"2011-09-08T04:15:22","guid":{"rendered":"http:\/\/angryweasel.com\/blog\/?p=340"},"modified":"2011-09-07T21:17:38","modified_gmt":"2011-09-08T04:17:38","slug":"numberz-winnerz","status":"publish","type":"post","link":"https:\/\/angryweasel.com\/blog\/numberz-winnerz\/","title":{"rendered":"Numberz Winnerz"},"content":{"rendered":"<p>Thanks everyone who played the <a href=\"http:\/\/angryweasel.com\/blog\/?p=335\" target=\"_blank\">Numberz Challenge<\/a>. I\u2019ll get the boring part out of the way first. Based on response time and completeness (and bonus points for <a href=\"http:\/\/angryweasel.com\/blog\/?p=335&amp;cpage=1#comment-8835\" target=\"_blank\">reverse engineering<\/a> the \u201cbad\u201d parts of the app), <strong>lixiong <\/strong>is the winner of either a signed copy of <a href=\"http:\/\/www.hwtsam.com\">HWTSAM<\/a> or an Amazon gift certificate. Li \u2013 email me and we\u2019ll figure out the details of the exchange. A definite honorable mention goes to Aleksander Lipski \u2013 he came up with the same conclusions as Li, and also took the time to establish some context (which is easy to forget in contrived examples such as this). Aleksander \u2013 send me an email and we can work out some sort of prize for you too.<\/p>\n<p>Thanks to everyone else for playing along and testing the app. It was nice to see a high interest level in my silly little experiment.<\/p>\n<h3>Analysis <\/h3>\n<p>For those interested in the what, why, and how of this exercise, read on.<\/p>\n<h4>The Numberz App v1<\/h4>\n<p>Brent Jensen noted that the <em>first<\/em> version of the application was quite buggy. It had several issues calculating the total. <em>I released this buggy version on purpose. <\/em>I have a bit of a distaste for testing applications that are so buggy that finding bugs is like shooting fish in a barrel \u2013 <strong><em>bugs should be hard to find. <\/em><\/strong>I think the applications we use to learn testing should be (mostly) working applications with some seeded defects that are difficult to find. Once I save up enough money for another Amazon gift certificate, I\u2019ll see if I can come up with a more difficult exercise.<\/p>\n<p>A more important point I\u2019d like to bring up is that as testers, I hope we aren\u2019t seeing apps like this as part of our day jobs. Something as broken as the first drop of this app shouldn\u2019t make it one micrometer away from the hard drive of the developer who wrote it. If the apps and functionality you see on a daily basis is this bad, your software development process is broken (IMO of course, YMMV).<\/p>\n<h4>Numberz v2 \u2013 the Bugs<\/h4>\n<p>You can dig the details out of the comments, but basically, Numberz had three notable bugs.<\/p>\n<p>The first bug was an intermittent addition error. Occasionally, the total would be one more than it should be. Some reports said that it seemed to happen about 2% of the time. Given the code, that sounds just about right. This gem was \u201c<a href=\"http:\/\/angryweasel.com\/blog\/?p=335&amp;cpage=1#comment-8835\" target=\"_blank\">hidden<\/a>\u201d in the source code.<\/p>\n<div class=\"csharpcode\">\n<pre class=\"alt\">    <span class=\"kwrd\">if<\/span> ((rand() % 50) == 0)<\/pre>\n<pre>    {<\/pre>\n<pre class=\"alt\">        total+=1;<\/pre>\n<pre>    }<\/pre>\n<\/div>\n<style type=\"text\/css\">.csharpcode, .csharpcode pre\n{\n\tfont-size: small;\n\tcolor: black;\n\tfont-family: consolas, \"Courier New\", courier, monospace;\n\tbackground-color: #ffffff;\n\t\/*white-space: pre;*\/\n}\n.csharpcode pre { margin: 0em; }\n.csharpcode .rem { color: #008000; }\n.csharpcode .kwrd { color: #0000ff; }\n.csharpcode .str { color: #006080; }\n.csharpcode .op { color: #0000c0; }\n.csharpcode .preproc { color: #cc6633; }\n.csharpcode .asp { background-color: #ffff00; }\n.csharpcode .html { color: #800000; }\n.csharpcode .attr { color: #ff0000; }\n.csharpcode .alt \n{\n\tbackground-color: #f4f4f4;\n\twidth: 100%;\n\tmargin: 0em;\n}\n.csharpcode .lnum { color: #606060; }\n<\/style>\n<p>The second bug was that the number 3 showed up slightly more often than other numbers. In 100 roles, the difference (likely) isn\u2019t statistically significant, but in larger number of roles, the delta was pronounced. <\/p>\n<p>In 10,000 rolls of 5 numbers spanning 10 digits, you\u2019d expect roughly 5000 occurrences of each digit. Most numbers had less than 5000 \u2013 mostly because the number 3 was being a hog.<\/p>\n<div class=\"csharpcode\">\n<pre class=\"alt\">        [0]    5096    <span class=\"kwrd\">int<\/span><\/pre>\n<pre>        [1]    4619    <span class=\"kwrd\">int<\/span><\/pre>\n<pre class=\"alt\">        [2]    4730    <span class=\"kwrd\">int<\/span><\/pre>\n<pre>        [3]    6842    <span class=\"kwrd\">int<\/span><\/pre>\n<pre class=\"alt\">        [4]    4513    <span class=\"kwrd\">int<\/span><\/pre>\n<pre>        [5]    5068    <span class=\"kwrd\">int<\/span><\/pre>\n<pre class=\"alt\">        [6]    4601    <span class=\"kwrd\">int<\/span><\/pre>\n<pre>        [7]    4986    <span class=\"kwrd\">int<\/span><\/pre>\n<pre class=\"alt\">        [8]    4958    <span class=\"kwrd\">int<\/span><\/pre>\n<pre>        [9]    4587    <span class=\"kwrd\">int<\/span><\/pre>\n<\/div>\n<style type=\"text\/css\">.csharpcode, .csharpcode pre\n{\n\tfont-size: small;\n\tcolor: black;\n\tfont-family: consolas, \"Courier New\", courier, monospace;\n\tbackground-color: #ffffff;\n\t\/*white-space: pre;*\/\n}\n.csharpcode pre { margin: 0em; }\n.csharpcode .rem { color: #008000; }\n.csharpcode .kwrd { color: #0000ff; }\n.csharpcode .str { color: #006080; }\n.csharpcode .op { color: #0000c0; }\n.csharpcode .preproc { color: #cc6633; }\n.csharpcode .asp { background-color: #ffff00; }\n.csharpcode .html { color: #800000; }\n.csharpcode .attr { color: #ff0000; }\n.csharpcode .alt \n{\n\tbackground-color: #f4f4f4;\n\twidth: 100%;\n\tmargin: 0em;\n}\n.csharpcode .lnum { color: #606060; }\n<\/style>\n<p><font color=\"#242626\">Based on the distribution (6842 \/ 50000), it appears that the number 3 has about a 13% chance of occurring when it <em>should<\/em> have a 10% chance of occurring. Sure enough, the pesky programmer wrote <a href=\"http:\/\/angryweasel.com\/blog\/?p=335&amp;cpage=1#comment-8833\" target=\"_blank\">this<\/a>:<\/font><\/p>\n<div class=\"csharpcode\">\n<pre class=\"alt\">        vals[i] = (rand() % 10);<\/pre>\n<pre>        <span class=\"kwrd\">if<\/span> ((rand() % 30) == 0)<\/pre>\n<pre class=\"alt\">        {<\/pre>\n<pre>            vals[i] = 3;<\/pre>\n<pre class=\"alt\">        }<\/pre>\n<pre>        total += vals[i];<\/pre>\n<\/div>\n<style type=\"text\/css\">.csharpcode, .csharpcode pre\n{\n\tfont-size: small;\n\tcolor: black;\n\tfont-family: consolas, \"Courier New\", courier, monospace;\n\tbackground-color: #ffffff;\n\t\/*white-space: pre;*\/\n}\n.csharpcode pre { margin: 0em; }\n.csharpcode .rem { color: #008000; }\n.csharpcode .kwrd { color: #0000ff; }\n.csharpcode .str { color: #006080; }\n.csharpcode .op { color: #0000c0; }\n.csharpcode .preproc { color: #cc6633; }\n.csharpcode .asp { background-color: #ffff00; }\n.csharpcode .html { color: #800000; }\n.csharpcode .attr { color: #ff0000; }\n.csharpcode .alt \n{\n\tbackground-color: #f4f4f4;\n\twidth: 100%;\n\tmargin: 0em;\n}\n.csharpcode .lnum { color: #606060; }\n<\/style>\n<p>&nbsp;<\/p>\n<p>The third bug had to do with the app not closing all the time. This one, I\u2019m afraid to say was unintentional, and is the sort of thing that occurs when one doesn\u2019t write a windows app in C for a very long time, then decides to \u201cwhip one out\u201d. For those interested in the root cause, it was a missing call to EndDialog() (win32 apps aren\u2019t dialog based by default, and I forgot the extra magic to make it actually exit when closed).<\/p>\n<h4>The Testing Challenge<\/h4>\n<p>Would you believe that I, the hater of GUI automation, wrote an automated GUI test to test the app? I thought it would be fun to write a quick test from a pure black box perspective. Staying close to my roots, I used a win32 app in C as the test app. I used Spy++ to get the control IDs and went off to the races. The entire app (minus header declarations is below). It takes about five seconds on my middle of the road dev machine to execute the 10000 iteration test (and slightly longer if I were to actually log the test results).<\/p>\n<div class=\"csharpcode\">\n<pre class=\"alt\"><span class=\"preproc\">#define<\/span> LOOPLENGTH 10000<\/pre>\n<pre>&nbsp;<\/pre>\n<pre class=\"alt\"><span class=\"kwrd\">int<\/span> values[5][LOOPLENGTH];<\/pre>\n<pre><span class=\"kwrd\">int<\/span> counts[10];<\/pre>\n<pre class=\"alt\"><span class=\"kwrd\">int<\/span> additionErrors = 0;<\/pre>\n<pre>&nbsp;<\/pre>\n<pre class=\"alt\"><span class=\"rem\">\/\/ I got the IDs of the window items I care about from spy++<\/span><\/pre>\n<pre><span class=\"kwrd\">int<\/span> numIDs[] = <\/pre>\n<pre class=\"alt\">{<\/pre>\n<pre>    0x3ea,<\/pre>\n<pre class=\"alt\">    0x3eb,<\/pre>\n<pre>    0x3ec,<\/pre>\n<pre class=\"alt\">    0x3ed,<\/pre>\n<pre>    0x3ee<\/pre>\n<pre class=\"alt\">};<\/pre>\n<pre><span class=\"kwrd\">int<\/span> resultID = 0x3ef;<\/pre>\n<pre class=\"alt\"><span class=\"kwrd\">int<\/span> buttonID = 0x3e8;<\/pre>\n<pre>&nbsp;<\/pre>\n<pre class=\"alt\">&nbsp;<\/pre>\n<pre><span class=\"kwrd\">int<\/span> APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,  <\/pre>\n<pre>                       LPTSTR lpCmdLine, <span class=\"kwrd\">int<\/span> nCmdShow)<\/pre>\n<pre class=\"alt\">{<\/pre>\n<pre>    UNREFERENCED_PARAMETER(hPrevInstance);<\/pre>\n<pre class=\"alt\">    UNREFERENCED_PARAMETER(lpCmdLine);<\/pre>\n<pre>&nbsp;<\/pre>\n<pre class=\"alt\">    HWND hwnd = FindWindow(NULL, L<span class=\"str\">\"Numberz\"<\/span>);<\/pre>\n<pre>&nbsp;<\/pre>\n<pre class=\"alt\">    <span class=\"rem\">\/\/ok - now we have all the window handles we need, the rest is (mostly) easy<\/span><\/pre>\n<pre>    ShowWindow(hwnd, nCmdShow);<\/pre>\n<pre class=\"alt\">    <span class=\"kwrd\">for<\/span> (<span class=\"kwrd\">int<\/span> loop = 0; loop &lt; LOOPLENGTH; loop++)<\/pre>\n<pre>    {<\/pre>\n<pre class=\"alt\">        SendDlgItemMessage(hwnd, buttonID, WM_LBUTTONDOWN, 0, 0);<\/pre>\n<pre>        SendDlgItemMessage(hwnd, buttonID, WM_LBUTTONUP, 0, 0);<\/pre>\n<pre class=\"alt\">        <span class=\"kwrd\">int<\/span> total = 0;<\/pre>\n<pre>        <span class=\"kwrd\">for<\/span> (<span class=\"kwrd\">int<\/span> i = 0; i &lt; 5; i++)<\/pre>\n<pre class=\"alt\">        {<\/pre>\n<pre>            <span class=\"kwrd\">int<\/span> val = GetDlgItemInt(hwnd, numIDs[i], NULL, FALSE);<\/pre>\n<pre class=\"alt\">            total +=val;<\/pre>\n<pre>            <span class=\"rem\">\/\/ fill an array with values that we can examine later<\/span><\/pre>\n<pre class=\"alt\">            values[i][loop] = val;<\/pre>\n<pre>            <span class=\"rem\">\/\/ counts may be enough<\/span><\/pre>\n<pre class=\"alt\">            counts[val]++;<\/pre>\n<pre>        }<\/pre>\n<pre class=\"alt\">        <span class=\"kwrd\">int<\/span> proposedVal = GetDlgItemInt(hwnd, resultID, NULL, FALSE);<\/pre>\n<pre>        <span class=\"kwrd\">if<\/span> (proposedVal != total)<\/pre>\n<pre class=\"alt\">        {<\/pre>\n<pre>            additionErrors++;<\/pre>\n<pre class=\"alt\">        }<\/pre>\n<pre>    }<\/pre>\n<pre class=\"alt\">    <span class=\"rem\">\/\/ logging omitted for now<\/span><\/pre>\n<pre>}<\/pre>\n<pre class=\"alt\"><\/pre>\n<\/div>\n<p>Note, that while this test app runs and obtains accurate results, it will break as soon as a single control ID changes. For a more sophisticated app, I\u2019d prefer a model that would let me get the values in a more reliable fashion. But given the context, it\u2019s a good solution.<\/p>\n<h4>But <em>real<\/em> bugs aren\u2019t seeded!?!<\/h4>\n<p>The seeded errors in the Numberz app were contrived, but that\u2019s about the best you can do in a 120 line application. However, the applications we test \u2013 and the applications we will be testing in the future, are huge complex <em>systems<\/em> where interactions and interoperability scenarios cause errors like this to exist. In many of these systems, an automated test is the only way to find these interaction bugs \u2013 but most importantly, we need to recognize <em>when<\/em> automation can help us find errors that we wouldn\u2019t be able to discover otherwise.<\/p>\n<p>Remember, as testers, our job isn\u2019t to write automated tests, <em>or<\/em> do exploratory testing; <em><strong>our job is to test.<\/strong> <\/em>Automate what is necessary in order to test efficiently, and explore where it\u2019s necessary to test effectively (which is another way of saying <em>you should automate 100% of the tests that should be automated, <\/em>and in a nutshell, is how I view test design).<\/p>\n<p>If you\u2019re interested in playing with the source code for the app or test, I put the code in <a href=\"https:\/\/github.com\/angryweasel\/My-Code\/tree\/master\/Numberz\" target=\"_blank\">my git repo<\/a> (open to the public). I didn\u2019t include make files, but those shouldn\u2019t be too hard to put together for anyone who can figure out git.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Thanks everyone who played the Numberz Challenge. I\u2019ll get the boring part out of the way first. Based on response time and completeness (and bonus points for reverse engineering the \u201cbad\u201d parts of the app), lixiong is the winner of either a signed copy of HWTSAM or an Amazon gift certificate. Li \u2013 email me&#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":false,"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-340","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\/340","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=340"}],"version-history":[{"count":0,"href":"https:\/\/angryweasel.com\/blog\/wp-json\/wp\/v2\/posts\/340\/revisions"}],"wp:attachment":[{"href":"https:\/\/angryweasel.com\/blog\/wp-json\/wp\/v2\/media?parent=340"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/angryweasel.com\/blog\/wp-json\/wp\/v2\/categories?post=340"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/angryweasel.com\/blog\/wp-json\/wp\/v2\/tags?post=340"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}