<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>I.M. Testy</title>
	<atom:link href="http://www.testingmentor.com/imtesty/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.testingmentor.com/imtesty</link>
	<description>Treatises on the practice of software testing</description>
	<lastBuildDate>Wed, 03 Feb 2010 16:12:17 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>API Testing: Testing in Layers</title>
		<link>http://www.testingmentor.com/imtesty/2010/02/02/api-testing-testing-in-layers/</link>
		<comments>http://www.testingmentor.com/imtesty/2010/02/02/api-testing-testing-in-layers/#comments</comments>
		<pubDate>Wed, 03 Feb 2010 01:08:08 +0000</pubDate>
		<dc:creator>Bj Rollison</dc:creator>
				<category><![CDATA[General Testing Topics]]></category>
		<category><![CDATA[API Testing]]></category>

		<guid isPermaLink="false">http://www.testingmentor.com/imtesty/2010/02/02/api-testing-testing-in-layers/</guid>
		<description><![CDATA[For the past few weeks my test automation class at the University of Washington has been focused on API (application programming interface) testing, or component level testing. Boris Beizer defines component level testing as “an integrated aggregate of one or more units” and that a “component can be anything from a unit to an entire [...]]]></description>
			<content:encoded><![CDATA[<p>For the past few weeks my test automation class at the University of Washington has been focused on API (application programming interface) testing, or component level testing. Boris Beizer defines <a href="http://www.faqs.org/faqs/software-eng/testing-faq/section-14.html" target="_blank">component level testing</a> as “an integrated aggregate of one or more units” and that a “component can be anything from a unit to an entire system.”</p>
<p>This seems a bit confusing at first but then we realize that a single method (or function) may be a unit, or a component, or may (although unlikely) be the ‘system.’ A collection of methods wrapped in a library or DLL that interact to meet a functional requirement is a component. Rather than a developer having to call each method individually to achieve some usually repetitive functional outcome from the library that functionality is usually exposed via a call to a single API.</p>
<p>In this situation the students are testing a public API in a single library (DLL) that calls several methods to produce a randomly generated string (outcome) based on parameterized property values. The interface is the single API call (and the property variables) in an automated test, so we might consider the DLL that contains this API as the ‘system’ under test based on Beizer’s definition of component. Also, since students don’t actually see the underlying code, API testing in this context is ‘black-box’ testing. <a href="file:///C:\Users\willro\AppData\Local\Temp\WindowsLiveWriter-429641856\supfiles13DAEC97\Untitled%5b5%5d.jpg"><img style="border-bottom: 0px; border-left: 0px; margin: 0px 0px 0px 10px; display: inline; border-top: 0px; border-right: 0px" title="clip_image001" src="http://testingmentor.com/imtesty/wp-content/uploads/2010/02/clip_image001.jpg" border="0" alt="clip_image001" width="366" height="308" align="right" /></a></p>
<p>The debate of who is responsible for API or component testing is tangential to the practice. I promote API testing because even in today’s extreme programming and TDD development lifecycle models we testers are still finding way too many ‘functional’ bugs (as opposed to behavioral bugs) during the integration and system levels of testing.</p>
<p>Also, generally (not all) software is designed and developed in layers similar to this simplified illustration. In well-designed, more easily testable projects the business logic or logical functionality is (should be) contained in classes or libraries (DLLs), and the public methods or APIs in those libraries know nothing about the user interface. and visa versa. End user inputs at the GUI are marshaled to the business logic layer via event handlers and properties (get/set accessors in C#) in different classes.</p>
<p>So, it shouldn’t be a surprise to anyone that certain categories of functional issues are more easily exposed at the API level of testing as opposed to testing through the UI. In fact, sometimes the UI properties and event handler layers in one project may actually mask some bugs in the APIs which aren’t exposed until much later when someone else uses that API in a different application or feature. The value of API testing is that a lot of functional testing can be performed very early in the project cycle, and functional testing can progress while the UI layer is unstable or in flux.</p>
<p>I sometimes think we are stuck testing from the end-user’s perspective. It seems that we often approach testing by trying to expose both behavioral type bugs and functional type bugs by testing completely through the UI. But, if we think of testing in layers the same way many products are developed then I wonder if we could better focus our test designs to target specific categories of functional bugs earlier and concentrate on behavioral issues and end-2-end customer scenarios when we have a more stable UI?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.testingmentor.com/imtesty/2010/02/02/api-testing-testing-in-layers/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Code Coverage: More Than Just a Number</title>
		<link>http://www.testingmentor.com/imtesty/2010/01/21/code-coverage-more-than-just-a-number/</link>
		<comments>http://www.testingmentor.com/imtesty/2010/01/21/code-coverage-more-than-just-a-number/#comments</comments>
		<pubDate>Fri, 22 Jan 2010 02:09:22 +0000</pubDate>
		<dc:creator>Bj Rollison</dc:creator>
				<category><![CDATA[General Testing Topics]]></category>
		<category><![CDATA[Testing Practices]]></category>
		<category><![CDATA[Code Coverage]]></category>
		<category><![CDATA[Metrics & Measures]]></category>

		<guid isPermaLink="false">http://www.testingmentor.com/imtesty/2010/01/21/code-coverage-more-than-just-a-number/</guid>
		<description><![CDATA[When I was growing up I would sometimes go down into my grandfather’s basement. He had amassed a variety of tools during his lifetime and he was an excellent wood craftsman. I wasn’t allowed to touch any of the power tools, because his rule was, “if you don’t know how to use a tool properly [...]]]></description>
			<content:encoded><![CDATA[<p>When I was growing up I would sometimes go down into my grandfather’s basement. He had amassed a variety of tools during his lifetime and he was an excellent wood craftsman. I wasn’t allowed to touch any of the power tools, because his rule was, “<strong><em>if you don’t know how to use a tool properly then you shouldn’t play with it</em></strong>.”</p>
<p>Of course, I am a bit of a hard head (even back then) and one day I started playing with the wood lathe while my grandfather was upstairs. Everything seemed to be going pretty well until I pushed the chisel in too far too fast and the wood split and went flying. One piece shattered the overhead light and the other piece ricocheted off the back of my hand leaving an nice gash. I shut off the machine and ran upstairs. After my grandmother cleaned and wrapped my hand, my grandfather made me go back downstairs and clean up the mess and stood over me with a stern look of disapproval making sure I wiped up my blood trail. After that incident, I heeded my grandfather’s advice, at least in his basement shop.</p>
<p>Anyway, with the recent discussions of code coverage around the testing blogosphere I started thinking about what was really being discussed. The discussions (as is the case with most discussions about code coverage) were not actually about the application code coverage as a tool, but more about the code coverage metric. And more specifically the discussions were about how not to assume a high measure of code coverage implies something is well tested. Interestingly enough, 2 years ago I wrote a <a href="http://www.testingmentor.com/imtesty/2009/11/13/the-code-coverage-metric-is-inversely-proportional-to-the-criticality-of-the-information-it-provides/" target="_blank">post</a> illustrating how the metric can be gamed and how the code coverage measure tells us nothing about quality or test effectiveness, but also alluded to how it might be used more effectively.</p>
<p>I thought that how the metric is sometimes misused is mostly self-evident, but then I realized that almost every time testers start talking about code coverage the discussion tends to focus on the metric. This may seem a bit harsh, but if a person&#8217;s only contribution to a conversation about code coverage is about how the metric doesn’t relate to quality or testing effectiveness then that person should not be allowed to play with hammers, and employing more complex tools such a wheel-barrows are well beyond that person&#8217;s comprehension.</p>
<p>Only thinking of code coverage as a means to get some magic number is akin to thinking “how many nails can I pound with this hammer. The metric itself is mostly irrelevant; and it is completely irrelevant if you don’t know how to interpret it in a way that helps you as a tester. Think about it this way; if we told our managers “our tests achieved 80% code coverage” some of our managers would be elated. (Of course IMHO, these types of managers are metric morons.) But, what do you think these same pointy headed number zombies would say if we told them “we ran our tests and we only missed testing 20% of the code.” I suspect they would start pacing back and forth in the room mumbling “We must run more tests, we must run more tests.”</p>
<p>When we stop thinking of code coverage as a simply measure where our only use of the tool is to try and achieve some magical number then perhaps we can start thinking about how to actually use code coverage as an effective tool to help us design tests (in under-tested or untested areas of the code), reduce potential risk, and possibly even drive quality upstream.</p>
<p>For example, one of my mentees is currently working on a project that uses just in time code coverage as a tool to evaluate how tests exercise changed code and downstream dependencies prior to checking code changes (e.g. bug fixes) back into the main tree. The initial pushback by some members of the team (including some pointy headed managers) was “code coverage doesn’t tell us about product quality” or “its too hard to achieve 80% code coverage” (although no such goal had been mentioned), and my personal favorite, “it’s too difficult to get everyone to measure coverage.” I reminded my mentee that the project is not about achieving some magic number, and in fact, it’s really not even about measuring at all. It’s about using the tool to discover information and to help us design additional functional tests at the API or component level that we might otherwise overlook to help prevent downstream regressions. In a nutshell, its about using code coverage as a defect prevention tool in this case.</p>
<p>Bottom line, code coverage is a tool! If you don’t know how to use it to improve your testing, well…</p>
]]></content:encoded>
			<wfw:commentRss>http://www.testingmentor.com/imtesty/2010/01/21/code-coverage-more-than-just-a-number/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Boundary bug hunting; sometimes it’s almost too easy!</title>
		<link>http://www.testingmentor.com/imtesty/2010/01/14/boundary-bug-hunting-sometimes-its-almost-too-easy/</link>
		<comments>http://www.testingmentor.com/imtesty/2010/01/14/boundary-bug-hunting-sometimes-its-almost-too-easy/#comments</comments>
		<pubDate>Thu, 14 Jan 2010 23:14:14 +0000</pubDate>
		<dc:creator>Bj Rollison</dc:creator>
				<category><![CDATA[General Testing Topics]]></category>
		<category><![CDATA[Testing Practices]]></category>
		<category><![CDATA[Boundary Testing]]></category>
		<category><![CDATA[Testing Techniques]]></category>

		<guid isPermaLink="false">http://www.testingmentor.com/imtesty/2010/01/14/boundary-bug-hunting-sometimes-its-almost-too-easy/</guid>
		<description><![CDATA[This past weekend I was working on a new test tool library for generating random email addresses; specifically the local address segment of an email address. I know, there are already a lot of email address generators available and this could be construed as reinventing the wheel. But I wanted to give my students in [...]]]></description>
			<content:encoded><![CDATA[<p>This past weekend I was working on a new test tool library for generating random email addresses; specifically the local address segment of an email address. I know, there are already a lot of email address generators available and this could be construed as reinventing the wheel. But I wanted to give my students in my test automation course at the University of Washington something to test at the API level. So why not have them test a test tool and learn a bit more about API level testing and how to use combinatorial analysis of the input property values to drive a data-driven automated test case. Also, having them test it means that I don’t have too!</p>
<p>Anyway, one of the tool’s properties is a character array of invalid characters for the specific email address system under test. Although the guidelines for email addresses are outlined in RFC 5322 and RFC 2821 many companies can place greater restrictions on the characters that are allowed for the local address component of an email address (the local address is the part before the ‘@’ character).</p>
<p>For example, Yahoo only allows a local address to be between 4 and 32 characters, the first character must be a letter, and only letters, numbers, underscores and only 1 period character. The Google mail local address is between 6 and 30 characters, and only allows letters, numbers, and (multiple) period characters. Hotmail and Live mail allow local address name lengths between 6 and 64 characters (64 is the maximum allowable size according to RFC 5322), and can only contain letters, numbers, periods, hyphens, and underscores.</p>
<p>Even from these few examples we can see a couple of things. First, although we are testing email addresses there is not a universal set of equivalent partitions that works in all contexts. We need to partition the test data into equivalent class subsets based on the specific domain we are testing. For example, the invalid class subset of characters for a Google local address includes the underscore character, but both Yahoo and Hotmail allow the underscore as a valid character in an email local address. (But, I will talk next week about the equivalent partitioning of this data…for now let’s get back to boundary testing!)</p>
<p>Back to my story – as I was exploring each email providers requirements in order to determine how to partition the data I discovered a interesting problem with Yahoo. Remember, the maximum length of the local address for a Yahoo account is 32 characters. <a href="http://testingmentor.com/imtesty/wp-content/uploads/2010/01/yahoomsg.jpg"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="yahoo msg" src="http://testingmentor.com/imtesty/wp-content/uploads/2010/01/yahoomsg_thumb.jpg" border="0" alt="yahoo msg" width="422" height="114" /></a></p>
<p>And, the textbox control property on the web page is set to only allow a maximum input of 32 characters to prevent the user from inputting more than 32 characters. Copying a string longer than 32 characters into that textbox simply truncates the string after the 32nd character.</p>
<p>But, when I bump up against the maximum allowable length with some test strings the underlying program that generates suggested alternative local address names will actually produce a local address of 35 characters in length!</p>
<p><a href="http://testingmentor.com/imtesty/wp-content/uploads/2010/01/yahoomsg2.jpg"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="yahoo msg 2" src="http://testingmentor.com/imtesty/wp-content/uploads/2010/01/yahoomsg2_thumb.jpg" border="0" alt="yahoo msg 2" width="426" height="110" /></a></p>
<p>Now, if the software message tells me I can’t do something (like have a local address name of more than 32 characters and then the software generates a local address name of 35 characters for me…well, I am the sort of fellow who will push that button!</p>
<p><a href="http://testingmentor.com/imtesty/wp-content/uploads/2010/01/yahoomsg3.jpg"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="yahoo msg 3" src="http://testingmentor.com/imtesty/wp-content/uploads/2010/01/yahoomsg3_thumb.jpg" border="0" alt="yahoo msg 3" width="431" height="155" /></a></p>
<p>And sure enough it looks like I can use it. But wait. Only one more button to push and…</p>
<p><a href="http://testingmentor.com/imtesty/wp-content/uploads/2010/01/yahoomsg4.jpg"><img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="yahoo msg 4" src="http://testingmentor.com/imtesty/wp-content/uploads/2010/01/yahoomsg4_thumb.jpg" border="0" alt="yahoo msg 4" width="437" height="108" /></a></p>
<p>What do you mean “Sorry, this appears to be an invalid Yahoo ID?” You generated an invalid local address for me! Why would Yahoo mail torment me so?</p>
<p>I am thinking in the developers mind the user story went sort of like;</p>
<blockquote><p><strong>User</strong>: “I would like this.”</p>
<p><strong>System</strong>: “No you can’t have that, but you can have this.”</p>
<p><strong>User</strong>: “OK”</p>
<p><strong>System</strong>: “No, you can’t have that either.”</p></blockquote>
<p>It’s funny this came up this week because I was talking with a group of senior SDETs about defect prevention versus defect detection and how 99.999% of boundary issues can be found at the unit level or API level of testing well before the UI is slapped onto the functional layer.</p>
<p>Testing the functional layer more thoroughly or a code review would most likely have revealed this ‘magic’ number was inconsistent. Or by forcing the algorithm that generates suggested local addresses to test boundary conditions would have much sooner exposed this problem.</p>
<p>Now I don’t know Yahoo’s development and testing practices, and unfortunately it&#8217;s not uncommon to overlook bugs similar to this. But, I suspect that if developer rely on testers to find all their bugs, and testers primarily rely on testing through the user interface to find bugs then we are always going to find boundary bugs post release (and that’s a good thing because it gives me something to blog about).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.testingmentor.com/imtesty/2010/01/14/boundary-bug-hunting-sometimes-its-almost-too-easy/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>API Testing &#8211; Thinking Differently About the Problem</title>
		<link>http://www.testingmentor.com/imtesty/2010/01/07/api-testing-thinking-differently-about-the-problem/</link>
		<comments>http://www.testingmentor.com/imtesty/2010/01/07/api-testing-thinking-differently-about-the-problem/#comments</comments>
		<pubDate>Thu, 07 Jan 2010 08:06:44 +0000</pubDate>
		<dc:creator>Bj Rollison</dc:creator>
				<category><![CDATA[General Testing Topics]]></category>
		<category><![CDATA[Test Automation]]></category>
		<category><![CDATA[API Testing]]></category>
		<category><![CDATA[Test Case Design]]></category>
		<category><![CDATA[Testing]]></category>

		<guid isPermaLink="false">http://www.testingmentor.com/imtesty/2010/01/07/api-testing-thinking-differently-about-the-problem/</guid>
		<description><![CDATA[Last year the University of Washington Extension Program started running a new Software Test Automation using C# program that I designed and developed for experienced testers with little or no programming background. The program is very popular and has more than 60 people waiting for the next offering. Unfortunately, the pay is not that great [...]]]></description>
			<content:encoded><![CDATA[<p>Last year the University of Washington Extension Program started running a new Software Test Automation using C# program that I designed and developed for experienced testers with little or no programming background. The program is very popular and has more than 60 people waiting for the next offering. Unfortunately, the pay is not that great so I have no intention of quitting my day job. It helps with the moorage costs for my sailboat, but the stipend I receive is not my motivation for teaching this course.</p>
<p>A few years ago I realized the industry would once again require software testers to have a richer understanding of the complete ‘systems’ they are testing, and also require testers to have a wider range of ‘testing’ skills beyond emulating user behavior in an attempt to expose as many bugs as possible before the software is released. I also realized there are many testers in the Seattle area who are good testers but simply lacked the coding skills necessary to design and develop automated test cases (that more and more companies are expecting from their testing staff).</p>
<p>So, this program is one way I can help testers in the community gain additional skills and share some ideas with my colleagues in the local community. Don’t tell the program coordinator from UW, but my real reward comes when a student tells me about how he/she was able to solve a test problem using something they learned in class. Frankly, I don’t think I am a really great teacher, but it is nice to think that in some small way I can sometimes help testers unleash their own potential to overcome challenges and succeed.</p>
<p>Anyway, the final project after the first 10 weeks of the course is to design automated tests of  3 simple API methods from a ‘black box’ perspective (e.g. they had to design a test that called the API method in a DLL). Each method required one or more argument variables to be passed to the method’s parameters when it was called in the automated test case, and each method returned a type (bool, int, and string) that had to be checked against the expected result based on the variables used in the test. The final project also introduces data-driven automation concepts. The focus of the project was to reinforce the programming concepts and skills they learned over the previous 9 weeks and put that knowledge and skill to use in a reasonably realistic testing project.</p>
<p>I am a big fan of API testing, and at Microsoft we do a lot of API testing and I would venture to say that a significant portion of our test automation runs below the UI layer banging away at various APIs. If API is broken…well it’s that whole “lipstick on a pig” thing; you might mask it for awhile, but it is still a pig and eventually the lipstick wears off.</p>
<p>Prior to the project I try to set the stage by telling everyone that the key to data-driven testing is dependent on the test data crafted by the tester. If the test data is insufficient you potentially miss a critical error. If the data is wrong then you are likely to throw a false positive; an error or exception thrown by the test and not by the system under test (or API method in this case). If a C# method parameter takes an intrinsic data type of int (Integer32) then trying to pass a string variable into the test case from a test data file to that parameter will throw an exception in the test code well before it makes the call to the API method being tested.</p>
<p>For example, the simplified sample test case below is testing a simple API static method ConvertValueToUnicodeChar(int value) that takes a integer value and converts it to a UTF-16 Unicode character. If the integer value is outside the UTF-16 range (0 through 65535) the method ConvertValueToUnicodeChar(int value) will throw an ArgumentOutOfRangeException.</p>
<div id="codeSnippetWrapper" style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; width: 97.5%; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; cursor: text; border: silver 1px solid; padding: 4px;">
<div id="codeSnippet" style="text-align: left; line-height: 12pt; background-color: #f4f4f4; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;">
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum1" style="color: #606060">   1:</span> <span style="color: #008000">// &lt;copyright file="simpletestcase.cs" company="TestingMentor"&gt; </span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum2" style="color: #606060">   2:</span>  <span style="color: #008000">// Copyright © 2009 by Bj Rollison. All rights reserved. </span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum3" style="color: #606060">   3:</span>  <span style="color: #008000">// &lt;/copyright&gt; </span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum4" style="color: #606060">   4:</span> </pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum5" style="color: #606060">   5:</span> <span style="color: #0000ff">namespace</span> TestingMentor.Sample</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum6" style="color: #606060">   6:</span> {</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum7" style="color: #606060">   7:</span>   <span style="color: #0000ff">using</span> System;</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum8" style="color: #606060">   8:</span>   <span style="color: #0000ff">using</span> System.IO;</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum9" style="color: #606060">   9:</span>   <span style="color: #0000ff">using</span> TestingMentor.Simulation;</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum10" style="color: #606060">  10:</span> </pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum11" style="color: #606060">  11:</span>   <span style="color: #0000ff">class</span> TestCase</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum12" style="color: #606060">  12:</span>   {</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum13" style="color: #606060">  13:</span>     <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> Main(<span style="color: #0000ff">string</span>[] args)</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum14" style="color: #606060">  14:</span>     {</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum15" style="color: #606060">  15:</span>       <span style="color: #0000ff">int</span> testCounter = 0;</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum16" style="color: #606060">  16:</span>       <span style="color: #008000">// Read in an array of strings representing the test data. </span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum17" style="color: #606060">  17:</span>       <span style="color: #008000">// Of course this would likely come from a static test data file</span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum18" style="color: #606060">  18:</span>       <span style="color: #008000">// on a server or copied to a folder on the local machine</span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum19" style="color: #606060">  19:</span>       <span style="color: #0000ff">string</span>[] testData = <span style="color: #0000ff">new</span> <span style="color: #0000ff">string</span>[]</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum20" style="color: #606060">  20:</span>       { <span style="color: #006080">"90,Z"</span>,</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum21" style="color: #606060">  21:</span>         <span style="color: #006080">"24798,惞"</span>,</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum22" style="color: #606060">  22:</span>         <span style="color: #006080">"0,null"</span>,</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum23" style="color: #606060">  23:</span>         <span style="color: #006080">"65536,Error"</span>,</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum24" style="color: #606060">  24:</span>         <span style="color: #006080">"-1,Error"</span>,</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum25" style="color: #606060">  25:</span>         <span style="color: #006080">"1.5,"</span>,</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum26" style="color: #606060">  26:</span>         <span style="color: #006080">"xyz,xyz"</span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum27" style="color: #606060">  27:</span>       };</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum28" style="color: #606060">  28:</span> </pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum29" style="color: #606060">  29:</span>       <span style="color: #008000">// Loop through each test data string</span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum30" style="color: #606060">  30:</span>       <span style="color: #0000ff">foreach</span> (<span style="color: #0000ff">string</span> test <span style="color: #0000ff">in</span> testData)</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum31" style="color: #606060">  31:</span>       {</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum32" style="color: #606060">  32:</span>         testCounter++;</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum33" style="color: #606060">  33:</span>         <span style="color: #008000">// This nested try/catch block catches invalid test data</span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum34" style="color: #606060">  34:</span>         <span style="color: #008000">// but allow additonal tests in the testData array</span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum35" style="color: #606060">  35:</span>         <span style="color: #0000ff">try</span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum36" style="color: #606060">  36:</span>         {</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum37" style="color: #606060">  37:</span>           <span style="color: #008000">// Parse each string into the test data and expected result</span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum38" style="color: #606060">  38:</span>           <span style="color: #0000ff">string</span>[] testElement = test.Split(<span style="color: #006080">','</span>);</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum39" style="color: #606060">  39:</span>           <span style="color: #0000ff">string</span> expectedResult = testElement[1];</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum40" style="color: #606060">  40:</span>           <span style="color: #0000ff">string</span> actualResult = String.Empty;</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum41" style="color: #606060">  41:</span> </pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum42" style="color: #606060">  42:</span>           <span style="color: #008000">// Convert the string to a type int value</span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum43" style="color: #606060">  43:</span>           <span style="color: #0000ff">int</span> <span style="color: #0000ff">value</span> = <span style="color: #0000ff">int</span>.Parse(testElement[0]);</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum44" style="color: #606060">  44:</span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum45" style="color: #606060">  45:</span>           <span style="color: #008000">// We need a way to handle int values 0 through 32 which are </span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum46" style="color: #606060">  46:</span>           <span style="color: #008000">// control characters, this is an example of how to deal with </span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum47" style="color: #606060">  47:</span>           <span style="color: #008000">// a int value of 0 which is a null character</span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum48" style="color: #606060">  48:</span>           <span style="color: #0000ff">if</span> (expectedResult.Equals(<span style="color: #006080">"null"</span>, StringComparison.OrdinalIgnoreCase))</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum49" style="color: #606060">  49:</span>           {</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum50" style="color: #606060">  50:</span>             expectedResult = <span style="color: #006080">'\0'</span>.ToString();</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum51" style="color: #606060">  51:</span>           }</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum52" style="color: #606060">  52:</span> </pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum53" style="color: #606060">  53:</span>           <span style="color: #008000">// This nested try/catch block tests catches exceptions thrown by </span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum54" style="color: #606060">  54:</span>           <span style="color: #008000">// the method under test. If the method under test throws an </span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum55" style="color: #606060">  55:</span>           <span style="color: #008000">// exception we certainly want to test for that case!</span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum56" style="color: #606060">  56:</span>           <span style="color: #0000ff">try</span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum57" style="color: #606060">  57:</span>           {</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum58" style="color: #606060">  58:</span>             <span style="color: #008000">// Call the API method under test </span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum59" style="color: #606060">  59:</span>             <span style="color: #0000ff">char</span> result = Converter.ConvertValueToUnicodeChar(<span style="color: #0000ff">value</span>);</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum60" style="color: #606060">  60:</span>             actualResult = result.ToString();</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum61" style="color: #606060">  61:</span>           }</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum62" style="color: #606060">  62:</span> </pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum63" style="color: #606060">  63:</span>           <span style="color: #0000ff">catch</span> (ArgumentOutOfRangeException)</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum64" style="color: #606060">  64:</span>           {</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum65" style="color: #606060">  65:</span>             actualResult = <span style="color: #006080">"Error"</span>;</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum66" style="color: #606060">  66:</span>           }</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum67" style="color: #606060">  67:</span> </pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum68" style="color: #606060">  68:</span>           <span style="color: #0000ff">catch</span> (Exception)</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum69" style="color: #606060">  69:</span>           {</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum70" style="color: #606060">  70:</span>             <span style="color: #008000">// if this happens this is a failure because the documentation</span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum71" style="color: #606060">  71:</span>             <span style="color: #008000">// states that this method will only throw an </span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum72" style="color: #606060">  72:</span>             <span style="color: #008000">// ArgumentOutOfRangeException.</span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum73" style="color: #606060">  73:</span>             actualResult = <span style="color: #006080">"Non-specific or unexpected error thrown"</span>;</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum74" style="color: #606060">  74:</span>           }</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum75" style="color: #606060">  75:</span> </pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum76" style="color: #606060">  76:</span>           <span style="color: #008000">// Call a simple oracle and log results</span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum77" style="color: #606060">  77:</span>           <span style="color: #0000ff">if</span> (String.Equals(actualResult, expectedResult))</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum78" style="color: #606060">  78:</span>           {</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum79" style="color: #606060">  79:</span>             <span style="color: #008000">// log pass</span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum80" style="color: #606060">  80:</span>             Console.WriteLine(<span style="color: #006080">"{0} Pass"</span>, testCounter);</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum81" style="color: #606060">  81:</span>           }</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum82" style="color: #606060">  82:</span>           <span style="color: #0000ff">else</span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum83" style="color: #606060">  83:</span>           {</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum84" style="color: #606060">  84:</span>             <span style="color: #008000">// log fail...of course log as much detail as possible</span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum85" style="color: #606060">  85:</span>             Console.WriteLine(<span style="color: #006080">"{0} Fail"</span>, testCounter);</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum86" style="color: #606060">  86:</span>           }</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum87" style="color: #606060">  87:</span>         }</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum88" style="color: #606060">  88:</span> </pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum89" style="color: #606060">  89:</span>         <span style="color: #0000ff">catch</span> (FormatException)</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum90" style="color: #606060">  90:</span>         {</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum91" style="color: #606060">  91:</span>           <span style="color: #008000">// log the test data for this test as incorrect, test is skipped</span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum92" style="color: #606060">  92:</span>           Console.WriteLine(<span style="color: #006080">"{0} Bad test data. Test skipped."</span>, testCounter);</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum93" style="color: #606060">  93:</span>         }</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum94" style="color: #606060">  94:</span>       }</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum95" style="color: #606060">  95:</span>     }</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum96" style="color: #606060">  96:</span>   }</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum97" style="color: #606060">  97:</span> }</pre>
<p><!--CRLF--></div>
</div>
<p>Instead of reading in test data from a file I simply created a string array called csvTestData to simulate a partial list of test data that might be contained in our csv formatted test data file. Notice that the test data on lines #25 and #26 are invalid integer types. So, when these test data variables are converted from strings to type int values in line #43 the int.Parse method will throw a FormatException which is caught by the outer catch block on line #89, marked as bad data and the oracle is skipped. Of course, we want to test the integer values that represent the physical boundaries for a UTF-16 char in C# (which are 0 and 65535) and the values immediately above and below those values (e.g. –1, 0, 1, 65534, 65535, and 65536). Then of course, we need to determine how many samples from the population of possible input variables (integer values between 0 and 65535) we need to test to attain a reasonable degree of confidence that the API method would return the correct UTF-6 Unicode character for a given integer value. (or in this case the population of test data is relatively small and we could simply run through all 65536 values because it would only take a minute or two).</p>
<p>Unfortunately, some of the test data files submitted in the final project contained invalid test data for the API method being called. In some test cases the parameter type required was a type int, but the test data read in from the file for that parameter was a real number such as 1.5, or a string such as “xyz” similar to the example above. I asked myself why would someone include these variables in a test that are being passed to a parameter of type int? The only thing I can think of is that when these testers designed their test data files, they were thinking about the problem as if they were testing the API method through a user interface. (And, in fact my suspicion was confirmed later when I asked them.)</p>
<p>The bottom line here is that we often times throw a lot of ‘tests’ or a lot of data at something in an attempt to trigger an unexpected error. Sometimes we are successful, and hopefully we document that information and share it with others so we can all learn. But, a lot of times it seems we can’t see the trees because of the forest and execute tests or include test data in our tests just for the sake of physical activity. I sometimes wonder whether or not it matters to think critically about the problem, analyze the situation, and design well-thought out tests, or is simply throwing stuff against the wall and seeing what sticks good enough testing?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.testingmentor.com/imtesty/2010/01/07/api-testing-thinking-differently-about-the-problem/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Thinking About Critical Thinking And Test Design</title>
		<link>http://www.testingmentor.com/imtesty/2009/12/29/thinking-about-critical-thinking-and-test-design/</link>
		<comments>http://www.testingmentor.com/imtesty/2009/12/29/thinking-about-critical-thinking-and-test-design/#comments</comments>
		<pubDate>Tue, 29 Dec 2009 22:04:46 +0000</pubDate>
		<dc:creator>Bj Rollison</dc:creator>
				<category><![CDATA[General Testing Topics]]></category>
		<category><![CDATA[Test Case Design]]></category>

		<guid isPermaLink="false">http://www.testingmentor.com/imtesty/2009/12/29/thinking-about-critical-thinking-and-test-design/</guid>
		<description><![CDATA[Did you ever notice that when you ask someone to test something the first thing they do is to start ‘testing?’
I often see this in my classes and I ask the person, “what is the purpose of your test?” Typically the response is, “I’m testing this,” or “I’m trying to find a bug.”
Unfortunately this seems [...]]]></description>
			<content:encoded><![CDATA[<p>Did you ever notice that when you ask someone to test something the first thing they do is to start ‘testing?’</p>
<p>I often see this in my classes and I ask the person, “what is the purpose of your test?” Typically the response is, “I’m testing this,” or “I’m trying to find a bug.”</p>
<p>Unfortunately this seems to indicate there is no or very little pre-thought that goes into the act of software testing. To some people, testing appears to be little more than simply pounding away at the keyboard and trying whatever flies into our subconscious mind as we interact with the software and declare a bug when we stumble upon unexpected behavior or see something we might disagree with.</p>
<p>This is why I found it especially interesting in my own <a href="http://www.testingmentor.com/imtesty/2009/12/10/evaluating-exploratory-testing/" target="_blank">research, and the case studies</a> by <a href="http://www.soberit.hut.fi/jitkonen/" target="_blank">Juha Itkonen</a> that testers who were trained in formal software testing techniques or patterns there was no significant difference in terms of defect rates or coverage between pre-defined test cases and an exploratory testing approach. This is not to say that one approach to testing is preferred over the other. It is not an either or proposition as I explained in my <a href="http://www.testingmentor.com/imtesty/2009/11/19/the-pesticide-paradox/" target="_blank">post on the pesticide paradox</a>, and there are certainly more than 2 approaches to software testing. Testing requires multiple approaches to most effectively aid us in collecting and presenting the appropriate information to the decision makers.</p>
<p>But, I am often puzzled that it seems we can easily think of negative or destructive tests once we have the product in hand, yet when we are designing a set of tests from the requirements the tests simply test the requirements and little else. I wonder why it is that we can think of ‘tests’ while executing other tests, but we can’t think of those same tests before hand. Is there some limitation in our psyche that prevents us from analyzing a problem until we are actually faced with the problem (software in hand)?</p>
<p>I don’t think so, but I suspect there is a mental hurdle in that we sometimes feel more productive when we are interacting with software as opposed to sitting back and analyzing the problem more prior to executing well-designed test cases. (<em><strong>More tests doesn’t equal better testing!</strong></em>)</p>
<p>The bottom line is that if we are given a set of requirements and can only design tests that only test the requirements, then we are probably not thinking critically about how to design test cases.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.testingmentor.com/imtesty/2009/12/29/thinking-about-critical-thinking-and-test-design/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Random Test Data &#8211; Credit Card Numbers</title>
		<link>http://www.testingmentor.com/imtesty/2009/12/18/random-test-data-credit-card-numbers/</link>
		<comments>http://www.testingmentor.com/imtesty/2009/12/18/random-test-data-credit-card-numbers/#comments</comments>
		<pubDate>Fri, 18 Dec 2009 08:32:37 +0000</pubDate>
		<dc:creator>Bj Rollison</dc:creator>
				<category><![CDATA[Test Automation]]></category>
		<category><![CDATA[Random Test Data Generation]]></category>

		<guid isPermaLink="false">http://www.testingmentor.com/imtesty/2009/12/18/random-test-data-credit-card-numbers/</guid>
		<description><![CDATA[Things are winding down for the year. The Christmas lights are up on the house, my gardens are tilled and mulched for next spring, people are disappearing from the office like there is a plague, it hasn’t snowed in a while which means the mountains are mostly ice (I dislike skiing on ice), the next [...]]]></description>
			<content:encoded><![CDATA[<p>Things are winding down for the year. The Christmas lights are up on the house, my gardens are tilled and mulched for next spring, people are disappearing from the office like there is a plague, it hasn’t snowed in a while which means the mountains are mostly ice (I dislike skiing on ice), the next GSHL ice hockey league doesn’t start for awhile and pick up games are few and far between (I suck at hockey but it is fun). So, what to do? Oh…I forgot Christmas shopping. I hate Christmas shopping! So, I have spent the past few idle nights refactoring the automation libraries for some of my test data generation tools after my daughter goes to bed. </p>
<p>One of the most popular random test data generators that I have developed so far has been a tool called <a href="http://www.testingmentor.com/tools/default.htm" target="_blank">CCMaker</a> to generate random valid and invalid credit card numbers. (<em>Sometimes I wonder why that is, but I don’t dwell on it for too long and I haven’t been interrogated by the FBI lately.</em>) Testing forms that require a credit card has always been risky business because you certainly don’t want to use your own card. Often times developers will include a check on web forms or client apps to do a high level verification of a credit card number before sending all the data across the wire to be validated. This early or high level verification prevents flooding the pipe with bad data. So, one test we can do prior to testing the end-to-end scenario is to test to see if and how the developer is validating credit cards numbers prior to submission.</p>
<p>As far as data goes, generating credit card numbers are fairly simple. There is a bank ID number (BIN), there is a number of digits between 12 and 19 depending on the card type, and there is a checksum. So, if we know the valid BINs for each issuing bank, the valid number of digits for each card type, and how to calculate the checksum we can generate valid credit card numbers. (<em>Of course this is a bit oversimplified because many credit and debit card companies are issued multiple BINs and use varying number lengths</em>.)</p>
<p>Testing for invalid credit card numbers should include using numbers that look close to being correct in some way but are slightly altered. For example for the 3 defined equivalent partitions (BIN, length, checksum) there are seven possible invalid combinations (2<sup>3</sup> – 1) we could test.</p>
<ol>
<li>Valid BIN, invalid length and valid checksum </li>
<li>Valid BIN, valid length, and invalid checksum </li>
<li>Valid BIN, invalid length, and invalid checksum </li>
<li>Invalid BIN, valid length and valid checksum </li>
<li>Invalid BIN, invalid length, and valid checksum </li>
<li>Invalid BIN, valid length, and invalid checksum </li>
<li>Invalid BIN, checksum and length </li>
</ol>
<p>This doesn’t mean I run 7 tests and call it good because there are numerous invalid lengths and invalid BINs for the different card types. A common mistake when using an equivalent partition testing approach is to simply plug in values for each combination listed above and call it good. The problem is that there are several hundred BINs and 8 different valid lengths. For example, for just the Discover card there are 829 valid BIN numbers, and for the Maestro cards there are 56 combinations of BINs and card lengths ranging from 12 to 19 numbers in length. This doesn’t include the permutations of the other numbers that compose the entire card number. </p>
<p>The question every tester must ask him or herself every day when designing tests is how many tests do I need to have any reasonable sense of confidence that risk is minimal and the perception of quality is high. Of course, there is no single right answer here and not magic formula, but since we can’t possibly execute every possible positive or negative test we should at least understand that ultimately <a href="http://www.testingmentor.com/imtesty/2009/11/18/testing-is-sampling/" target="_blank">testing is sampling</a>.</p>
<p>For example, one strategy for positive testing might be to test every valid BIN for every valid card length for any given credit card. For example for American Express I would want to test at least one number with a BIN of 34 and a card length of 15 that satisfies the checksum requirement, and at least one number with a BIN of 37 and a card length of 15 that also satisfies the checksum requirement. For a card type of Visa I would need a minimum of 2 tests in which the BIN is 4, the checksum requirement is satisfied, and one has a card length of&#160; 13 numbers and the other has a card length of 16 numbers. </p>
<p>That probably sounds like quite a bit of testing, and tests which most likely would not produce an error (unless of course the BIN is miss identified (e.g. instead of checking for a BIN of 5020 the BIN is incorrectly assigned as 5002), or if a valid BIN is not recognized as valid because it is omitted from a list or enumeration of valid BINs for that credit card). Certainly testing of this magnitude would be expensive if done manually. But when automated using a random test data generator and a data-driven automation approach to set the random generator properties comprehensive testing becomes a much more reasonable proposition and can significantly increase overall confidence.</p>
<p>This is where my CCMaker 3.1 test data generator can help by randomly generating both valid and invalid credit card numbers. The updated <a href="http://www.testingmentor.com/automation/sdk/ccmaker.htm" target="_blank">CCMaker test automation library</a> has just been posted to <a href="http://www.testingmentor.com/" target="_blank">my web site</a> with documentation and examples. If you have any questions, or find any issues with the new library please let me know.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.testingmentor.com/imtesty/2009/12/18/random-test-data-credit-card-numbers/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Evaluating Exploratory Testing</title>
		<link>http://www.testingmentor.com/imtesty/2009/12/10/evaluating-exploratory-testing/</link>
		<comments>http://www.testingmentor.com/imtesty/2009/12/10/evaluating-exploratory-testing/#comments</comments>
		<pubDate>Thu, 10 Dec 2009 21:03:54 +0000</pubDate>
		<dc:creator>Bj Rollison</dc:creator>
				<category><![CDATA[Testing Practices]]></category>
		<category><![CDATA[Exploratory Testing]]></category>

		<guid isPermaLink="false">http://testingmentor.com/imtesty/2009/12/10/evaluating-exploratory-testing/</guid>
		<description><![CDATA[This month’s issue of Testing Experience published my article that summarizes the findings of several case studies of exploratory testing both inside and outside of Microsoft. Although some people consider me to be a harsh critic of exploratory testing nothing could be further from the truth. When I started my career as a professional tester [...]]]></description>
			<content:encoded><![CDATA[<p>This month’s issue of <a href="http://testingexperience.com/testingexperience04_09.pdf" target="_blank">Testing Experience</a> published my article that summarizes the findings of several case studies of exploratory testing both inside and outside of Microsoft. Although some people consider me to be a harsh critic of exploratory testing nothing could be further from the truth. When I started my career as a professional tester my approach to software testing was primarily exploratory in nature. I was focused on executing as many negative tests I could possibly conceive of in search of the most heinous bugs I could find; and I was good at it. My criticism is not of exploratory testing as an approach; however, I do ‘question’ the claim that claim exploratory testing is “orders of magnitude more productive.” And, I am also critical of the argument that we don’t understand exploratory testing if we don’t conform to one notion of the concept (or buy into an ideological doctrine) because I don’t believe that there is only one ‘right’ way to perform or think about exploratory testing.</p>
<p>Of course, I know it is un-unpopular to question the claims of exploratory testing ‘experts,’ but I just happen to be one of those people who question things that are founded on anecdotal observations without any hard data to substantiate those claims. I certainly don’t have all the information, but I personally like to be able to back up my position with facts (known at the time) and several verifiable/repeatable data points so I can answer questions from a defendable position rather than trying to convince or cajole someone with my subjective opinion. (<em>I know a lot of studies show that many Americans base their decisions on their emotional state at the time. But I learned a long time ago that you should never buy the boat you fall in love with because you will spend more time maintaining her than sailing her</em>.) Also, it’s easier to persuade me that I might be wrong with solid, verifiable information and repeatable data versus emotional rhetoric or personal insults.</p>
<p>I think most people who promote exploratory testing are well intentioned and realize in conjunction with other testing approaches that exploratory testing adds value to any testing effort. I also think that many practitioners realize that while we must not only hone our intellectual capabilities of critical thinking and logical reasoning, we must also constantly build our knowledge and skills of the other approaches, methods, and techniques used in our professional trade.</p>
<p>At Microsoft, I can’t think of any testing group that does not use exploratory testing as part of its overall strategy. We have learned not to rely on exploratory testing as our primary approach because it simply doesn&#8217;t scale as project size and complexity increase, and it is easy for testers to focus too much on out of context issues in hopes of finding another bug. As one Principal Test Manager summarized, exploratory testing helps</p>
<ul>
<li>flush out “low hanging fruit” (identify obvious issues very quickly)</li>
<li>provide welcomed context switching by getting folks to look at other areas of the product</li>
<li>to seed new testing ideas or helps identify holes (<em>which is great as long as we have a way to preserve those ideas and they are learnable by other testers</em>)</li>
</ul>
<p>But, of course, it was also noted that greater ‘system knowledge’ and an understanding of other various testing techniques and approaches enriched the overall effectiveness of the testers on the teams. My job as a teacher and mentor of software testing is to take really smart people who already know how to think critically about problems and provide them with the foundational knowledge of alternative techniques, methods, approaches, and the skills that are specific to the profession of software testing that will enable them to decide what approach to use depending on the context.</p>
<p>Similar to other testing approaches exploratory testing has benefits and limitations and is more effective in exposing certain categories of issues, and is less effective at exposing other types of problems. (See post on <a href="http://testingmentor.com/imtesty/2009/11/19/the-pesticide-paradox/" target="_blank">Pesticide Paradox</a>.) And now we have researched case studies that begin to help us understand how to utilize exploratory testing as part of our overall testing strategy. Of course, further research could be done in this area, but it is very interesting that the independent studies used in the article reached similar findings and conclusions.</p>
<p>Anyway, I look forward to comments or feedback on the article.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.testingmentor.com/imtesty/2009/12/10/evaluating-exploratory-testing/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Refactoring for Testability</title>
		<link>http://www.testingmentor.com/imtesty/2009/12/02/refactoring-for-testability/</link>
		<comments>http://www.testingmentor.com/imtesty/2009/12/02/refactoring-for-testability/#comments</comments>
		<pubDate>Wed, 02 Dec 2009 20:35:24 +0000</pubDate>
		<dc:creator>Bj Rollison</dc:creator>
				<category><![CDATA[Testing Practices]]></category>
		<category><![CDATA[Code Coverage]]></category>
		<category><![CDATA[Testability]]></category>
		<category><![CDATA[White Box Testing]]></category>

		<guid isPermaLink="false">http://testingmentor.com/imtesty/2009/12/02/refactoring-for-testability/</guid>
		<description><![CDATA[ 

One of my hobbies is shooting CMP matches and long range precision shooting. Besides lots of practice perfecting the techniques a big part of precision shooting depends on the ammunition and studying the ballistic patterns of various loads. All precision shooters custom load their ammunition and it is not as simple as simply reading a [...]]]></description>
			<content:encoded><![CDATA[<p> </p>
<div class="mceTemp">
<div id="attachment_255" class="wp-caption alignleft" style="width: 209px"><img class="size-medium wp-image-255 " style="margin-left: 5px; margin-right: 5px;" title="DSC_1276" src="http://testingmentor.com/imtesty/wp-content/uploads/2009/12/DSC_1276-199x300.jpg" alt="Teaching my daughter about bullet seating depth." width="199" height="300" /><p class="wp-caption-text">Teaching my daughter about bullet seating depth.</p></div>
<p>One of my hobbies is shooting <a href="http://odcmp.com/">CMP matches</a> and long range precision shooting. Besides lots of practice perfecting the techniques a big part of precision shooting depends on the ammunition and studying the ballistic patterns of various loads. All precision shooters custom load their ammunition and it is not as simple as simply reading a reloading manual. Slight variations of .001” of an inch in seating depth of a bullet or .1 grain of powder may determine whether the group of shots at a target 600 yards away is 1” MOA or 6” MOA. So, getting the ammunition to match the rifle requires continually analyzing your shots, making slight adjustments to the load, and repeating; in computer jargon we might call that refactoring. Reloading for precision is a continually optimizing process until we find the optimal load. Similarly, one of the things we do in the Engineering Excellence group at Microsoft is to continually analyze our internal processes and practices to see how we can help our business groups constantly improve and optimize towards their target. One of the big things on our plate these days is testability.</div>
<p>In <a href="http://www.amazon.com/Testing-Object-Oriented-Systems-Models-Patterns/dp/0201809389%3FSubscriptionId%3D0JTCV5ZMHMF7ZYTXGFR2%26tag%3Dbrdicr-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D0201809389">Testing Object-Oriented Systems: Models, Patterns, and Tools</a>, a book I consider one of the most important books on software testing practices, the author Robert Binder defines testability as “The relative ease or difficulty of producing and executing an economically feasible test suite to determine whether the [system under test ] SUT (i) conforms to stated requirements and specifications, and (ii) exhibits an acceptably low probability of failure.” This and several definitions of testability floating around on the web and all generally agree that testability generally involves</p>
<p>1.) The ease with which the SUT can be tested<br />
2.) The cost of testing is reasonable</p>
<p>So, as the testability increases the ease with which our tests can determine whether the SUT satisfies implicit and explicit requirements and has a lower chance of failure at reduced testing costs. This all sounds nice, but unfortunately testability cannot be directly measured; testability is a qualitative measure. Although we can’t accurately measure testability we can sometimes do small things to improve the characteristics of testability and help reduce testing costs by reducing the number of tests required to determine whether the SUT satisfies the stated requirements and also has a low chance of failure, or finding ways to test more efficiently through better designs.</p>
<p>In last week’s post I referred a pseudo code example that was written to illustrate how bugs could linger in code despite a high measure of code coverage. Of course we should realize that pseudo code is generally a far cry from the real implementation of the code. Pseudo code is simply a model, and there are many ways to implement that model. The advantage of a model is that we can often test a model earlier to identify potential issues before a single line of code is written. In this particular pseudo code sample, there were a couple of things that stood out that could likely impact the testability of an implementation of the pseudo code model. So, the neurons in my brain starting firing with lots of testing related questions.</p>
<p>So, let’s use that example to discuss potential testability issues. The sample was based on a requirement that stated “Student ID’ are seven digit numbers between one million and 6 million inclusive.” The function is relatively simple in that it takes a string type passed to the <em>sid</em> parameter, and returns a Boolean true or false to the calling function depending on whether the string satisfies the internal Boolean conditions it is being compared against. But this function also calls 2 other functions; the <em>length</em> () function, and the <em>number</em> () function. From the function names I would think the <em>length</em> () function provides a numeric value that represents the number of characters in the string passed to the <em>sid</em> parameter. I am also betting the <em>number</em> () function returns a numeric value (it converts the string variable to a numeric type such as an integer. The pseudo code example was</p>
<blockquote><p>function validate_studentid(string sid) return<br />
TRUEFALSE<br />
BEGIN<br />
  STATIC TRUEFALSE isOk;<br />
  isOk = true;</p>
<p>  if ((length(sid) is not 7) then<br />
    isOk = False;</p>
<p>  if (number(sid) &lt;= 1000000 or number(sid) &gt; 6000000 then<br />
     isOk = False;</p>
<p>  return isOk;</p>
<p>END</p></blockquote>
<p>One of the reasons that we hire testers with a programming background at Microsoft is that they can help the developer identify potential issues, reduce the probability of failure, and improve testability by stepping through the code during peer reviews, or while designing additional tests to cover un-tested or under-tested areas of the code that are exposed by code coverage analysis. So, when I come across a code sample, I generally step through it to</p>
<ul>
<li>See if it will work as intended (basic unit test)</li>
<li>See if there are any potential obvious errors in logic</li>
<li>Identify tests necessary for branch or conditional coverage (because developers are usually only concerned with block coverage)</li>
<li>Identify argument values for negative testing that might expose undesirable results (bugs)</li>
</ul>
<p>So, in this pseudo code example, once I got to the second conditional clause (if (number (sid)) &lt;= 1000000 or number (sid) &gt; 6000000 then) the little cranks in my brain began to turn. I thought to myself, why are we checking the length of the string? I mean, if the number can only be between 1,000,000 and 6,000,000 then it seems to me that checking the length of the string is simply redundant.</p>
<p>If we remove the first conditional clause (if ((length(sid) is not 7) then) then we actually reduce the number of tests to 3 instead of 4 assuming <a href="http://www.student.cs.uwaterloo.ca/~cs132/Weekly/W02/SCBooleans.html">short-circuiting</a> since short-circuiting compound Boolean expressions is one of several code optimization techniques. (By the way, the first caveat example in Wikipedia on short-circuiting where a function used as a Boolean conditional also “performs some required operation regardless of whether the first conditional evaluates true or false” is simply poor architectural design and is very, very likely to be problematic.) The 3 tests for condition (and basis path) coverage to exercise the true and false outcome of every single Boolean conditional expression are listed in the table below.</p>
<table border="1" cellspacing="0" cellpadding="2" width="681">
<tbody>
<tr>
<td width="173" valign="top"> </td>
<td width="196" valign="top">Conditional 1</td>
<td width="186" valign="top">Conditional 2</td>
<td width="124" valign="top"> </td>
</tr>
<tr>
<td width="172" valign="top">Test</td>
<td width="195" valign="top">number (sid) &lt;= 1000000</td>
<td width="186" valign="top">number (sid) &gt; 6000000</td>
<td width="126" valign="top">Expected Result</td>
</tr>
<tr>
<td width="172" valign="top">Any value between 1000000 and 6000000</td>
<td width="194" valign="top">false</td>
<td width="185" valign="top">false</td>
<td width="128" valign="top">true</td>
</tr>
<tr>
<td width="171" valign="top">Any value &gt; 6000000</td>
<td width="194" valign="top">false</td>
<td width="185" valign="top">true</td>
<td width="129" valign="top">false</td>
</tr>
<tr>
<td width="171" valign="top">Any value &lt; 1000000</td>
<td width="194" valign="top">true</td>
<td width="185" valign="top">(short-circuited)</td>
<td width="130" valign="top">false</td>
</tr>
</tbody>
</table>
<p>Of course, even testing several samples from the equivalent partitions may not expose the bug in this code because the bug in this code is a typical boundary error. (In a <a href="http://testingmentor.com/imtesty/2009/11/18/boundary-testing-isnt-guessing-at-numbers/">previous post</a> I explained the basic fault model that caused many boundary issues. In a nutshell, boundary bugs are generally caused by incorrect relational operators or <a href="http://en.wikipedia.org/wiki/Magic_number_(programming)">magic numbers</a> in code.) Without recognizing that we also need to test the boundaries (999999, 1000000, 1000001, and 5999999, 6000000, 6000001) also we could easily overlook the error in the pseudo code.</p>
<p>Another thing that caught my attention was the lack of exception handling. Some people may not consider including exception handling in pseudo code and take it as a given. But, as a tester when I don’t exception handling in pseudo code in a review then I need to start asking questions so I can better design tests to exercise the exception handling control flow paths that directly impact code coverage measures. Another reason this is an important consideration is because results of code coverage analysis indicates that exception handlers are generally under-tested. It seems we are really good at finding unhandled exceptions with our negative tests (which is really good), but we do not seem to be as thorough in testing the logical code paths of exception handlers. This is especially true for predicate statement with multiple Boolean sub-expressions might trigger an exception. We tend to test one of the conditionals, and the other conditionals expressions in that statement are often under-tested.</p>
<p>So, we can surmise the <em>number</em> () function must be converting the string parameter (the <em>sid</em> variable) to a numeric type and returning a type of number because the conditional clause is comparing it to magic numbers (1000000 and 6000000). But if we entered a string that contained non-numeric characters my initial thought was that the <em>number</em> () function would throw an exception that is unhandled by the <em>validate</em>_<em>studentID</em> () function.</p>
<p>Then I thought a bit more, and considered that the <em>number</em> () function might swallow the exception and return a 0 or even a -1. Now, there are some <a href="http://haacked.com/archive/2005/08/10/9293.aspx">arguments in favor of swallowing exceptions</a>, but in general it is not a good idea. In this case, it is probably a bad idea because one of the primary purposes of a separate function is reusability. If the <em>number</em> () is reused in some other code, or other part of the code where we need to convert a string to a numeric type regardless of the range (within the range of the data type being converted to), I would suspect we would want to throw an exception, and then rethrow the exception in the calling function. Of course, this is where the rubber hits the road, and a professional tester needs to dig in and start asking some hard questions as to how the developer is going to handle this situation. If the <em>number</em> () function is not going to be reused, then most modern programming languages include a function call that will easily convert the string to a numeric type and do it more efficiently as compared to calling a separate function. And may in that case we could swallow the exception in the <em>validate</em>_<em>studentID</em> () function and simply return false as illustrated in the C# code below.</p>
<div id="codeSnippetWrapper" style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; width: 97.5%; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; cursor: text; border: silver 1px solid; padding: 4px;">
<div id="codeSnippet" style="text-align: left; line-height: 12pt; background-color: #f4f4f4; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;">
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum1" style="color: #606060">   1:</span> <span style="color: #0000ff">try</span></pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum2" style="color: #606060">   2:</span> {</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum3" style="color: #606060">   3:</span>     <span style="color: #0000ff">if</span> (<span style="color: #0000ff">int</span>.Parse(sid) &lt; minValue || <span style="color: #0000ff">int</span>.Parse(sid) &gt; maxValue)</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum4" style="color: #606060">   4:</span>     {</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum5" style="color: #606060">   5:</span>         isOk = <span style="color: #0000ff">false</span>;</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum6" style="color: #606060">   6:</span>     }</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum7" style="color: #606060">   7:</span> }</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum8" style="color: #606060">   8:</span> <span style="color: #0000ff">catch</span> (FormatException)</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum9" style="color: #606060">   9:</span> {</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum10" style="color: #606060">  10:</span>     isOk = <span style="color: #0000ff">false</span>;</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum11" style="color: #606060">  11:</span> }</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum12" style="color: #606060">  12:</span> <span style="color: #0000ff">catch</span> (OverflowException)</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum13" style="color: #606060">  13:</span> {</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum14" style="color: #606060">  14:</span>     isOk = <span style="color: #0000ff">false</span>;</pre>
<p><!--CRLF--></p>
<pre style="text-align: left; line-height: 12pt; background-color: white; margin: 0em; width: 100%; font-family: 'Courier New', courier, monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible; border-style: none; padding: 0px;"><span id="lnum15" style="color: #606060">  15:</span> }</pre>
<p><!--CRLF--></div>
</div>
<p>With the push to drive quality upstream, reduce costs (especially testing costs), and improve testability I envision that many testers will be working alongside our development counterparts to help them prevent defects from getting into the product code base, and improve the maintainability of the code. This doesn’t mean that testers will become developers or visa versa; it simply means that testers are (generally) experts in designing tests, and developers are experts in designing solutions that adhere to requirements. Rather than an adversarial relationship, I suspect in the future developers and testers will have a more symbiotic relationship to improve the intrinsic quality of our code bases.</p>
<p>The bottom line of all this is that in teams where testers are designing white box tests for improved code coverage (control flow testing), or where testers are engaged in design reviews or peer reviews of code prior to check in, I hope this gives you some things to think about.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.testingmentor.com/imtesty/2009/12/02/refactoring-for-testability/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Reconsidering Code Coverage</title>
		<link>http://www.testingmentor.com/imtesty/2009/11/25/reconsidering-code-coverage/</link>
		<comments>http://www.testingmentor.com/imtesty/2009/11/25/reconsidering-code-coverage/#comments</comments>
		<pubDate>Wed, 25 Nov 2009 10:44:13 +0000</pubDate>
		<dc:creator>Bj Rollison</dc:creator>
				<category><![CDATA[Testing Practices]]></category>
		<category><![CDATA[Code Coverage]]></category>
		<category><![CDATA[Structural Testing]]></category>

		<guid isPermaLink="false">http://testingmentor.com/imtesty/2009/11/25/reconsidering-code-coverage/</guid>
		<description><![CDATA[Tonight on my way to teach a test automation course at the University of Washington I had some free time to catch up on my reading. My manager asked me if I had read this month’s copy of one of the several testing magazines we get and I replied that I had downloaded it but [...]]]></description>
			<content:encoded><![CDATA[<p>Tonight on my way to teach a test automation course at the University of Washington I had some free time to catch up on my reading. My manager asked me if I had read this month’s copy of one of the several testing magazines we get and I replied that I had downloaded it but hadn’t had a chance to read it yet. So, he tossed me the hardcopy of the magazine and said, “Enjoy.” Now this should have been a clue because although Alan is a great manager and mentor, I think he secretly likes to see the veins in my neck swell and blood shoot out of my eyes from time to time.</p>
<p>I read a lot of articles, white papers, and books. I like most of what I read, even if I disagree with some of the points being made. I can’t remember ever reading an article on software testing that ever made me angry. I was not angry because of the message of the article. In fact, I think the point the authors are trying to make is valid and I agree with them on their fundamental point. Unfortunately, the article is filled with technical inaccuracies the end message was almost lost.</p>
<p>I spent the last 10 years studying various techniques, methods, and approaches in software testing. I teach more than 500 testers a year on structural testing techniques, and am now working with a team in the Windows division to implement a new tool for just in time code coverage analysis at the component level that allows us to see how our tests exercise code paths in changed code and the dependent modules. I also discuss structural testing in chapter 5 of our book <em><a href="http://www.hwtams.com" target="_blank">How We Test Software At Microsoft</a></em>. I don’t really consider myself to be an expert in the subject, but I might know a thing or two about it. So, let’s Reconsider Code Coverage!</p>
<p>In August 2007 I wrote an <a href="http://blogs.msdn.com/imtesty/archive/2007/08/14/code-coverage-is-inversely-proportional-to-the-critical-information-it-provides.aspx">informative blog post</a> on the potential misuse of the code coverage measure. But code coverage measures are used by some companies as one of many ways to help them reduce risk. And, let me be very clear here, <strong><em>there is no correlation between code coverage and quality, and code coverage measures don’t tell us “how well” the code was tested</em></strong>. The code coverage measure simply measures what code has been executed, and more importantly what code has not been executed. The value of measuring code coverage is not in producing some “magic number,” but that it helps testers investigate untested or under-tested areas of the product and design additional tests (generally using structural testing techniques) to improve coverage and reduce overall risk.</p>
<blockquote><p><em>Just because you execute a line of code doesn’t mean a bug doesn’t still exist, but if you don’t execute a line of code you have 0 probability of finding a bug if one exists!</em></p></blockquote>
<p>Also it is important to note there are several ways to measure code coverage. Different tools employ different measures and sometimes different tools measure the same type of coverage differently. Also, I discovered that even the same tool can measure the same code differently depending on how it is compiled (debug, retail, etc.) and previously <a href="http://testingmentor.com/imtesty/2009/11/18/basic-blocks-arent-so-basic/">wrote</a> about my study. Some of the basic ways to measure code coverage (not test coverage) include:</p>
<ul>
<li><strong>Function coverage</strong> measures the percentage of functions or methods in a class or application that are called at runtime.</li>
<li><strong>Statement coverage</strong> measures the percentage of executable statements exercised at runtime.</li>
<li><strong>Block coverage</strong> measures the percentage of each sequence of non-branching statements that are executed at runtime. Block coverage subsumes statement coverage.</li>
<li><strong>Decision or branch coverage</strong> measures the percentage of both Boolean (not binary) outcomes (true and false) of simple conditional expressions at runtime. If a predicate statement has more than one conditional sub-expression decision (or branch) coverage treats that predicate statement as one conditional clause. Decision coverage subsumes block coverage.</li>
<li><strong>Condition coverage</strong> measures the percentage of both Boolean outcomes of each conditional sub-expressions that are separated by logical and or logical or in compound predicate statements. Condition coverage subsumes decision coverage.</li>
<li><a href="http://www.mccabe.com/pdf/nist235r.pdf"><strong>Basis path coverage</strong></a> measures the number of linearly independent paths through a program. Basis path coverage is based on <a href="http://www.literateprogramming.com/mccabe.pdf">McCabe’s cyclomatic complexity</a> research.</li>
<li><strong>Path coverage</strong> measures every possible path from the entry to the return statement (or exception) or exit of every method. Unfortunately path testing is usually impossible due to the sheer number of path combinations, and the inability to execute constrained path combinations.</li>
</ul>
<p>Clearly there are different measures of code coverage, and certain types of measures subsume other measures. So, now that we have a handle on the different types of code coverage measures, let’s look at testing some code. We will use the same pseudo code used in the aforementioned article which is based upon the following requirement.</p>
<blockquote><p>“Student ID’ are seven digit numbers between one million and 6 million inclusive.”</p></blockquote>
<p>The authors provided the following pseudo code example for a function to meet this requirement.</p>
<blockquote><p>function validate_studentid(string sid) return<br />
TRUEFALSE<br />
BEGIN<br />
  STATIC TRUEFALSE isOk;<br />
  isOk = true;</p>
<p>  if ((length(sid) is not 7) then<br />
    isOk = False;</p>
<p>  if (number(sid) &lt;= 1000000 or number(sid) &gt; 6000000 then<br />
     isOk = False;</p>
<p>  return isOk;</p>
<p>END</p></blockquote>
<p>So, other than the fact that there is no reason to ‘test’ the length of the sid variable before evaluating it to see if it is within the allowable range (removing this first conditional improves performance and also improves testability of the code), and that if the call to the number() function fails to convert the string to a number for a valid Boolean comparison it will throw an unhandled exception, let’s look at path testing of this simple example by starting with control flow diagrams of each possible path (assuming the call to the number() function does not throw an unhandled exception by passing this message a string of characters such as “foo” rather than a string of digits).</p>
<div id="attachment_244" class="wp-caption aligncenter" style="width: 594px"><img class="size-full wp-image-244" title="path" src="http://testingmentor.com/imtesty/wp-content/uploads/2009/11/path3.jpg" alt="Control flow diagram for validate_studentID() function pseudo-code" width="584" height="653" /><p class="wp-caption-text">Control flow diagram for validate_studentID() function pseudo-code</p></div>
<p>(Edited 11/25: After thinking about this a bit more, if the number() function returned a 0 (zero) if the input was incorrectly formatted, then the number() function would not throw an exception, and the control flow path would be identical to the first test in the table below).</p>
<p><a href="http://testingmentor.com/imtesty/wp-content/uploads/2009/11/path.jpg"></a></p>
<p>Because we are doing path coverage testing and not decision testing, we actually have to separate each Boolean conditional sub-expression in the second compound predicate statement if (number(sid) &lt;= 1000000 or number(sid) &gt; 600000. The example in the article treated both sub-expressions in the compound predicate statement as a single Boolean expression which would be synonymous with decision coverage. Path coverage actually treats each sub-expression as if there were 2 single Boolean conditions such as</p>
<blockquote><p>if (number(sid) &lt;= 1000000<br />
  isOk = False;</p>
<p>if number(sid) &gt; 600000<br />
  isOk = False;</p></blockquote>
<p>The table below illustrates the tests required for testing control flow through this function for path coverage (again assuming we are going to ignore the unhandled exception in the code that would occur by passing in a string such as “foo.”)</p>
<table border="1" cellspacing="0" cellpadding="2" width="553">
<tbody>
<tr>
<td width="71" valign="top">Input (sid)</td>
<td width="101" valign="top">Conditional<br />
length(sid)!= 7</td>
<td width="103" valign="top">Conditional<br />
number &lt;= 1mill</td>
<td width="93" valign="top">Conditional<br />
number &gt; 6mil</td>
<td width="86" valign="top">Expected<br />
Result</td>
<td width="97" valign="top">Actual<br />
Result</td>
</tr>
<tr>
<td width="71" valign="top">999999</td>
<td width="101" valign="top">true</td>
<td width="103" valign="top">true</td>
<td width="93" valign="top">false</td>
<td width="86" valign="top">False</td>
<td width="97" valign="top">False</td>
</tr>
<tr>
<td width="71" valign="top">6500000</td>
<td width="101" valign="top">false</td>
<td width="103" valign="top">false</td>
<td width="93" valign="top">true</td>
<td width="86" valign="top">False</td>
<td width="97" valign="top">False</td>
</tr>
<tr>
<td width="71" valign="top">1000000</td>
<td width="101" valign="top">false</td>
<td width="103" valign="top">true</td>
<td width="93" valign="top">false</td>
<td width="86" valign="top"><strong>True</strong></td>
<td width="97" valign="top"><strong>False</strong></td>
</tr>
<tr>
<td width="71" valign="top">6000000</td>
<td width="101" valign="top">false</td>
<td width="103" valign="top">false</td>
<td width="93" valign="top">false</td>
<td width="86" valign="top">True</td>
<td width="97" valign="top">True</td>
</tr>
</tbody>
</table>
<p>The first test would be a value less than 7 digits, and would cause all Boolean conditional expressions to evaluate as true which will set the isOk variable to false (3 times), and we correctly return the expected result of false (or invalid ID). The second test is a number greater than 6,000,000 (but less than the maximum value that would result in an unhandled overflow exception hopefully being thrown by the number() function). In this case the 3rd conditional expression (<em>if (number(sid) &gt; 6000000</em>) would evaluate as true and the function would return false. The 3rd path is buggy. In this pseudo code example, the only possible way to exercise the true outcome of the Boolean condition <em>if (number(sid) &lt;= 1000000</em> is to use the value of 1,000,000; any other value larger or smaller will cause this Boolean condition to evaluate as false. In this case we expect the function to return true, but it in fact will return false. Finally, any number greater than 1000001 and less than or equal to 6000000 will return a true result indicating a valid student ID.</p>
<p>The article also suggest that structural testing misses other problems. But, when we look at these issues, they actually have nothing to do with structural testing of the function; in other words they are completely out of context of the problem being discussed.</p>
<p>For example, the assert is the requirement is incorrect and should have read 6,999,999 (<strong><em>which I believe is a typo and should be 5,999,999</em></strong>) because of confusion over the word “inclusive.” Inclusive means “<em>including the stated limit or extremes in consideration or account,</em>” but in computing inclusive means “<em>the predicate holds for all elements of an increasing sequence then it holds for their least upper bound.</em>” I disagree with this assumption because I suspect the analyst writing the spec is basing the inclusive range on the common definition, and not a definition based on <a href="http://www.cs.bham.ac.uk/~axj/pub/papers/handy1.pdf">domain theory</a>.</p>
<p>The article questions what would occur with incorrectly formatted numbers such as 123 456 789 or 123,456,789. So, beside the point that these values are not within the valid range of student id numbers, the answer to the question would actually lie in how the <em>number()</em> function being called handles improperly formatted numbers (e.g throwing a format exception, which again is unhandled in our <em>validate_studentid()</em> function), or how an event handler that sits between the UI and the function might deal with invalid or incorrectly formatted inputs.</p>
<p>The next question concerned resizing of the input window or the screen (assuming desktop resolution) and repainting the window or form and its affect on code coverage of the <em>validate_studentid()</em> function. Well, I am going out on a limb here and I am going to say…”what are you talking about?” I am not quite sure how to phrase this, but let me try…resizing or repainting a window has 0 effect on the structural control flow of the <em>validate_studentid()</em> function. (Of course, I could be wrong, and the length() function number() function might have some code that mysteriously interacts with the repainting libraries and how it determines the length of a string or whether a string is a valid number.)</p>
<p>Bugs in external libraries are part of the business. Hopefully those external libraries are well tested or at least documented especially if our development team wrote them. Personally, I have not encountered any public functions or APIs which use wild ass random numbers such as 5.8 million as boundary values, but that’s not to say it couldn’t happen. And of course, if these external functions throw exceptions (as they should based on what they are probably doing), we should have exception handler code in our function to deal with any exceptions thrown from external libraries or function calls.</p>
<p>Based on incorrect path analysis, and out-of-context questions that have nothing to do with control flow through the <em>validate_studentid()</em> function the article suggests that path testing is not a magic potion, but I am not too sure that anyone actually believes it is. And so, the article suggests that “input combinatorics coverage” might work better. Hmm…now I have been teaching combinatorial testing for over 10 years and have read some interesting papers on the effectiveness of combinatorics on statistical testing and code coverage, and I must say I pretty sure you need more than one input parameter in combinatorial testing!</p>
<p>Finally, I don’t agree that code coverage measures tell us “how well the developers have tested their code.” The code coverage measure only tells us what percentage of the code has been executed in a particular way, and more importantly it tells us how what percentage of code has been untested. We must determine whether we need to investigate that area to reduce risk. Of course, many code coverage tools provide a “heat map” that helps us and developers identify untested code, and that is where we shift from the simple act of measuring coverage to the testing method of code coverage analysis in order to design new tests that effectively exercise previously untested code if that level of coverage is important to reduce overall risk.</p>
<p><a href="http://testingmentor.com/imtesty/wp-content/uploads/2009/11/heatmap.jpg"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="heat map" src="http://testingmentor.com/imtesty/wp-content/uploads/2009/11/heatmap_thumb.jpg" border="0" alt="heat map" width="545" height="514" /></a></p>
<p>My intent here is not to ridicule the authors of the article. In fact, I agree with their summation that testers should not believe high code coverage numbers mean “well tested.” (Again see my <a href="http://testingmentor.com/imtesty/2009/11/13/the-code-coverage-metric-is-inversely-proportional-to-the-criticality-of-the-information-it-provides/">blog post from Aug 2007</a>.) Unfortunately, the path to the point was fraught with inaccuracies and tangents that I almost never made it to the end.</p>
<p>There are many books and white papers on this subject in the ACM and IEEE libraries. Books by Boris Beizer, Robert Binder, and others go into great detail on structural testing. McCabe’s papers linked to in this post are an excellent resources.</p>
<p>OK…I feel better now. I need to clean up the blood, take a sedative, and go to sleep.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.testingmentor.com/imtesty/2009/11/25/reconsidering-code-coverage/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>The Pesticide Paradox</title>
		<link>http://www.testingmentor.com/imtesty/2009/11/19/the-pesticide-paradox/</link>
		<comments>http://www.testingmentor.com/imtesty/2009/11/19/the-pesticide-paradox/#comments</comments>
		<pubDate>Fri, 20 Nov 2009 05:12:31 +0000</pubDate>
		<dc:creator>Bj Rollison</dc:creator>
				<category><![CDATA[General Testing Topics]]></category>
		<category><![CDATA[Teaching]]></category>

		<guid isPermaLink="false">http://testingmentor.com/imtesty/2009/11/19/the-pesticide-paradox/</guid>
		<description><![CDATA[Some of you know that I am an organic gardener. I do this not only because I like the fresh taste of vegetables and fruits that are not tainted with chemicals, but my daughter loves to eat things right off the vine or stem as we are harvesting our bounty and I am perhaps overly [...]]]></description>
			<content:encoded><![CDATA[<p>Some of you know that I am an organic gardener. I do this not only because I like the fresh taste of vegetables and fruits that are not tainted with chemicals, but my daughter loves to eat things right off the vine or stem as we are harvesting our bounty and I am perhaps overly protective of my daughter. Here in the Pacific Northwest slugs are a particular problem, and I must use several different techniques and approaches to try to ward off or destroy these nasty, slimy creatures throughout the year because no single approach is 100% effective. Yes it is unfortunately true, even with my diligent efforts and myriad of tactics a few slugs still get by into the raised gardens. This sure seems a lot like software testing and how some tests find some bugs and miss others, and how iterative builds seem to allow new bugs to continually creep in. But, this really isn’t a revelation.</p>
<p>In 1983, in his seminal book <em>Software Testing Techniques</em>, Boris Beizer compared the diminishing effects of insecticides on boll weevils destroying cotton fields to the decreasing effectiveness of testing methods in exposing defects in software. This became well known as the Pesticide Paradox. The Pesticide Paradox states “<strong><em>Every method you use to prevent or find bugs leaves a residue of subtler bugs against which those methods are ineffectual</em></strong>.”</p>
<p>Now, unlike insects (or pests), software doesn’t magically build up an immunity to bugs. What happens is that we design and execute tests using one approach that exposes some set of issues. But, then the number of issues being exposed by that approach starts to diminish, yet there are still some ‘residue of subtler bugs’ that haven’t been detected by that set of tests or testing approach. Also similar to how the ladybugs in my garden that eat aphids and mites have no effect on slugs, not all approaches or techniques we might use in our testing is effective in detecting or preventing all types of bugs. </p>
<p>For the past 10 years, I have been teaching various software testing practices and approaches for solving complex problems at Microsoft. One cool aspect of my job is that I get to experiment a lot in a reasonably controlled environment with diverse groups of people. We often design these studies to better understand the benefits and limitations of various testing approaches and methods in exposing different categories of defects to better understand how each approach can be used more effectively within the appropriate context. Of course, it should be of no surprise to anyone that the pesticide paradox holds true not just in the classroom, but also in practice.</p>
<p>I often explain Beizer’s paradox by stating, “there is no single approach or method used in software testing that is completely effective in exposing all bugs, and some approaches or methods are more effective in exposing different types or categories of bugs.” </p>
<p>At Microsoft there is no “one size fits all” solution, and the Engineering Excellence group doesn’t dictate how to test or what testing methods can or can’t be used. But, through a series of problem solving exercises in our new SDET training program each tester experiences the benefits and limitations of various approaches and techniques. Based on their experiences in the classroom and in ‘real life’ they also learn the most effective strategy for testing is not to rely too heavily on a single approach, and to use a variety of test design principles and patterns throughout the product lifecycle. But, that’s just how we roll.</p>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td><img src="http://ecx.images-amazon.com/images/I/41S6BXE49RL._SL75_.jpg" /> </td>
<td valign="top"><a href="http://www.amazon.com/Software-Testing-Techniques-2nd-Eidition/dp/1850328803%3FSubscriptionId%3D0JTCV5ZMHMF7ZYTXGFR2%26tag%3Dbrdicr-20%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3D1850328803">Software Testing Techniques 2nd Eidition</a> </td>
</tr>
</tbody>
</table>
]]></content:encoded>
			<wfw:commentRss>http://www.testingmentor.com/imtesty/2009/11/19/the-pesticide-paradox/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>
