<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
  <channel>
    <title>Jay Harris is Cpt. LoadTest - Testing</title>
    <link>http://www.cptloadtest.com/</link>
    <description>a .net developers blog on improving user experience of humans and coders</description>
    <language>en-us</language>
    <copyright>Jason Harris</copyright>
    <lastBuildDate>Wed, 07 Apr 2010 15:27:53 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 2.3.12105.0</generator>
    <managingEditor>jharris@harrisdesigns.com</managingEditor>
    <webMaster>jharris@harrisdesigns.com</webMaster>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=5a613524-5607-4fbb-a89f-74b5afb7c5e9</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,5a613524-5607-4fbb-a89f-74b5afb7c5e9.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,5a613524-5607-4fbb-a89f-74b5afb7c5e9.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=5a613524-5607-4fbb-a89f-74b5afb7c5e9</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Aligned with another jam session at Ann Arbor's <a href="http://www.comejamwithus.org">Come
Jam With Us</a> is another installment of Learn to Code, this time providing an introduction
to WatiN, or Web Application Testing in .NET. The jam session was held at the offices
of SRT Solutions in Ann Arbor, Michigan, at 5:30p, Tuesday April 6th. Though thunderstorms
were in the forecast, the predicted high was 72°F (22°C), so we weren't bothered by
the same 8" of fluffy white snow that caused cancellations and delays during
the my session on ASP.NET MVC 2. But for those that couldn't make the WatiN jam session,
might I recommend the exercise below.
</p>
        <h3>About This Exercise
</h3>
        <p>
This coding exercise is designed to give you an introduction to browser-based testing
using the WatiN framework, or Web Application Testing in .NET. The framework allows
developers to create integration tests (using a unit testing framework like MbUnit,
NUnit, or MSTest) to test and assert their application within a browser window. The
framework interacts with the browser DOM much like and end-user, producing reliable
results that mimic the real world. In this sample, we will write a few WatiN tests
against the Google search engine.
</p>
        <h3>Prerequisites
</h3>
        <p>
To complete this exercise, you will need to meet or complete a few prerequisites.
Please complete these prerequisites before moving on. The session is designed to be
completed in about an hour, but setup and prerequisites are not included in that time.
</p>
        <ul>
          <li>
An active internet connection. (Our tests will be conducted against live third-party
sites.) 
</li>
          <li>
Install Microsoft Visual Studio 2008 or Microsoft Visual Studio 2010. 
</li>
          <li>
            <a title="Download WATiN from SourceForge" href="http://sourceforge.net/projects/watin/files/">Download</a> and
extract the latest version of the WatiN framework. 
</li>
        </ul>
        <h3>Exercise 0: Getting Started
</h3>
        <h4>Creating a Project
</h4>
        <p>
WatiN is generally used within the context of a unit testing framework. For this exercise,
we will be using a Visual Studio Test Project and MSTest to wrap our WatiN code.
</p>
        <ol>
          <li>
Create a new "Test Project" in Visual Studio named "WatinSample".
The language is up to you, but all of the examples in this post will use C#. 
</li>
          <li>
Feel free to delete the Authoring Tests document, the Manual Test file, and UnitTest1.cs.
We won't be using these. 
</li>
          <li>
Add a reference to WatiN.Core.dll from the bin directory of your extracted WatiN download. 
</li>
          <li>
Compile. 
</li>
        </ol>
        <h3>Exercise 1: My First Browser Tests
</h3>
        <p>
In our first test, we will use the project we just created to test Google's home page.
After accessing <a href="http://www.google.com">http://www.google.com</a>, we will
check a few properties of the browser and a few loaded elements to ensure that the
expected page was returned. The first thing we will need is a new Unit Test class
to start our testing.
</p>
        <ol>
          <li>
Create a new class (Right click on the "WatinSample" project and select
Add –&gt; Class…), called WhenViewingTheGoogleHomePage. 
</li>
          <li>
Mark the class as public. 
</li>
          <li>
Add the MSTest [TestClass] attribute to the new class. 
</li>
          <li>
Compile. 
</li>
        </ol>
        <pre class="csharp:nocontrols" name="code">using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace WatinSample
{
  [TestClass]
  public class WhenViewingTheGoogleHomePage
  {
  }
}</pre>
        <h4>Make an instance of the browser
</h4>
        <p>
Now that we have a test class, we can start writing WatiN code. Each of our tests
will first need a Browser object to test against. Using methods attributed with TestInitialize
and TestCleanup, we can create a browser instance before the test starts and shut
it down when the test is complete.
</p>
        <p>
Creating an instance of a browser in WatiN is easy: simply create a new instance of
the IE class, passing in a URL. We can assign this new class to a field of type Browser,
which is a base class of all browser classes in WatiN. Currently, WatiN supports Internet
Explorer and Firefox.
</p>
        <ol>
          <li>
Create a private field in the test class named browserInstance of type WatiN.Core.Browser.
Add a using statement to WatiN.Core if you wish. 
</li>
          <li>
Create a test initialization method named WithAnInstanceOfTheBrowser and give it the
[TestInitialize] attribute. Within this method, create a new instance of the IE class,
passing in the Google URL, <a href="http://www.google.com">http://www.google.com</a>,
and assigning the instance to the browserInstance field. 
</li>
          <li>
Finally, create a test cleanup method named ShutdownBrowserWhenDone and give it the
[TestCleanup] attribute. Within this method, execute the Close() method on our browser
instance and assign the field to null to assist with object disposal. 
</li>
        </ol>
        <pre class="csharp:nocontrols" name="code">using Microsoft.VisualStudio.TestTools.UnitTesting;
using WatiN.Core;

namespace WatinSample
{
  [TestClass]
  public class WhenViewingTheGoogleHomePage
  {
    Browser browserInstance;

    [TestInitialize]
    public void WithAnInstanceOfTheBrowser()
    {
      browserInstance = new IE("http://www.google.com");
    }

    [TestCleanup]
    public void ShutdownBrowserWhenDone()
    {
      browserInstance.Close();
      browserInstance = null;
    }
  }
}</pre>
        <h4>Our First Tests: Checking for existence of an element
</h4>
        <p>
There are three prominent items on the Google home page: the Google logo, the search
criteria text box, and the search button. Using WatiN, we can check for them all.
The WatiN Browser object contains an Elements collection, which is a flattened collection
of every element in the entire DOM. Like any collection, you can use Linq and lambda
expressions to search for items within this collection. Alternately, you may also
use the Element method, which accepts the same lambda expression that would be used
within the Where extension method on the collection, and returns the first or default
element. For more specific searches, WatiN's Browser object includes similar collections
and methods for searching explicitly for Images (&lt;IMG&gt;), Paras (&lt;P&gt;),
Text Fields (&lt;INPUT type="text" /&gt;), and so on.
</p>
        <p>
On each returned Element (or derived Para, Image, or Text Field, etc., all of which
inherit from Element), WatiN supplies properties for accessing the CSS Class, Id,
InnerHtml, Name, Tag, Text, Value, or many other attributes. The method GetAttributeValue(string
attributeName) is provided for accessing other attributes that are not explicitly
defined on the object (uncommon attributes and custom attributes). Finally, elements
also contain a Style property, which not only gives access to the inline style attribute,
but also any CSS properties associated with the element from Internal Style (in the
Page Head) or External Style (in an external style sheet).
</p>
        <p>
On to checking for the three elements within the Google home page: the logo, the criteria
input, and the search button. First, check for the existence of the Google logo graphic.
The image can be found by searching the DOM for an image with an Id of "logo".
WatiN works very closely with lambda expressions, so we can use these to help us find
out graphic.
</p>
        <ol>
          <li>
Create a new public method named PageShouldContainGoogleLogo. 
</li>
          <li>
Add the MSTest [TestMethod] attribute to the method. 
</li>
          <li>
Search for and assert on the existence of an image with the Id of "logo". 
</li>
          <li>
Optionally, we can also check that the image has the expected Alt attribute; in this
case, the value should be "Google". 
</li>
          <li>
Compile and run the test. The test should pass. 
</li>
        </ol>
        <pre class="csharp:nocontrols" name="code">[TestMethod]
public void PageShouldContainGoogleLogo()
{
  Image googleLogo;
  googleLogo = browserInstance.Image(img =&gt; img.Id == "logo");
  Assert.IsTrue(googleLogo.Exists);
  Assert.AreEqual("Google", googleLogo.Alt);
}</pre>
        <p>
Next, check for the existence of the search criteria input box. WatiN refers to these
elements as Text Fields, using the TextField type. Additionally, this form field is
identified by its Name rather than its Id. In Google, the name given to the criteria
input is "q".
</p>
        <ol>
          <li>
Create a new public method named PageShouldContainSearchCriteriaInput and give it
the [TestMethod] attribute. 
</li>
          <li>
Search for and assert on the existence of a Text Field with the name "q". 
</li>
          <li>
Compile and run the test. The test should pass. 
</li>
        </ol>
        <pre class="csharp:nocontrols" name="code">[TestMethod]
public void PageShouldContainSearchCriteriaInput()
{
  TextField criteriaInput;
  criteriaInput = browserInstance.TextField(tf =&gt; tf.Name == "q");
  Assert.IsTrue(criteriaInput.Exists);
}</pre>
        <p>
Finally, check for the existence of the search button using the Button method. In
our lambda expression, it is not important to know if the field is identified by a
Name property or an Id attribute, as WatiN supplies a IdOrName property to help us
find the element. The value to identify the button is "btnG".
</p>
        <ol>
          <li>
Create a new public method named PageShouldContainSearchButton and give it the [TestMethod]
attribute. 
</li>
          <li>
Search for and assert on the existence of a Button with the Id or Name of 'btnG". 
</li>
          <li>
Optionally, we can also check the value of the button, which is the text displayed
on the button on-screen. This text should be "Google Search". 
</li>
          <li>
Compile and run the test. The test should pass. 
</li>
        </ol>
        <pre class="csharp:nocontrols" name="code">[TestMethod]
public void PageShouldContainSearchButton()
{
  Button searchButton;
  searchButton = browserInstance.Button(btn =&gt; btn.IdOrName == "btnG");
  Assert.IsTrue(searchButton.Exists);
  Assert.AreEqual("Google Search", searchButton.Value);
}</pre>
        <h4>Working with Style
</h4>
        <p>
WatiN can access properties on the DOM beyond just Text values and Alt attributes.
WatiN also has full access to the style that CSS has applied to an element. Let's
check out a few CSS properties, both those explicitly defined by WatiN and those implicitly
accessible through the WatiN framework.
</p>
        <p>
For our first style check, we'll take a look at the default font family used on the
Google Home Page. Font Family is one of the explicitly available style properties
on a WatiN element. Some others, like Color, Display, and Height are also explicitly
defined.
</p>
        <ol>
          <li>
Create a new public test method named BodyShouldUseArialFontFamily. 
</li>
          <li>
Assert that the font family assigned to the body matches "arial, sans-serif". 
</li>
          <li>
Compile and run the test. The test should pass. 
</li>
        </ol>
        <pre class="csharp:nocontrols" name="code">[TestMethod]
public void BodyShouldUseArialFontFamily()
{
  Assert.AreEqual("arial, sans-serif", browserInstance.Body.Style.FontFamily);
}</pre>
        <p>
For our second style check, we will look for an implicit style definition. At the
top of the Google Home Page is a series of links to other areas of Google, such as
Images, Videos, Maps, and News. At the end of this list is a More link, that when
clicked, displays a hidden DIV tag containing even more links, such as Books, Finance,
and Google Translate. Since we do not have any code in our test initialization that
interacts with the browser, and thus nothing that is clicking the More link, that
DIV should still have a hidden visibility. However, since Visibility isn't an explicitly
defined style property within WatiN, we need to use the GetAttributeValue method to
retrieve the current visibility setting.
</p>
        <ol>
          <li>
Create a new public test method named MoreItemsShouldNotBeVisibleOnPageLoad. 
</li>
          <li>
Search for the More Items DIV. It's Id is "gbi". 
</li>
          <li>
Using the property lookup method, GetAttributeValue(string attributeName), check that
the Visibility is set to "hidden". 
</li>
          <li>
Compile and run the test. The test should pass. 
</li>
        </ol>
        <pre class="csharp:nocontrols" name="code">[TestMethod]
public void MoreItemsShouldNotBeVisibleOnPageLoad()
{
  var googleBarMoreItems = browserInstance.Div(gbi =&gt; gbi.Id == "gbi");
  Assert.AreEqual("hidden", googleBarMoreItems.Style.GetAttributeValue("visibility"));
}</pre>
        <h3>Exercise 2: Interacting with the Browser
</h3>
        <p>
Browser Integration tests are more than just loading a page and checking a few element
attributes. Our tests may also need to enter values into form fields, click links
and buttons, or interact with browser navigation like the back button. WatiN fully
supports all of these features in a very intuitive fashion.
</p>
        <h4>A new test class, this time with Search Capability
</h4>
        <p>
Create a new test class, similar to what we did in Exercise 1, calling the new test
class WhenViewingGoogleSearchResultsForComeJamWithUs. Also add in the TestInitialize
and TestCleanup methods that open and close the browser. However, this time, after
we load <a href="http://www.google.com">http://www.google.com</a>, enter a value into
the search criteria input and then click the Google Search button.
</p>
        <ol>
          <li>
Create a new class named WhenViewingGoogleSearchResultsForComeJamWithUs, similar to
what was done in Exercise 1. 
</li>
          <li>
Add in the TestInitialize and TestCleanup methods from Exercise 1. Name the Initialize
method WithAnInstanceOfTheBrowserSearchingGoogle. 
</li>
          <li>
After the code that initializes the IE class, find the search criteria Text Field
and set its value to "Come Jam With Us". 
</li>
          <li>
After setting the Text Field value, click the Google Search button by calling the
Click() method on the Button class. 
</li>
          <li>
Compile. 
</li>
        </ol>
        <pre class="csharp:nocontrols" name="code">using Microsoft.VisualStudio.TestTools.UnitTesting;
using WatiN.Core;

namespace WatinSample
{
  [TestClass]
  public class WhenViewingGoogleSearchResultsForComeJamWithUs
  {
    Browser browserInstance;

    [TestInitialize]
    public void WithAnInstanceOfTheBrowserSearchingGoogle()
    {
      browserInstance = new IE(@"http://www.google.com");
      TextField criteria =
        browserInstance.TextField(tf =&gt; tf.Name == "q");
      criteria.Value = "Come Jam With Us";
      Button search =
        browserInstance.Button(btn =&gt; btn.IdOrName == "btnG");
      search.Click();
    }

    [TestCleanup]
    public void ShutdownBrowserWhenDone()
    {
      browserInstance.Close();
      browserInstance = null;
    }
  }
}</pre>
        <p>
With this code, or initialized test will load the Google Home Page and will conduct
a search for "Come Jam With Us".
</p>
        <h4>Validating the Search Results Page
</h4>
        <p>
For our first verification, let's check the URL for the browser window. The search
result URL should contain the search criteria in the URL's query string; we can validate
this using the URL property on our instance of the Browser object.
</p>
        <ol>
          <li>
Create a new public test method named BrowserUrlShouldContainSearchCriteria. 
</li>
          <li>
Validate that the current browser URL contains the search criteria information, "q=Come+Jam+With+Us". 
</li>
          <li>
Compile and run the test. The test should pass. 
</li>
        </ol>
        <pre class="csharp:nocontrols" name="code">[TestMethod]
public void BrowserUrlShouldContainSearchCriteria()
{
  Assert.IsTrue(browserInstance.Url.Contains(@"q=Come+Jam+With+Us"));
}</pre>
        <h4>Finding Child Elements
</h4>
        <p>
With WatiN, we are not just limited to searching for items directly from the Browser
object. We can also search for child elements directly from their parent element or
any ancestor element. Our search results should contain a search result item linking
to the Come Jam With Us web site. The Google Results page contains a DIV identified
as "res" that serves as a container for all search result information. Rather
than checking that our Come Jam With Us link exists somewhere on the page, we should
search for it directly within the results DIV.
</p>
        <ol>
          <li>
Create a new public test method named ResultsShouldContainLinkToComeJamWithUs. 
</li>
          <li>
From the browser instance, find a DIV identified as "res". 
</li>
          <li>
Assert that a link to <a href="http://www.comejamwithus.org">http://www.comejamwithus.org</a> exists
within the "res" DIV. 
</li>
          <li>
Compile and run the test. The test should pass. 
</li>
        </ol>
        <pre class="csharp:nocontrols" name="code">[TestMethod]
public void ResultsShouldContainLinkToComeJamWithUs()
{
  Link comeJamWithUs;
  Div searchResults = browserInstance.Div(div =&gt; div.IdOrName == "res");
  comeJamWithUs =
    searchResults.Link(link =&gt; link.Url == @"http://www.comejamwithus.org/");
  Assert.IsTrue(comeJamWithUs.Exists);
}</pre>
        <h4>Inner Text verses InnerHtml
</h4>
        <p>
An element may contain many child elements. An anchor tag—&lt;A href="#"&gt;—can
contain text, and child elements may make portions of that text bold, italic, underlined,
or even bright red. Through WatiN, we can access that inner content as straight text
without the formatting, or as the InnerHtml including all of the child elements.
</p>
        <ol>
          <li>
Create two public test methods, one named ResultsLinkContainsComeJamWithUsText and
the other named ResultsLinkContainsComeJamWithUsHtml. 
</li>
          <li>
In both methods, search for the results DIV, as we did in the previous test. 
</li>
          <li>
In both methods, search through the results DIV for a link with a URL matching <a href="http://www.comejamwithus.org">http://www.comejamwithus.org</a></li>
          <li>
In the Text method, assert that the text of the link matches "Come Jam with us
(Software Development Study Group)". Note that the value contains no child HTML
elements. 
</li>
          <li>
In the HTML method, assert that the InnerHtml of the link matches "&lt;EM&gt;Come
Jam with us&lt;/EM&gt; (Software Development Study Group)". Note that for the
same link, we now have the emphasis tags surrounding Come Jam With Us. 
</li>
          <li>
Compile and run both tests. The tests should pass.</li>
        </ol>
        <pre class="csharp:nocontrols" name="code">[TestMethod]
public void ResultsLinkContainsComeJamWithUsText()
{
  Link comeJamWithUs;
  Div searchResults = browserInstance.Div(div =&gt; div.IdOrName == "res");
  comeJamWithUs =
    searchResults.Link(link =&gt; link.Url == @"http://www.comejamwithus.org/");
  Assert.AreEqual(@"Come Jam with us (Software Development Study Group)",
    comeJamWithUs.Text);
}

[TestMethod]
public void ResultsLinkContainsComeJamWithUsHtml()
{
  Link comeJamWithUs;
  Div searchResults = browserInstance.Div(div =&gt; div.IdOrName == "res");
  comeJamWithUs =
    searchResults.Link(link =&gt; link.Url == @"http://www.comejamwithus.org/");
  Assert.AreEqual(
    @"&lt;EM&gt;Come Jam with us&lt;/EM&gt; (Software Development Study Group)",
    comeJamWithUs.InnerHtml);
}</pre>
        <h4>Back to the Start
</h4>
        <p>
As previously mentioned, we can also fully interact with the browser, itself. Our
test initialization started from the Google Home Page and performed a search. Using
functionality built in to WatiN, we can execute the browser's back navigation to return
to the previous page.
</p>
        <p>
For our next test, execute a back navigation and verify that the browser's URL matches <a href="http://www.google.com/">http://www.google.com/</a>.
</p>
        <ol>
          <li>
Create a public test method named PageShouldHaveComeFromGoogleDotCom. 
</li>
          <li>
Execute back navigation in the browser by calling the Back() method on browserInstance. 
</li>
          <li>
Validate that the browser URL matches <a href="http://www.google.com/">http://www.google.com/</a>. 
</li>
          <li>
Compile and run the test. The test should pass.</li>
        </ol>
        <pre class="csharp:nocontrols" name="code">[TestMethod]
public void PageShouldHaveComeFromGoogleDotCom()
{
  string previousUrl;
  browserInstance.Back();
  previousUrl = browserInstance.Url;
  Assert.AreEqual(@"http://www.google.com/", previousUrl);
}</pre>
        <h4>Putting it all together
</h4>
        <p>
Some interactions on a page cause element properties to change. An example of this
is the More link from Exercise 1; when the end-user clicks the More link, the More
Items DIV appears because the link's click event changes the Visibility style property
of the DIV to visible. For our final test, we will use what we have learned to test
this functionality.
</p>
        <ol>
          <li>
Create a new public test method named MoreItemsShouldBeVisibleOnMoreLinkClick.</li>
          <li>
Search for the header bar of Google links, a DIV with an Id of "gbar".</li>
          <li>
Within "gbar", search for the More Items DIV by an Id or Name of "gbi". 
</li>
          <li>
Assert that the visibility style property has a value of "hidden". 
</li>
          <li>
Within "gbar", search for the More link by its class name, "gb3".
Note that since a class attribute may contain multiple class definitions, this is
accomplished by validating that the class attribute contains the class you are searching
for. 
</li>
          <li>
Execute a Click event on the link. 
</li>
          <li>
Assert that the visibility style property of the More Items DIV has changed to "visible". 
</li>
        </ol>
        <pre class="csharp:nocontrols" name="code">[TestMethod]
public void MoreItemsShouldBeVisibleOnMoreLinkClick()
{
  var googleBar = browserInstance.Div(gbar =&gt; gbar.Id == "gbar");
  var googleBarMoreItems = googleBar.Div(gbi =&gt; gbi.Id == "gbi");
  Assert.AreEqual("hidden",
    googleBarMoreItems.Style.GetAttributeValue("visibility"));
  var googleBarMoreLink =
    googleBar.Link(link =&gt; link.ClassName.Contains("gb3"));
  googleBarMoreLink.Click();
  Assert.AreEqual("visible",
    googleBarMoreItems.Style.GetAttributeValue("visibility"));
}</pre>
        <h4>That's It
</h4>
        <p>
Now that we have spent some time on basic properties, interactions, and style sheets
within the WatiN framework, hopefully you can apply this to your own application and
get started with your own browser-based integration tests. If you would like more
information, I encourage you to check out the WatiN site at <a href="http://watin.sourceforge.net">http://watin.sourceforge.net</a>.
And as always, if you have any questions, drop me a line.
</p>
        <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:9a272a14-7cc1-4234-a4bc-8531ce7b8597" class="wlWriterEditableSmartContent">Technorati
Tags: <a href="http://technorati.com/tags/WatiN" rel="tag">WatiN</a>,<a href="http://technorati.com/tags/Jam+Session" rel="tag">Jam
Session</a>,<a href="http://technorati.com/tags/Coding+Exercise" rel="tag">Coding
Exercise</a>,<a href="http://technorati.com/tags/Learn+to+Code" rel="tag">Learn to
Code</a>,<a href="http://technorati.com/tags/Browser+Testing" rel="tag">Browser Testing</a></div>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=5a613524-5607-4fbb-a89f-74b5afb7c5e9" />
      </body>
      <title>Learn to Code WatiN: Browser Test your Web Site with WatiN</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,5a613524-5607-4fbb-a89f-74b5afb7c5e9.aspx</guid>
      <link>http://www.cptloadtest.com/2010/04/07/Learn-To-Code-WatiN-Browser-Test-Your-Web-Site-With-WatiN.aspx</link>
      <pubDate>Wed, 07 Apr 2010 15:27:53 GMT</pubDate>
      <description>&lt;p&gt;
Aligned with another jam session at Ann Arbor's &lt;a href="http://www.comejamwithus.org"&gt;Come
Jam With Us&lt;/a&gt; is another installment of Learn to Code, this time providing an introduction
to WatiN, or Web Application Testing in .NET. The jam session was held at the offices
of SRT Solutions in Ann Arbor, Michigan, at 5:30p, Tuesday April 6th. Though thunderstorms
were in the forecast, the predicted high was 72°F (22°C), so we weren't bothered by
the same 8&amp;quot; of fluffy white snow that caused cancellations and delays during
the my session on ASP.NET MVC 2. But for those that couldn't make the WatiN jam session,
might I recommend the exercise below.
&lt;/p&gt;
&lt;h3&gt;About This Exercise
&lt;/h3&gt;
&lt;p&gt;
This coding exercise is designed to give you an introduction to browser-based testing
using the WatiN framework, or Web Application Testing in .NET. The framework allows
developers to create integration tests (using a unit testing framework like MbUnit,
NUnit, or MSTest) to test and assert their application within a browser window. The
framework interacts with the browser DOM much like and end-user, producing reliable
results that mimic the real world. In this sample, we will write a few WatiN tests
against the Google search engine.
&lt;/p&gt;
&lt;h3&gt;Prerequisites
&lt;/h3&gt;
&lt;p&gt;
To complete this exercise, you will need to meet or complete a few prerequisites.
Please complete these prerequisites before moving on. The session is designed to be
completed in about an hour, but setup and prerequisites are not included in that time.
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
An active internet connection. (Our tests will be conducted against live third-party
sites.) 
&lt;/li&gt;
&lt;li&gt;
Install Microsoft Visual Studio 2008 or Microsoft Visual Studio 2010. 
&lt;/li&gt;
&lt;li&gt;
&lt;a title="Download WATiN from SourceForge" href="http://sourceforge.net/projects/watin/files/"&gt;Download&lt;/a&gt; and
extract the latest version of the WatiN framework. 
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Exercise 0: Getting Started
&lt;/h3&gt;
&lt;h4&gt;Creating a Project
&lt;/h4&gt;
&lt;p&gt;
WatiN is generally used within the context of a unit testing framework. For this exercise,
we will be using a Visual Studio Test Project and MSTest to wrap our WatiN code.
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Create a new &amp;quot;Test Project&amp;quot; in Visual Studio named &amp;quot;WatinSample&amp;quot;.
The language is up to you, but all of the examples in this post will use C#. 
&lt;/li&gt;
&lt;li&gt;
Feel free to delete the Authoring Tests document, the Manual Test file, and UnitTest1.cs.
We won't be using these. 
&lt;/li&gt;
&lt;li&gt;
Add a reference to WatiN.Core.dll from the bin directory of your extracted WatiN download. 
&lt;/li&gt;
&lt;li&gt;
Compile. 
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Exercise 1: My First Browser Tests
&lt;/h3&gt;
&lt;p&gt;
In our first test, we will use the project we just created to test Google's home page.
After accessing &lt;a href="http://www.google.com"&gt;http://www.google.com&lt;/a&gt;, we will
check a few properties of the browser and a few loaded elements to ensure that the
expected page was returned. The first thing we will need is a new Unit Test class
to start our testing.
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Create a new class (Right click on the &amp;quot;WatinSample&amp;quot; project and select
Add –&amp;gt; Class…), called WhenViewingTheGoogleHomePage. 
&lt;/li&gt;
&lt;li&gt;
Mark the class as public. 
&lt;/li&gt;
&lt;li&gt;
Add the MSTest [TestClass] attribute to the new class. 
&lt;/li&gt;
&lt;li&gt;
Compile. 
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="csharp:nocontrols" name="code"&gt;using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace WatinSample
{
  [TestClass]
  public class WhenViewingTheGoogleHomePage
  {
  }
}&lt;/pre&gt;
&lt;h4&gt;Make an instance of the browser
&lt;/h4&gt;
&lt;p&gt;
Now that we have a test class, we can start writing WatiN code. Each of our tests
will first need a Browser object to test against. Using methods attributed with TestInitialize
and TestCleanup, we can create a browser instance before the test starts and shut
it down when the test is complete.
&lt;/p&gt;
&lt;p&gt;
Creating an instance of a browser in WatiN is easy: simply create a new instance of
the IE class, passing in a URL. We can assign this new class to a field of type Browser,
which is a base class of all browser classes in WatiN. Currently, WatiN supports Internet
Explorer and Firefox.
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Create a private field in the test class named browserInstance of type WatiN.Core.Browser.
Add a using statement to WatiN.Core if you wish. 
&lt;/li&gt;
&lt;li&gt;
Create a test initialization method named WithAnInstanceOfTheBrowser and give it the
[TestInitialize] attribute. Within this method, create a new instance of the IE class,
passing in the Google URL, &lt;a href="http://www.google.com"&gt;http://www.google.com&lt;/a&gt;,
and assigning the instance to the browserInstance field. 
&lt;/li&gt;
&lt;li&gt;
Finally, create a test cleanup method named ShutdownBrowserWhenDone and give it the
[TestCleanup] attribute. Within this method, execute the Close() method on our browser
instance and assign the field to null to assist with object disposal. 
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="csharp:nocontrols" name="code"&gt;using Microsoft.VisualStudio.TestTools.UnitTesting;
using WatiN.Core;

namespace WatinSample
{
  [TestClass]
  public class WhenViewingTheGoogleHomePage
  {
    Browser browserInstance;

    [TestInitialize]
    public void WithAnInstanceOfTheBrowser()
    {
      browserInstance = new IE(&amp;quot;http://www.google.com&amp;quot;);
    }

    [TestCleanup]
    public void ShutdownBrowserWhenDone()
    {
      browserInstance.Close();
      browserInstance = null;
    }
  }
}&lt;/pre&gt;
&lt;h4&gt;Our First Tests: Checking for existence of an element
&lt;/h4&gt;
&lt;p&gt;
There are three prominent items on the Google home page: the Google logo, the search
criteria text box, and the search button. Using WatiN, we can check for them all.
The WatiN Browser object contains an Elements collection, which is a flattened collection
of every element in the entire DOM. Like any collection, you can use Linq and lambda
expressions to search for items within this collection. Alternately, you may also
use the Element method, which accepts the same lambda expression that would be used
within the Where extension method on the collection, and returns the first or default
element. For more specific searches, WatiN's Browser object includes similar collections
and methods for searching explicitly for Images (&amp;lt;IMG&amp;gt;), Paras (&amp;lt;P&amp;gt;),
Text Fields (&amp;lt;INPUT type=&amp;quot;text&amp;quot; /&amp;gt;), and so on.
&lt;/p&gt;
&lt;p&gt;
On each returned Element (or derived Para, Image, or Text Field, etc., all of which
inherit from Element), WatiN supplies properties for accessing the CSS Class, Id,
InnerHtml, Name, Tag, Text, Value, or many other attributes. The method GetAttributeValue(string
attributeName) is provided for accessing other attributes that are not explicitly
defined on the object (uncommon attributes and custom attributes). Finally, elements
also contain a Style property, which not only gives access to the inline style attribute,
but also any CSS properties associated with the element from Internal Style (in the
Page Head) or External Style (in an external style sheet).
&lt;/p&gt;
&lt;p&gt;
On to checking for the three elements within the Google home page: the logo, the criteria
input, and the search button. First, check for the existence of the Google logo graphic.
The image can be found by searching the DOM for an image with an Id of &amp;quot;logo&amp;quot;.
WatiN works very closely with lambda expressions, so we can use these to help us find
out graphic.
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Create a new public method named PageShouldContainGoogleLogo. 
&lt;/li&gt;
&lt;li&gt;
Add the MSTest [TestMethod] attribute to the method. 
&lt;/li&gt;
&lt;li&gt;
Search for and assert on the existence of an image with the Id of &amp;quot;logo&amp;quot;. 
&lt;/li&gt;
&lt;li&gt;
Optionally, we can also check that the image has the expected Alt attribute; in this
case, the value should be &amp;quot;Google&amp;quot;. 
&lt;/li&gt;
&lt;li&gt;
Compile and run the test. The test should pass. 
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="csharp:nocontrols" name="code"&gt;[TestMethod]
public void PageShouldContainGoogleLogo()
{
  Image googleLogo;
  googleLogo = browserInstance.Image(img =&amp;gt; img.Id == &amp;quot;logo&amp;quot;);
  Assert.IsTrue(googleLogo.Exists);
  Assert.AreEqual(&amp;quot;Google&amp;quot;, googleLogo.Alt);
}&lt;/pre&gt;
&lt;p&gt;
Next, check for the existence of the search criteria input box. WatiN refers to these
elements as Text Fields, using the TextField type. Additionally, this form field is
identified by its Name rather than its Id. In Google, the name given to the criteria
input is &amp;quot;q&amp;quot;.
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Create a new public method named PageShouldContainSearchCriteriaInput and give it
the [TestMethod] attribute. 
&lt;/li&gt;
&lt;li&gt;
Search for and assert on the existence of a Text Field with the name &amp;quot;q&amp;quot;. 
&lt;/li&gt;
&lt;li&gt;
Compile and run the test. The test should pass. 
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="csharp:nocontrols" name="code"&gt;[TestMethod]
public void PageShouldContainSearchCriteriaInput()
{
  TextField criteriaInput;
  criteriaInput = browserInstance.TextField(tf =&amp;gt; tf.Name == &amp;quot;q&amp;quot;);
  Assert.IsTrue(criteriaInput.Exists);
}&lt;/pre&gt;
&lt;p&gt;
Finally, check for the existence of the search button using the Button method. In
our lambda expression, it is not important to know if the field is identified by a
Name property or an Id attribute, as WatiN supplies a IdOrName property to help us
find the element. The value to identify the button is &amp;quot;btnG&amp;quot;.
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Create a new public method named PageShouldContainSearchButton and give it the [TestMethod]
attribute. 
&lt;/li&gt;
&lt;li&gt;
Search for and assert on the existence of a Button with the Id or Name of 'btnG&amp;quot;. 
&lt;/li&gt;
&lt;li&gt;
Optionally, we can also check the value of the button, which is the text displayed
on the button on-screen. This text should be &amp;quot;Google Search&amp;quot;. 
&lt;/li&gt;
&lt;li&gt;
Compile and run the test. The test should pass. 
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="csharp:nocontrols" name="code"&gt;[TestMethod]
public void PageShouldContainSearchButton()
{
  Button searchButton;
  searchButton = browserInstance.Button(btn =&amp;gt; btn.IdOrName == &amp;quot;btnG&amp;quot;);
  Assert.IsTrue(searchButton.Exists);
  Assert.AreEqual(&amp;quot;Google Search&amp;quot;, searchButton.Value);
}&lt;/pre&gt;
&lt;h4&gt;Working with Style
&lt;/h4&gt;
&lt;p&gt;
WatiN can access properties on the DOM beyond just Text values and Alt attributes.
WatiN also has full access to the style that CSS has applied to an element. Let's
check out a few CSS properties, both those explicitly defined by WatiN and those implicitly
accessible through the WatiN framework.
&lt;/p&gt;
&lt;p&gt;
For our first style check, we'll take a look at the default font family used on the
Google Home Page. Font Family is one of the explicitly available style properties
on a WatiN element. Some others, like Color, Display, and Height are also explicitly
defined.
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Create a new public test method named BodyShouldUseArialFontFamily. 
&lt;/li&gt;
&lt;li&gt;
Assert that the font family assigned to the body matches &amp;quot;arial, sans-serif&amp;quot;. 
&lt;/li&gt;
&lt;li&gt;
Compile and run the test. The test should pass. 
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="csharp:nocontrols" name="code"&gt;[TestMethod]
public void BodyShouldUseArialFontFamily()
{
  Assert.AreEqual(&amp;quot;arial, sans-serif&amp;quot;, browserInstance.Body.Style.FontFamily);
}&lt;/pre&gt;
&lt;p&gt;
For our second style check, we will look for an implicit style definition. At the
top of the Google Home Page is a series of links to other areas of Google, such as
Images, Videos, Maps, and News. At the end of this list is a More link, that when
clicked, displays a hidden DIV tag containing even more links, such as Books, Finance,
and Google Translate. Since we do not have any code in our test initialization that
interacts with the browser, and thus nothing that is clicking the More link, that
DIV should still have a hidden visibility. However, since Visibility isn't an explicitly
defined style property within WatiN, we need to use the GetAttributeValue method to
retrieve the current visibility setting.
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Create a new public test method named MoreItemsShouldNotBeVisibleOnPageLoad. 
&lt;/li&gt;
&lt;li&gt;
Search for the More Items DIV. It's Id is &amp;quot;gbi&amp;quot;. 
&lt;/li&gt;
&lt;li&gt;
Using the property lookup method, GetAttributeValue(string attributeName), check that
the Visibility is set to &amp;quot;hidden&amp;quot;. 
&lt;/li&gt;
&lt;li&gt;
Compile and run the test. The test should pass. 
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="csharp:nocontrols" name="code"&gt;[TestMethod]
public void MoreItemsShouldNotBeVisibleOnPageLoad()
{
  var googleBarMoreItems = browserInstance.Div(gbi =&amp;gt; gbi.Id == &amp;quot;gbi&amp;quot;);
  Assert.AreEqual(&amp;quot;hidden&amp;quot;, googleBarMoreItems.Style.GetAttributeValue(&amp;quot;visibility&amp;quot;));
}&lt;/pre&gt;
&lt;h3&gt;Exercise 2: Interacting with the Browser
&lt;/h3&gt;
&lt;p&gt;
Browser Integration tests are more than just loading a page and checking a few element
attributes. Our tests may also need to enter values into form fields, click links
and buttons, or interact with browser navigation like the back button. WatiN fully
supports all of these features in a very intuitive fashion.
&lt;/p&gt;
&lt;h4&gt;A new test class, this time with Search Capability
&lt;/h4&gt;
&lt;p&gt;
Create a new test class, similar to what we did in Exercise 1, calling the new test
class WhenViewingGoogleSearchResultsForComeJamWithUs. Also add in the TestInitialize
and TestCleanup methods that open and close the browser. However, this time, after
we load &lt;a href="http://www.google.com"&gt;http://www.google.com&lt;/a&gt;, enter a value into
the search criteria input and then click the Google Search button.
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Create a new class named WhenViewingGoogleSearchResultsForComeJamWithUs, similar to
what was done in Exercise 1. 
&lt;/li&gt;
&lt;li&gt;
Add in the TestInitialize and TestCleanup methods from Exercise 1. Name the Initialize
method WithAnInstanceOfTheBrowserSearchingGoogle. 
&lt;/li&gt;
&lt;li&gt;
After the code that initializes the IE class, find the search criteria Text Field
and set its value to &amp;quot;Come Jam With Us&amp;quot;. 
&lt;/li&gt;
&lt;li&gt;
After setting the Text Field value, click the Google Search button by calling the
Click() method on the Button class. 
&lt;/li&gt;
&lt;li&gt;
Compile. 
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="csharp:nocontrols" name="code"&gt;using Microsoft.VisualStudio.TestTools.UnitTesting;
using WatiN.Core;

namespace WatinSample
{
  [TestClass]
  public class WhenViewingGoogleSearchResultsForComeJamWithUs
  {
    Browser browserInstance;

    [TestInitialize]
    public void WithAnInstanceOfTheBrowserSearchingGoogle()
    {
      browserInstance = new IE(@&amp;quot;http://www.google.com&amp;quot;);
      TextField criteria =
        browserInstance.TextField(tf =&amp;gt; tf.Name == &amp;quot;q&amp;quot;);
      criteria.Value = &amp;quot;Come Jam With Us&amp;quot;;
      Button search =
        browserInstance.Button(btn =&amp;gt; btn.IdOrName == &amp;quot;btnG&amp;quot;);
      search.Click();
    }

    [TestCleanup]
    public void ShutdownBrowserWhenDone()
    {
      browserInstance.Close();
      browserInstance = null;
    }
  }
}&lt;/pre&gt;
&lt;p&gt;
With this code, or initialized test will load the Google Home Page and will conduct
a search for &amp;quot;Come Jam With Us&amp;quot;.
&lt;/p&gt;
&lt;h4&gt;Validating the Search Results Page
&lt;/h4&gt;
&lt;p&gt;
For our first verification, let's check the URL for the browser window. The search
result URL should contain the search criteria in the URL's query string; we can validate
this using the URL property on our instance of the Browser object.
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Create a new public test method named BrowserUrlShouldContainSearchCriteria. 
&lt;/li&gt;
&lt;li&gt;
Validate that the current browser URL contains the search criteria information, &amp;quot;q=Come+Jam+With+Us&amp;quot;. 
&lt;/li&gt;
&lt;li&gt;
Compile and run the test. The test should pass. 
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="csharp:nocontrols" name="code"&gt;[TestMethod]
public void BrowserUrlShouldContainSearchCriteria()
{
  Assert.IsTrue(browserInstance.Url.Contains(@&amp;quot;q=Come+Jam+With+Us&amp;quot;));
}&lt;/pre&gt;
&lt;h4&gt;Finding Child Elements
&lt;/h4&gt;
&lt;p&gt;
With WatiN, we are not just limited to searching for items directly from the Browser
object. We can also search for child elements directly from their parent element or
any ancestor element. Our search results should contain a search result item linking
to the Come Jam With Us web site. The Google Results page contains a DIV identified
as &amp;quot;res&amp;quot; that serves as a container for all search result information. Rather
than checking that our Come Jam With Us link exists somewhere on the page, we should
search for it directly within the results DIV.
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Create a new public test method named ResultsShouldContainLinkToComeJamWithUs. 
&lt;/li&gt;
&lt;li&gt;
From the browser instance, find a DIV identified as &amp;quot;res&amp;quot;. 
&lt;/li&gt;
&lt;li&gt;
Assert that a link to &lt;a href="http://www.comejamwithus.org"&gt;http://www.comejamwithus.org&lt;/a&gt; exists
within the &amp;quot;res&amp;quot; DIV. 
&lt;/li&gt;
&lt;li&gt;
Compile and run the test. The test should pass. 
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="csharp:nocontrols" name="code"&gt;[TestMethod]
public void ResultsShouldContainLinkToComeJamWithUs()
{
  Link comeJamWithUs;
  Div searchResults = browserInstance.Div(div =&amp;gt; div.IdOrName == &amp;quot;res&amp;quot;);
  comeJamWithUs =
    searchResults.Link(link =&amp;gt; link.Url == @&amp;quot;http://www.comejamwithus.org/&amp;quot;);
  Assert.IsTrue(comeJamWithUs.Exists);
}&lt;/pre&gt;
&lt;h4&gt;Inner Text verses InnerHtml
&lt;/h4&gt;
&lt;p&gt;
An element may contain many child elements. An anchor tag—&amp;lt;A href=&amp;quot;#&amp;quot;&amp;gt;—can
contain text, and child elements may make portions of that text bold, italic, underlined,
or even bright red. Through WatiN, we can access that inner content as straight text
without the formatting, or as the InnerHtml including all of the child elements.
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Create two public test methods, one named ResultsLinkContainsComeJamWithUsText and
the other named ResultsLinkContainsComeJamWithUsHtml. 
&lt;/li&gt;
&lt;li&gt;
In both methods, search for the results DIV, as we did in the previous test. 
&lt;/li&gt;
&lt;li&gt;
In both methods, search through the results DIV for a link with a URL matching &lt;a href="http://www.comejamwithus.org"&gt;http://www.comejamwithus.org&lt;/a&gt; 
&lt;/li&gt;
&lt;li&gt;
In the Text method, assert that the text of the link matches &amp;quot;Come Jam with us
(Software Development Study Group)&amp;quot;. Note that the value contains no child HTML
elements. 
&lt;/li&gt;
&lt;li&gt;
In the HTML method, assert that the InnerHtml of the link matches &amp;quot;&amp;lt;EM&amp;gt;Come
Jam with us&amp;lt;/EM&amp;gt; (Software Development Study Group)&amp;quot;. Note that for the
same link, we now have the emphasis tags surrounding Come Jam With Us. 
&lt;/li&gt;
&lt;li&gt;
Compile and run both tests. The tests should pass.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="csharp:nocontrols" name="code"&gt;[TestMethod]
public void ResultsLinkContainsComeJamWithUsText()
{
  Link comeJamWithUs;
  Div searchResults = browserInstance.Div(div =&amp;gt; div.IdOrName == &amp;quot;res&amp;quot;);
  comeJamWithUs =
    searchResults.Link(link =&amp;gt; link.Url == @&amp;quot;http://www.comejamwithus.org/&amp;quot;);
  Assert.AreEqual(@&amp;quot;Come Jam with us (Software Development Study Group)&amp;quot;,
    comeJamWithUs.Text);
}

[TestMethod]
public void ResultsLinkContainsComeJamWithUsHtml()
{
  Link comeJamWithUs;
  Div searchResults = browserInstance.Div(div =&amp;gt; div.IdOrName == &amp;quot;res&amp;quot;);
  comeJamWithUs =
    searchResults.Link(link =&amp;gt; link.Url == @&amp;quot;http://www.comejamwithus.org/&amp;quot;);
  Assert.AreEqual(
    @&amp;quot;&amp;lt;EM&amp;gt;Come Jam with us&amp;lt;/EM&amp;gt; (Software Development Study Group)&amp;quot;,
    comeJamWithUs.InnerHtml);
}&lt;/pre&gt;
&lt;h4&gt;Back to the Start
&lt;/h4&gt;
&lt;p&gt;
As previously mentioned, we can also fully interact with the browser, itself. Our
test initialization started from the Google Home Page and performed a search. Using
functionality built in to WatiN, we can execute the browser's back navigation to return
to the previous page.
&lt;/p&gt;
&lt;p&gt;
For our next test, execute a back navigation and verify that the browser's URL matches &lt;a href="http://www.google.com/"&gt;http://www.google.com/&lt;/a&gt;.
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Create a public test method named PageShouldHaveComeFromGoogleDotCom. 
&lt;/li&gt;
&lt;li&gt;
Execute back navigation in the browser by calling the Back() method on browserInstance. 
&lt;/li&gt;
&lt;li&gt;
Validate that the browser URL matches &lt;a href="http://www.google.com/"&gt;http://www.google.com/&lt;/a&gt;. 
&lt;/li&gt;
&lt;li&gt;
Compile and run the test. The test should pass.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="csharp:nocontrols" name="code"&gt;[TestMethod]
public void PageShouldHaveComeFromGoogleDotCom()
{
  string previousUrl;
  browserInstance.Back();
  previousUrl = browserInstance.Url;
  Assert.AreEqual(@&amp;quot;http://www.google.com/&amp;quot;, previousUrl);
}&lt;/pre&gt;
&lt;h4&gt;Putting it all together
&lt;/h4&gt;
&lt;p&gt;
Some interactions on a page cause element properties to change. An example of this
is the More link from Exercise 1; when the end-user clicks the More link, the More
Items DIV appears because the link's click event changes the Visibility style property
of the DIV to visible. For our final test, we will use what we have learned to test
this functionality.
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Create a new public test method named MoreItemsShouldBeVisibleOnMoreLinkClick.&lt;/li&gt;
&lt;li&gt;
Search for the header bar of Google links, a DIV with an Id of &amp;quot;gbar&amp;quot;.&lt;/li&gt;
&lt;li&gt;
Within &amp;quot;gbar&amp;quot;, search for the More Items DIV by an Id or Name of &amp;quot;gbi&amp;quot;. 
&lt;/li&gt;
&lt;li&gt;
Assert that the visibility style property has a value of &amp;quot;hidden&amp;quot;. 
&lt;/li&gt;
&lt;li&gt;
Within &amp;quot;gbar&amp;quot;, search for the More link by its class name, &amp;quot;gb3&amp;quot;.
Note that since a class attribute may contain multiple class definitions, this is
accomplished by validating that the class attribute contains the class you are searching
for. 
&lt;/li&gt;
&lt;li&gt;
Execute a Click event on the link. 
&lt;/li&gt;
&lt;li&gt;
Assert that the visibility style property of the More Items DIV has changed to &amp;quot;visible&amp;quot;. 
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="csharp:nocontrols" name="code"&gt;[TestMethod]
public void MoreItemsShouldBeVisibleOnMoreLinkClick()
{
  var googleBar = browserInstance.Div(gbar =&amp;gt; gbar.Id == &amp;quot;gbar&amp;quot;);
  var googleBarMoreItems = googleBar.Div(gbi =&amp;gt; gbi.Id == &amp;quot;gbi&amp;quot;);
  Assert.AreEqual(&amp;quot;hidden&amp;quot;,
    googleBarMoreItems.Style.GetAttributeValue(&amp;quot;visibility&amp;quot;));
  var googleBarMoreLink =
    googleBar.Link(link =&amp;gt; link.ClassName.Contains(&amp;quot;gb3&amp;quot;));
  googleBarMoreLink.Click();
  Assert.AreEqual(&amp;quot;visible&amp;quot;,
    googleBarMoreItems.Style.GetAttributeValue(&amp;quot;visibility&amp;quot;));
}&lt;/pre&gt;
&lt;h4&gt;That's It
&lt;/h4&gt;
&lt;p&gt;
Now that we have spent some time on basic properties, interactions, and style sheets
within the WatiN framework, hopefully you can apply this to your own application and
get started with your own browser-based integration tests. If you would like more
information, I encourage you to check out the WatiN site at &lt;a href="http://watin.sourceforge.net"&gt;http://watin.sourceforge.net&lt;/a&gt;.
And as always, if you have any questions, drop me a line.
&lt;/p&gt;
&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:9a272a14-7cc1-4234-a4bc-8531ce7b8597" class="wlWriterEditableSmartContent"&gt;Technorati
Tags: &lt;a href="http://technorati.com/tags/WatiN" rel="tag"&gt;WatiN&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Jam+Session" rel="tag"&gt;Jam
Session&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Coding+Exercise" rel="tag"&gt;Coding
Exercise&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Learn+to+Code" rel="tag"&gt;Learn to
Code&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Browser+Testing" rel="tag"&gt;Browser Testing&lt;/a&gt;
&lt;/div&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=5a613524-5607-4fbb-a89f-74b5afb7c5e9" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,5a613524-5607-4fbb-a89f-74b5afb7c5e9.aspx</comments>
      <category>Learn to Code</category>
      <category>Testing</category>
      <category>Tools</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=31b3c96d-5f73-4a20-bc3c-c155b5238071</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,31b3c96d-5f73-4a20-bc3c-c155b5238071.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,31b3c96d-5f73-4a20-bc3c-c155b5238071.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=31b3c96d-5f73-4a20-bc3c-c155b5238071</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Recently, I was writing unit tests for a web application built on Castle ActiveRecord.
My goal was to mock ActiveRecord's data store, rather than use a Microsoft SQL Server
database for testing. SQL Server backing just would not fit my needs, where a mock
data store would serve much better: 
</p>
        <ul>
          <li>
I did not want a SQL Server installation to be a requirement for me, the other developers,
and my Continuous Integration server. 
</li>
          <li>
I wanted something fast. I didn't want to have to wait for SQL Server to build / tear
down my schema. 
</li>
          <li>
I wanted something isolated, so the other developers, and my CI server, and I wouldn't
have contention over the same database, but didn't want to have to deal with independent
SQL Server instances for everyone.</li>
        </ul>
        <p>
Essentially what I wanted was a local, in-memory database that could be quickly initialized
and destroyed specifically for my tests. The resolution was using SQLite for ADO.Net,
using an in-memory SQLite instance. <a href="http://brian.genisio.org/2008/07/active-record-mock-framework.html">Brian
Genisio</a> has a fantastic write-up on mocking the data store for Castle ActiveRecord
using this SQLite for ADO.Net. The post made my day, since I was looking for a way
to do this, and he had already done all of the work &lt;grin/&gt;. I encourage you
to read <a href="http://brian.genisio.org/2008/07/active-record-mock-framework.html">his
post</a> first, as the rest of this post assumes you have already done so.
</p>
        <p>
Brian's post was a great help to me; I made a few enhancements to what he started
to make it fit my needs even more. 
</p>
        <p>
My updated version of Brian's ActiveRecordMockConnectionProvider class:
</p>
        <pre class="csharp:nocontrols" name="code">using System;
using System.Collections;
using System.Data;
using System.Reflection;
using Castle.ActiveRecord;
using Castle.ActiveRecord.Framework;
using Castle.ActiveRecord.Framework.Config;
using NHibernate.Connection;

namespace ActiveRecordTestHelper
{
  public class ActiveRecordMockConnectionProvider : DriverConnectionProvider
  {
    private static IDbConnection _connection;

    private static IConfigurationSource MockConfiguration
    {
      get
      {
        var properties = new Hashtable
            {
              {"hibernate.connection.driver_class",
                "NHibernate.Driver.SQLite20Driver"},
              {"hibernate.dialect", "NHibernate.Dialect.SQLiteDialect"},
              {"hibernate.connection.provider", ConnectionProviderLocator},
              {"hibernate.connection.connection_string",
                "Data Source=:memory:;Version=3;New=True;"}
            };

        var source = new InPlaceConfigurationSource();
        source.Add(typeof (ActiveRecordBase), properties);

        return source;
      }
    }

    private static string ConnectionProviderLocator
    {
      get { return String.Format("{0}, {1}", TypeOfEnclosingClass.FullName,
                                    EnclosingAssemblyName.Split(',')[0]); }
    }

    private static Type TypeOfEnclosingClass
    {
      get { return MethodBase.GetCurrentMethod().DeclaringType; }
    }

    private static string EnclosingAssemblyName
    {
      get { return Assembly.GetAssembly(TypeOfEnclosingClass).FullName; }
    }

    public override IDbConnection GetConnection()
    {
      if (_connection == null)
        _connection = base.GetConnection();

      return _connection;
    }

    public override void CloseConnection(IDbConnection conn) {}

    /// &lt;summary&gt;
    /// Destroys the connection that is kept open in order to keep the
    /// in-memory database alive. Destroying the connection will destroy
    /// all of the data stored in the mock database. Call this method when
    /// the test is complete.
    /// &lt;/summary&gt;
    public static void ExplicitlyDestroyConnection()
    {
      if (_connection != null)
      {
        _connection.Close();
        _connection = null;
      }
    }

    /// &lt;summary&gt;
    /// Initializes ActiveRecord and the Database that ActiveRecord uses to
    /// store the data. Call this method before the test executes.
    /// &lt;/summary&gt;
    /// &lt;param name="useDynamicConfiguration"&gt;
    /// Use reflection to build configuration, rather than the Configuration
    /// file.
    /// &lt;/param&gt;
    /// &lt;param name="types"&gt;
    /// A list of ActiveRecord types that will be created in the database
    /// &lt;/param&gt;
    public static void InitializeActiveRecord(bool useDynamicConfiguration,
                                              params Type[] types)
    {
      ActiveRecordStarter.ResetInitializationFlag();
      IConfigurationSource configurationSource = useDynamicConfiguration
                                       ? MockConfiguration
                                       : ActiveRecordSectionHandler.Instance;
      ActiveRecordStarter.Initialize(configurationSource, types);
      ActiveRecordStarter.CreateSchema();
    }

    /// &lt;summary&gt;
    /// Initializes ActiveRecord and the Database that ActiveRecord uses to
    /// store the data based. Configuration is dynamically generated using
    /// reflection. Call this method before the test executes.
    /// &lt;/summary&gt;
    /// &lt;param name="types"&gt;
    /// A list of ActiveRecord types that will be created in the database
    /// &lt;/param&gt;
    [Obsolete("Use InitializeActiveRecord(bool, params Type[])")]
    public static void InitializeActiveRecord(params Type[] types)
    {
      InitializeActiveRecord(true, types);
    }
  }
}
</pre>
        <p>
In my class I have overloaded the method InitializeActiveRecord to include the boolean
parameter useDynamicConfiguration, governing if the configuration is dynamically built
using Reflection or if the configuration in your app.config is used instead. If the
parameter is not specified, it default to false (Use app.config).
</p>
        <p>
Why? Brian's original code, as is, is meant to be dropped in as a new class within
your test assembly, and uses reflection to dynamically determine the provider information,
including the fully-qualified class name and assembly of the new DriverConnectionProvider.
Reflection makes for little effort for me when I want to drop in the class into a
new test assembly. Drop it in and go; no need to even modify the app.config. However,
if I want to switch my provider back to SQL Server or some other platform, I have
to modify the code and recompile.
</p>
        <p>
My modifications remove the restriction of configuration in compiled code, allow configuration
to be placed in app.config, while preserving the existing functionality for backward
compatibility. By allowing app.config-based configuration, users can quickly switch
back-and-forth between SQLite and SQL Server databases without having to modify and
recompile the application. To use this customized ActiveRecordMockConnectionProvider
class without dynamic configuration, add the following code to the configuration block
of your test's app.config.
</p>
        <pre class="xml:nocontrols:nogutter" name="code">&lt;activerecord&gt;
  &lt;config&gt;
    &lt;add key="hibernate.connection.driver_class"
      value="NHibernate.Driver.SQLite20Driver" /&gt;
    &lt;add key="hibernate.dialect" value="NHibernate.Dialect.SQLiteDialect" /&gt;
    &lt;add key="hibernate.connection.provider"
      value="ActiveRecordTestHelper.ActiveRecordMockConnectionProvider, ActiveRecordTestHelper" /&gt;
    &lt;add key="hibernate.connection.connection_string"
      value="Data Source=:memory:;Version=3;New=True;" /&gt;
  &lt;/config&gt;
&lt;/activerecord&gt;</pre>
        <p>
The catch is that you will need to know the fully-qualified class and assembly information
for your provider (Line 6, above). This means you will have to modify it for every
test assembly. To get around this, compile the code into a separate assembly (I called
mine 'ActiveRecordTestHelper.dll'), and reference this new assembly in your test assembly.
By using a separate assembly, you no longer need to modify the activerecord configuration
block for every instance, and can reuse the same block everywhere the new assembly
is referenced.
</p>
        <p>
And to switch over from in-memory SQLite to SQL Server, just comment out the SQLite
block and uncomment the SQL Server block (or whatever other provider you are using).
</p>
        <blockquote>
          <p>
            <b>Download:</b>
            <a href="http://www.cptloadtest.com/content/binary/ActiveRecordMockConnectionProvider.zip">ActiveRecordMockConnectionProvider.zip</a>
            <br />
Includes:
</p>
          <ul>
            <li>
Source code for the <em>ActiveRecordMockConnectionProvider</em> class 
</li>
            <li>
Sample Class that uses the new provider 
</li>
            <li>
Sample <em>app.config</em> containing the ActiveRecord block using the provider. 
</li>
            <li>
Compiled versions of <em>ActiveRecordTestHelper.dll</em></li>
          </ul>
          <p>
As always, this code is provided with no warranties or guarantees. Use at your own
risk. Your mileage may vary.<br />
And thanks again to Brian Genisio.
</p>
        </blockquote>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=31b3c96d-5f73-4a20-bc3c-c155b5238071" />
      </body>
      <title>Unit Testing ActiveRecord Applications using Mock Databases</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,31b3c96d-5f73-4a20-bc3c-c155b5238071.aspx</guid>
      <link>http://www.cptloadtest.com/2008/10/30/Unit-Testing-ActiveRecord-Applications-Using-Mock-Databases.aspx</link>
      <pubDate>Thu, 30 Oct 2008 14:10:01 GMT</pubDate>
      <description>&lt;p&gt;
Recently, I was writing unit tests for a web application built on Castle ActiveRecord.
My goal was to mock ActiveRecord's data store, rather than use a Microsoft SQL Server
database for testing. SQL Server backing just would not fit my needs, where a mock
data store would serve much better: 
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
I did not want a SQL Server installation to be a requirement for me, the other developers,
and my Continuous Integration server. 
&lt;li&gt;
I wanted something fast. I didn't want to have to wait for SQL Server to build / tear
down my schema. 
&lt;li&gt;
I wanted something isolated, so the other developers, and my CI server, and I wouldn't
have contention over the same database, but didn't want to have to deal with independent
SQL Server instances for everyone.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Essentially what I wanted was a local, in-memory database that could be quickly initialized
and destroyed specifically for my tests. The resolution was using SQLite for ADO.Net,
using an in-memory SQLite instance. &lt;a href="http://brian.genisio.org/2008/07/active-record-mock-framework.html"&gt;Brian
Genisio&lt;/a&gt; has a fantastic write-up on mocking the data store for Castle ActiveRecord
using this SQLite for ADO.Net. The post made my day, since I was looking for a way
to do this, and he had already done all of the work &amp;lt;grin/&amp;gt;. I encourage you
to read &lt;a href="http://brian.genisio.org/2008/07/active-record-mock-framework.html"&gt;his
post&lt;/a&gt; first, as the rest of this post assumes you have already done so.
&lt;/p&gt;
&lt;p&gt;
Brian's post was a great help to me; I made a few enhancements to what he started
to make it fit my needs even more. 
&lt;/p&gt;
&lt;p&gt;
My updated version of Brian's ActiveRecordMockConnectionProvider class:
&lt;/p&gt;
&lt;pre class="csharp:nocontrols" name="code"&gt;using System;
using System.Collections;
using System.Data;
using System.Reflection;
using Castle.ActiveRecord;
using Castle.ActiveRecord.Framework;
using Castle.ActiveRecord.Framework.Config;
using NHibernate.Connection;

namespace ActiveRecordTestHelper
{
  public class ActiveRecordMockConnectionProvider : DriverConnectionProvider
  {
    private static IDbConnection _connection;

    private static IConfigurationSource MockConfiguration
    {
      get
      {
        var properties = new Hashtable
            {
              {"hibernate.connection.driver_class",
                "NHibernate.Driver.SQLite20Driver"},
              {"hibernate.dialect", "NHibernate.Dialect.SQLiteDialect"},
              {"hibernate.connection.provider", ConnectionProviderLocator},
              {"hibernate.connection.connection_string",
                "Data Source=:memory:;Version=3;New=True;"}
            };

        var source = new InPlaceConfigurationSource();
        source.Add(typeof (ActiveRecordBase), properties);

        return source;
      }
    }

    private static string ConnectionProviderLocator
    {
      get { return String.Format("{0}, {1}", TypeOfEnclosingClass.FullName,
                                    EnclosingAssemblyName.Split(',')[0]); }
    }

    private static Type TypeOfEnclosingClass
    {
      get { return MethodBase.GetCurrentMethod().DeclaringType; }
    }

    private static string EnclosingAssemblyName
    {
      get { return Assembly.GetAssembly(TypeOfEnclosingClass).FullName; }
    }

    public override IDbConnection GetConnection()
    {
      if (_connection == null)
        _connection = base.GetConnection();

      return _connection;
    }

    public override void CloseConnection(IDbConnection conn) {}

    /// &amp;lt;summary&amp;gt;
    /// Destroys the connection that is kept open in order to keep the
    /// in-memory database alive. Destroying the connection will destroy
    /// all of the data stored in the mock database. Call this method when
    /// the test is complete.
    /// &amp;lt;/summary&amp;gt;
    public static void ExplicitlyDestroyConnection()
    {
      if (_connection != null)
      {
        _connection.Close();
        _connection = null;
      }
    }

    /// &amp;lt;summary&amp;gt;
    /// Initializes ActiveRecord and the Database that ActiveRecord uses to
    /// store the data. Call this method before the test executes.
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;param name="useDynamicConfiguration"&amp;gt;
    /// Use reflection to build configuration, rather than the Configuration
    /// file.
    /// &amp;lt;/param&amp;gt;
    /// &amp;lt;param name="types"&amp;gt;
    /// A list of ActiveRecord types that will be created in the database
    /// &amp;lt;/param&amp;gt;
    public static void InitializeActiveRecord(bool useDynamicConfiguration,
                                              params Type[] types)
    {
      ActiveRecordStarter.ResetInitializationFlag();
      IConfigurationSource configurationSource = useDynamicConfiguration
                                       ? MockConfiguration
                                       : ActiveRecordSectionHandler.Instance;
      ActiveRecordStarter.Initialize(configurationSource, types);
      ActiveRecordStarter.CreateSchema();
    }

    /// &amp;lt;summary&amp;gt;
    /// Initializes ActiveRecord and the Database that ActiveRecord uses to
    /// store the data based. Configuration is dynamically generated using
    /// reflection. Call this method before the test executes.
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;param name="types"&amp;gt;
    /// A list of ActiveRecord types that will be created in the database
    /// &amp;lt;/param&amp;gt;
    [Obsolete("Use InitializeActiveRecord(bool, params Type[])")]
    public static void InitializeActiveRecord(params Type[] types)
    {
      InitializeActiveRecord(true, types);
    }
  }
}
&lt;/pre&gt;
&lt;p&gt;
In my class I have overloaded the method InitializeActiveRecord to include the boolean
parameter useDynamicConfiguration, governing if the configuration is dynamically built
using Reflection or if the configuration in your app.config is used instead. If the
parameter is not specified, it default to false (Use app.config).
&lt;/p&gt;
&lt;p&gt;
Why? Brian's original code, as is, is meant to be dropped in as a new class within
your test assembly, and uses reflection to dynamically determine the provider information,
including the fully-qualified class name and assembly of the new DriverConnectionProvider.
Reflection makes for little effort for me when I want to drop in the class into a
new test assembly. Drop it in and go; no need to even modify the app.config. However,
if I want to switch my provider back to SQL Server or some other platform, I have
to modify the code and recompile.
&lt;/p&gt;
&lt;p&gt;
My modifications remove the restriction of configuration in compiled code, allow configuration
to be placed in app.config, while preserving the existing functionality for backward
compatibility. By allowing app.config-based configuration, users can quickly switch
back-and-forth between SQLite and SQL Server databases without having to modify and
recompile the application. To use this customized ActiveRecordMockConnectionProvider
class without dynamic configuration, add the following code to the configuration block
of your test's app.config.
&lt;/p&gt;
&lt;pre class="xml:nocontrols:nogutter" name="code"&gt;&amp;lt;activerecord&amp;gt;
  &amp;lt;config&amp;gt;
    &amp;lt;add key="hibernate.connection.driver_class"
      value="NHibernate.Driver.SQLite20Driver" /&amp;gt;
    &amp;lt;add key="hibernate.dialect" value="NHibernate.Dialect.SQLiteDialect" /&amp;gt;
    &amp;lt;add key="hibernate.connection.provider"
      value="ActiveRecordTestHelper.ActiveRecordMockConnectionProvider, ActiveRecordTestHelper" /&amp;gt;
    &amp;lt;add key="hibernate.connection.connection_string"
      value="Data Source=:memory:;Version=3;New=True;" /&amp;gt;
  &amp;lt;/config&amp;gt;
&amp;lt;/activerecord&amp;gt;&lt;/pre&gt;
&lt;p&gt;
The catch is that you will need to know the fully-qualified class and assembly information
for your provider (Line 6, above). This means you will have to modify it for every
test assembly. To get around this, compile the code into a separate assembly (I called
mine 'ActiveRecordTestHelper.dll'), and reference this new assembly in your test assembly.
By using a separate assembly, you no longer need to modify the activerecord configuration
block for every instance, and can reuse the same block everywhere the new assembly
is referenced.
&lt;/p&gt;
&lt;p&gt;
And to switch over from in-memory SQLite to SQL Server, just comment out the SQLite
block and uncomment the SQL Server block (or whatever other provider you are using).
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;b&gt;Download:&lt;/b&gt; &lt;a href="http://www.cptloadtest.com/content/binary/ActiveRecordMockConnectionProvider.zip"&gt;ActiveRecordMockConnectionProvider.zip&lt;/a&gt;
&lt;br&gt;
Includes:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Source code for the &lt;em&gt;ActiveRecordMockConnectionProvider&lt;/em&gt; class 
&lt;li&gt;
Sample Class that uses the new provider 
&lt;li&gt;
Sample &lt;em&gt;app.config&lt;/em&gt; containing the ActiveRecord block using the provider. 
&lt;li&gt;
Compiled versions of &lt;em&gt;ActiveRecordTestHelper.dll&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
As always, this code is provided with no warranties or guarantees. Use at your own
risk. Your mileage may vary.&lt;br&gt;
And thanks again to Brian Genisio.
&lt;/p&gt;
&lt;/blockquote&gt;&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=31b3c96d-5f73-4a20-bc3c-c155b5238071" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,31b3c96d-5f73-4a20-bc3c-c155b5238071.aspx</comments>
      <category>Programming</category>
      <category>Testing</category>
      <category>Tools</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=3ee864da-159d-467d-bc59-b9d7a88b58a2</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,3ee864da-159d-467d-bc59-b9d7a88b58a2.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,3ee864da-159d-467d-bc59-b9d7a88b58a2.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=3ee864da-159d-467d-bc59-b9d7a88b58a2</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
If you are new to testing, are looking for some experience in testing, or just want
to have fun breaking things, check out the <a href="http://codex.wordpress.org/WordPress_Bug_Hunts">WordPress
Bug Hunt</a> on 5 July 2006. The WordPress clan is holding a Bug Hunt against versions
2.0.4 and 2.1 in true “fixing them as fast as we can break them” style, as volunteer
coders will be jumping on the bugs as fast as you can get them logged. These guys
would truly appreciate any help you can supply, and you can have some fun unleashing
all of those crazy testing / breaking / hacking tactics that sit in your closet.
</p>
        <p>
WordPress is what runs this site, so your assistance ultimately helps me out, too.
</p>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=3ee864da-159d-467d-bc59-b9d7a88b58a2" />
      </body>
      <title>Testing Experience: The WordPress BugHunt</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,3ee864da-159d-467d-bc59-b9d7a88b58a2.aspx</guid>
      <link>http://www.cptloadtest.com/2006/06/29/Testing-Experience-The-WordPress-BugHunt.aspx</link>
      <pubDate>Thu, 29 Jun 2006 13:18:11 GMT</pubDate>
      <description>&lt;p&gt;
If you are new to testing, are looking for some experience in testing, or just want
to have fun breaking things, check out the &lt;a href="http://codex.wordpress.org/WordPress_Bug_Hunts"&gt;WordPress
Bug Hunt&lt;/a&gt; on 5 July 2006. The WordPress clan is holding a Bug Hunt against versions
2.0.4 and 2.1 in true “fixing them as fast as we can break them” style, as volunteer
coders will be jumping on the bugs as fast as you can get them logged. These guys
would truly appreciate any help you can supply, and you can have some fun unleashing
all of those crazy testing / breaking / hacking tactics that sit in your closet.
&lt;/p&gt;
&lt;p&gt;
WordPress is what runs this site, so your assistance ultimately helps me out, too.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=3ee864da-159d-467d-bc59-b9d7a88b58a2" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,3ee864da-159d-467d-bc59-b9d7a88b58a2.aspx</comments>
      <category>Testing</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=9ca818d8-d9d7-4d19-aec3-370387c131f3</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,9ca818d8-d9d7-4d19-aec3-370387c131f3.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,9ca818d8-d9d7-4d19-aec3-370387c131f3.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=9ca818d8-d9d7-4d19-aec3-370387c131f3</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I never understood the point of manual test scripts. They annoy me. I view them as
nothing more than a candidate for automation. I have never come across a manual script
that wouldn’t be better used as an automation script, which of course violates
the inherent nature of them being <em>manual</em> test scripts. The only value to
manual test scripts is to give them to clients, so that they can run through the new
app you just created for them and feel comfortable about the application (and learn
about the app as they run through the scripts).
</p>
        <p>
          <a href="http://www.kohl.ca/blog/archives/000150.html">Jonathan Kohl</a> presents
the perfect argument about why manual test cases should be extinct. Everyone should
read this. Developers should read it, clients should read it, testers should read
this, and, most definitely, project managers should read this.
</p>
        <p>
Most bugs will never be found by a manual script. They only illustrate the “conventional”
click-path for completing a task, and the developer should have already went through
this during their own testing; there is high probability that this path will already
work. End-users are never going to follow this path, anyway; they will do something
that you entirely don’t expect. They will hit the ‘Back’ button
when you didn’t plan for it, or double-click the ‘Submit’ button
when you didn’t handle it, or bookmark the third step in a five-step wizard.
Scenarios like these will <em>never</em> be tested in a manual script, but <em>could</em> be
tested if so much of the industry wasn’t convinced that scripts are the holy
grail, and <em>will</em> be tested by any tester worth his salt.
</p>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=9ca818d8-d9d7-4d19-aec3-370387c131f3" />
      </body>
      <title>Procedural test scripts should be extinct</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,9ca818d8-d9d7-4d19-aec3-370387c131f3.aspx</guid>
      <link>http://www.cptloadtest.com/2005/11/16/Procedural-Test-Scripts-Should-Be-Extinct.aspx</link>
      <pubDate>Wed, 16 Nov 2005 16:56:33 GMT</pubDate>
      <description>&lt;p&gt;
I never understood the point of manual test scripts. They annoy me. I view them as
nothing more than a candidate for automation. I have never come across a manual script
that wouldn&amp;#8217;t be better used as an automation script, which of course violates
the inherent nature of them being &lt;em&gt;manual&lt;/em&gt; test scripts. The only value to
manual test scripts is to give them to clients, so that they can run through the new
app you just created for them and feel comfortable about the application (and learn
about the app as they run through the scripts).
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.kohl.ca/blog/archives/000150.html"&gt;Jonathan Kohl&lt;/a&gt; presents
the perfect argument about why manual test cases should be extinct. Everyone should
read this. Developers should read it, clients should read it, testers should read
this, and, most definitely, project managers should read this.
&lt;/p&gt;
&lt;p&gt;
Most bugs will never be found by a manual script. They only illustrate the &amp;#8220;conventional&amp;#8221;
click-path for completing a task, and the developer should have already went through
this during their own testing; there is high probability that this path will already
work. End-users are never going to follow this path, anyway; they will do something
that you entirely don&amp;#8217;t expect. They will hit the &amp;#8216;Back&amp;#8217; button
when you didn&amp;#8217;t plan for it, or double-click the &amp;#8216;Submit&amp;#8217; button
when you didn&amp;#8217;t handle it, or bookmark the third step in a five-step wizard.
Scenarios like these will &lt;em&gt;never&lt;/em&gt; be tested in a manual script, but &lt;em&gt;could&lt;/em&gt; be
tested if so much of the industry wasn&amp;#8217;t convinced that scripts are the holy
grail, and &lt;em&gt;will&lt;/em&gt; be tested by any tester worth his salt.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=9ca818d8-d9d7-4d19-aec3-370387c131f3" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,9ca818d8-d9d7-4d19-aec3-370387c131f3.aspx</comments>
      <category>Testing</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=7dcbc600-fa83-4503-9077-040074103484</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,7dcbc600-fa83-4503-9077-040074103484.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,7dcbc600-fa83-4503-9077-040074103484.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=7dcbc600-fa83-4503-9077-040074103484</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Outside of the QA world (and unfortunately, sometimes in the QA world), I’ve heard
people toss around ‘Performance Testing’, ‘Load Testing’, ‘Scalability Testing’, and
‘Stress Testing’, yet always mean the same thing. My clients do this. My project managers
do this. My fellow developers do this. It doesn’t bother me–I’m not some QA psycho
that harasses anyone that doesn’t use exactly the correct term–but I do smirk on the
inside whenever one of these offenses occurs.
</p>
        <p>
Performance testing is not load testing is not scalability testing is not stress testing.
They are not the same thing. They closely relate, but they are not the same thing.
</p>
        <blockquote>
          <ul>
            <li>
Load testing is testing that involves applying a load to the system.</li>
            <li>
Performance testing evaluates how well the system performs.</li>
            <li>
Stress testing looks at how the system behaves under a heavy load.</li>
            <li>
Scalability testing investigates how well the system scales as the load and/or resources
are increased.</li>
          </ul>
          <p>
Alexander Podelko, Load Testing in a Diverse Environment, <em>Software Test &amp;
Performance</em>, October 2005.
</p>
        </blockquote>
        <h3>Performance Testing
</h3>
        <p>
Any type of testing–and I mean <em>any</em> type–that measures the performance (essentially,
speed) of the system in question. Measuring the speed at which your database cluster
switches from the primary to secondary database server when the primary is unplugged
is a performance test and has nothing to do with the load on the system.
</p>
        <h3>Load Testing
</h3>
        <p>
Any type of test that is dependent upon load or a specific load being placed on the
system. Load testing is not always a performance test. When 25 transactions per second
(tps) are placed on a web site, and the load balancer is monitored to ensure that
traffic is being properly distributed to the farm, you are load testing without a
care for performance.
</p>
        <h3>Stress Testing
</h3>
        <p>
Here is where I disagree with Alexander: stress testing places some sort of unexpected
stress on the system, but does not have to be a heavy load. Stress testing could include
testing a web server where one of its two processors have failed, a load-balanced
farm with some if its servers dropped from the cluster, a wireless system with a weak
signal or increased signal noise, or a laptop outside in below-freezing temperatures.
</p>
        <h3>Scalability Testing
</h3>
        <p>
Testing how well a system scales also is independent of load or resources, but still
relies on load or resources. Does a system produce timeout errors when you increase
the load from 20tps to 40tps? At 40tps, does the system produce less timeout errors
as the number of web servers in the farm is increased from 2 servers to 4? Or when
the Dell PowerEdge 2300s are replaced with PE2500s?
</p>
        <hr />
        <p>
Any type of testing in QA is vague. This includes the countless types of functional
testing, reliability testing, performance testing, and so on. Often time a single
test can fit into a handful of testing categories. Testing how fast the login page
loads after three days of 20tps traffic can be a load test, a performance test, and
a reliability test. The type of testing that it should be categorized as is dependent
upon what you are trying to do or achieve. Under this example, it is a performance
testing, since the goal is to measure ‘how fast’. If you change the question to ‘is
it slower after three days’, then it is a reliability test. The point is that no matter
where the test fits in your “Venn Diagram of QA,” the true identify of a test is based
on what you are trying to get out of it. The rest is just a means to an end.
</p>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=7dcbc600-fa83-4503-9077-040074103484" />
      </body>
      <title>Performance Testing != Load Testing</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,7dcbc600-fa83-4503-9077-040074103484.aspx</guid>
      <link>http://www.cptloadtest.com/2005/10/16/Performance-Testing-Load-Testing.aspx</link>
      <pubDate>Sun, 16 Oct 2005 17:41:01 GMT</pubDate>
      <description>&lt;p&gt;
Outside of the QA world (and unfortunately, sometimes in the QA world), I’ve heard
people toss around ‘Performance Testing’, ‘Load Testing’, ‘Scalability Testing’, and
‘Stress Testing’, yet always mean the same thing. My clients do this. My project managers
do this. My fellow developers do this. It doesn’t bother me–I’m not some QA psycho
that harasses anyone that doesn’t use exactly the correct term–but I do smirk on the
inside whenever one of these offenses occurs.
&lt;/p&gt;
&lt;p&gt;
Performance testing is not load testing is not scalability testing is not stress testing.
They are not the same thing. They closely relate, but they are not the same thing.
&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
Load testing is testing that involves applying a load to the system.&lt;/li&gt;
&lt;li&gt;
Performance testing evaluates how well the system performs.&lt;/li&gt;
&lt;li&gt;
Stress testing looks at how the system behaves under a heavy load.&lt;/li&gt;
&lt;li&gt;
Scalability testing investigates how well the system scales as the load and/or resources
are increased.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Alexander Podelko, Load Testing in a Diverse Environment, &lt;em&gt;Software Test &amp;amp;
Performance&lt;/em&gt;, October 2005.
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;h3&gt;Performance Testing
&lt;/h3&gt;
&lt;p&gt;
Any type of testing–and I mean &lt;em&gt;any&lt;/em&gt; type–that measures the performance (essentially,
speed) of the system in question. Measuring the speed at which your database cluster
switches from the primary to secondary database server when the primary is unplugged
is a performance test and has nothing to do with the load on the system.
&lt;/p&gt;
&lt;h3&gt;Load Testing
&lt;/h3&gt;
&lt;p&gt;
Any type of test that is dependent upon load or a specific load being placed on the
system. Load testing is not always a performance test. When 25 transactions per second
(tps) are placed on a web site, and the load balancer is monitored to ensure that
traffic is being properly distributed to the farm, you are load testing without a
care for performance.
&lt;/p&gt;
&lt;h3&gt;Stress Testing
&lt;/h3&gt;
&lt;p&gt;
Here is where I disagree with Alexander: stress testing places some sort of unexpected
stress on the system, but does not have to be a heavy load. Stress testing could include
testing a web server where one of its two processors have failed, a load-balanced
farm with some if its servers dropped from the cluster, a wireless system with a weak
signal or increased signal noise, or a laptop outside in below-freezing temperatures.
&lt;/p&gt;
&lt;h3&gt;Scalability Testing
&lt;/h3&gt;
&lt;p&gt;
Testing how well a system scales also is independent of load or resources, but still
relies on load or resources. Does a system produce timeout errors when you increase
the load from 20tps to 40tps? At 40tps, does the system produce less timeout errors
as the number of web servers in the farm is increased from 2 servers to 4? Or when
the Dell PowerEdge 2300s are replaced with PE2500s?
&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;
Any type of testing in QA is vague. This includes the countless types of functional
testing, reliability testing, performance testing, and so on. Often time a single
test can fit into a handful of testing categories. Testing how fast the login page
loads after three days of 20tps traffic can be a load test, a performance test, and
a reliability test. The type of testing that it should be categorized as is dependent
upon what you are trying to do or achieve. Under this example, it is a performance
testing, since the goal is to measure ‘how fast’. If you change the question to ‘is
it slower after three days’, then it is a reliability test. The point is that no matter
where the test fits in your “Venn Diagram of QA,” the true identify of a test is based
on what you are trying to get out of it. The rest is just a means to an end.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=7dcbc600-fa83-4503-9077-040074103484" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,7dcbc600-fa83-4503-9077-040074103484.aspx</comments>
      <category>Performance</category>
      <category>Testing</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=8c1f277e-a561-4bca-99e7-facfa9e2583c</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,8c1f277e-a561-4bca-99e7-facfa9e2583c.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,8c1f277e-a561-4bca-99e7-facfa9e2583c.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=8c1f277e-a561-4bca-99e7-facfa9e2583c</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I know. I haven’t posted in a while. But I’ve been crazy busy. Twelve hour days are
my norm, right now. But enough complaining; let’s get to the good stuff.
</p>
        <p>
By now you know my love for PsExec. I discovered it when trying to find a way to add
assemblies to a remote GAC [<a href="http://www.cptloadtest.com/?cat=8">post</a>].
I’ve found more love for it. Now, I can remotely execute my performance tests!
</p>
        <h3>Execute LoadRunner test using NAnt via LoadRunner:
</h3>
        <pre name="code" class="xml">&lt;exec basedir="${P1}"
  program="psexec"
  failonerror="false"
  commandline='\${P2} /u ${P3} /p ${P4} /i /w "${P5}" cmd /c wlrun -Run
    -InvokeAnalysis -TestPath "${P6}" -ResultLocation "${P7}"
    -ResultCleanName "${P8}"' /&gt;
</pre>
        <p>
(I’ve created generic parameter names so that you can read it a little better.)<br /><strong>P1</strong>: Local directory for PsExec<br /><strong>P2</strong>: LoadRunner Controller Server name<br /><strong>P3</strong>: LoadRunner Controller Server user username. I use an Admin-level
ID here, since this ID also needs rights to capture Windows PerfMon metrics on my
app servers.<br /><strong>P4</strong>: LoadRunner Controller Server user password<br /><strong>P5</strong>: Working directory on P2 for 'wlrun.exe', such as C:\Program Files\Mercury\Mercury
LoadRunner\bin<br /><strong>P6</strong>: Path on P2 to the LoadRunner scenario file<br /><strong>P7</strong>: Directory on P2 that contains all results from every test<br /><strong>P8</strong>: Result Set name for this test run
</p>
        <p>
'-InvokeAnalysis' will automatically execute LoadRunner analysis at test completion.
If you properly configure your Analysis default template, Analysis will automatically
generate the result set you want, save the Analysis session information, and create
a HTML report of the results. Now, put IIS on your Controller machine, and VDir to
the main results directory in P7, and you will have access to the HTML report within
minutes after your test completes.
</p>
        <h4>Other ideas:
</h4>
        <ul>
          <li>
You can also hook it up to CruiseControl and have your CC.Net report include a link
to the LR report.</li>
          <li>
Create a nightly build in CC.Net that will compile your code, deploy it to your performance
testing environment, and execute the performance test. When you get to work in the
morning, you have a link to your full performance test report waiting in your inbox.</li>
        </ul>
        <p>
The catch for all of this: you need a session logged in to the LoadRunner controller
box at all times. The '/i' in the PsExec command means that it interacts with the
desktop.
</p>
        <h4>
          <em>Sidenote</em>
        </h4>
        <p>
PsExec is my favorite tool right now. I can do so many cool things. I admit, as a
domain administrator, I also get a little malicious, sometimes. The other day I used
PsExec to start up solitaire on a co-workers box, then razzed him for playing games
on the clock.
</p>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=8c1f277e-a561-4bca-99e7-facfa9e2583c" />
      </body>
      <title>Automate LoadRunner through NAnt</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,8c1f277e-a561-4bca-99e7-facfa9e2583c.aspx</guid>
      <link>http://www.cptloadtest.com/2005/10/14/Automate-LoadRunner-Through-NAnt.aspx</link>
      <pubDate>Fri, 14 Oct 2005 15:35:40 GMT</pubDate>
      <description>&lt;p&gt;
I know. I haven’t posted in a while. But I’ve been crazy busy. Twelve hour days are
my norm, right now. But enough complaining; let’s get to the good stuff.
&lt;/p&gt;
&lt;p&gt;
By now you know my love for PsExec. I discovered it when trying to find a way to add
assemblies to a remote GAC [&lt;a href="http://www.cptloadtest.com/?cat=8"&gt;post&lt;/a&gt;].
I’ve found more love for it. Now, I can remotely execute my performance tests!
&lt;/p&gt;
&lt;h3&gt;Execute LoadRunner test using NAnt via LoadRunner:
&lt;/h3&gt;
&lt;pre name="code" class="xml"&gt;&amp;lt;exec basedir="${P1}"
  program="psexec"
  failonerror="false"
  commandline='\${P2} /u ${P3} /p ${P4} /i /w "${P5}" cmd /c wlrun -Run
    -InvokeAnalysis -TestPath "${P6}" -ResultLocation "${P7}"
    -ResultCleanName "${P8}"' /&amp;gt;
&lt;/pre&gt;
&lt;p&gt;
(I’ve created generic parameter names so that you can read it a little better.)&lt;br&gt;
&lt;strong&gt;P1&lt;/strong&gt;: Local directory for PsExec&lt;br&gt;
&lt;strong&gt;P2&lt;/strong&gt;: LoadRunner Controller Server name&lt;br&gt;
&lt;strong&gt;P3&lt;/strong&gt;: LoadRunner Controller Server user username. I use an Admin-level
ID here, since this ID also needs rights to capture Windows PerfMon metrics on my
app servers.&lt;br&gt;
&lt;strong&gt;P4&lt;/strong&gt;: LoadRunner Controller Server user password&lt;br&gt;
&lt;strong&gt;P5&lt;/strong&gt;: Working directory on P2 for 'wlrun.exe', such as C:\Program Files\Mercury\Mercury
LoadRunner\bin&lt;br&gt;
&lt;strong&gt;P6&lt;/strong&gt;: Path on P2 to the LoadRunner scenario file&lt;br&gt;
&lt;strong&gt;P7&lt;/strong&gt;: Directory on P2 that contains all results from every test&lt;br&gt;
&lt;strong&gt;P8&lt;/strong&gt;: Result Set name for this test run
&lt;/p&gt;
&lt;p&gt;
'-InvokeAnalysis' will automatically execute LoadRunner analysis at test completion.
If you properly configure your Analysis default template, Analysis will automatically
generate the result set you want, save the Analysis session information, and create
a HTML report of the results. Now, put IIS on your Controller machine, and VDir to
the main results directory in P7, and you will have access to the HTML report within
minutes after your test completes.
&lt;/p&gt;
&lt;h4&gt;Other ideas:
&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
You can also hook it up to CruiseControl and have your CC.Net report include a link
to the LR report.&lt;/li&gt;
&lt;li&gt;
Create a nightly build in CC.Net that will compile your code, deploy it to your performance
testing environment, and execute the performance test. When you get to work in the
morning, you have a link to your full performance test report waiting in your inbox.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
The catch for all of this: you need a session logged in to the LoadRunner controller
box at all times. The '/i' in the PsExec command means that it interacts with the
desktop.
&lt;/p&gt;
&lt;h4&gt;&lt;em&gt;Sidenote&lt;/em&gt;
&lt;/h4&gt;
&lt;p&gt;
PsExec is my favorite tool right now. I can do so many cool things. I admit, as a
domain administrator, I also get a little malicious, sometimes. The other day I used
PsExec to start up solitaire on a co-workers box, then razzed him for playing games
on the clock.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=8c1f277e-a561-4bca-99e7-facfa9e2583c" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,8c1f277e-a561-4bca-99e7-facfa9e2583c.aspx</comments>
      <category>Continuous Integration</category>
      <category>NAnt</category>
      <category>Performance</category>
      <category>Task Automation</category>
      <category>Testing</category>
      <category>LoadRunner</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=9f35db14-51c6-4baa-b3bd-3f9370881091</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,9f35db14-51c6-4baa-b3bd-3f9370881091.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,9f35db14-51c6-4baa-b3bd-3f9370881091.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=9f35db14-51c6-4baa-b3bd-3f9370881091</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I remember a day in my past when my project manager approached me, relaying a client
request. This client always received a copy of the test cases we used when testing
the application, and their request involved modifying our practices regarding case
creation. Through this request—and you know how client ‘requests’ go—the client was
convinced that we would be more efficient and better testers.
</p>
        <p>
Fortunately I was able to convince my project manager that it was not a good idea,
or at least “not a good idea right now.”<br />
We relayed that we appreciated any suggestions to improve our process, but “would
not be implementing this suggestion at this time.”
</p>
        <p>
I am constantly looking for ways to improve my craft, and have received many quality
suggestions from clients in a similar form to “Our testing department does [this].
You should take a look at it, and see you can benefit from it.” Suggestions carry
the mood of “If you implement it, great. If you don’t, that’s great, too.” However,
be weary of ‘missions from God’ to change your practices. The client’s plan may be
driven by budget, promoting inferior methods that will save a few dollars. They may
be based on their own practices that are less refined or matured than your own, also
resulting in inferior methods. Finally, changing your practices mid-stream in a project—as
many adopted “client requests” manifest—will disrupt flow, causing less quality over-all.
</p>
        <p>
Your client is in the business of making whozigadgets. You trust that they know what
they are doing, and know far better than you how to do it. You are in the business
of testing. Likewise, your client should trust that you are the subject matter expert
in your field.
</p>
        <p>
I’m not advocating that all clients don’t know anything about what you do, and that
everything they say about your craft should be blown off. All qualifying* suggestions
should be thoroughly considered and evaluated; that’s good business. Perhaps there
is a place in your organization for the process change, and that it would make you
more efficient at what it is you do. However, I am advocating that you should not
take a gung-ho attitude to please the client in any way possible, and implement every
process change they utter; that’s suicide. Your testing team will turn in to a confused,
ad-hoc organization. Your quality—and with it, your reputation—will crumble.
</p>
        <blockquote>
          <p>
* Qualifying Suggestion: Any suggestion that is reasonable, intelligent, and well-thought.
i.e. Do not abandon all QA to save costs, and rely on the client’s internal testing
to find all bugs.
</p>
        </blockquote>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=9f35db14-51c6-4baa-b3bd-3f9370881091" />
      </body>
      <title>Don't let clients control your testing</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,9f35db14-51c6-4baa-b3bd-3f9370881091.aspx</guid>
      <link>http://www.cptloadtest.com/2005/09/12/Dont-Let-Clients-Control-Your-Testing.aspx</link>
      <pubDate>Mon, 12 Sep 2005 17:25:09 GMT</pubDate>
      <description>&lt;p&gt;
I remember a day in my past when my project manager approached me, relaying a client
request. This client always received a copy of the test cases we used when testing
the application, and their request involved modifying our practices regarding case
creation. Through this request—and you know how client ‘requests’ go—the client was
convinced that we would be more efficient and better testers.
&lt;/p&gt;
&lt;p&gt;
Fortunately I was able to convince my project manager that it was not a good idea,
or at least “not a good idea right now.”&lt;br&gt;
We relayed that we appreciated any suggestions to improve our process, but “would
not be implementing this suggestion at this time.”
&lt;/p&gt;
&lt;p&gt;
I am constantly looking for ways to improve my craft, and have received many quality
suggestions from clients in a similar form to “Our testing department does [this].
You should take a look at it, and see you can benefit from it.” Suggestions carry
the mood of “If you implement it, great. If you don’t, that’s great, too.” However,
be weary of ‘missions from God’ to change your practices. The client’s plan may be
driven by budget, promoting inferior methods that will save a few dollars. They may
be based on their own practices that are less refined or matured than your own, also
resulting in inferior methods. Finally, changing your practices mid-stream in a project—as
many adopted “client requests” manifest—will disrupt flow, causing less quality over-all.
&lt;/p&gt;
&lt;p&gt;
Your client is in the business of making whozigadgets. You trust that they know what
they are doing, and know far better than you how to do it. You are in the business
of testing. Likewise, your client should trust that you are the subject matter expert
in your field.
&lt;/p&gt;
&lt;p&gt;
I’m not advocating that all clients don’t know anything about what you do, and that
everything they say about your craft should be blown off. All qualifying* suggestions
should be thoroughly considered and evaluated; that’s good business. Perhaps there
is a place in your organization for the process change, and that it would make you
more efficient at what it is you do. However, I am advocating that you should not
take a gung-ho attitude to please the client in any way possible, and implement every
process change they utter; that’s suicide. Your testing team will turn in to a confused,
ad-hoc organization. Your quality—and with it, your reputation—will crumble.
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;
* Qualifying Suggestion: Any suggestion that is reasonable, intelligent, and well-thought.
i.e. Do not abandon all QA to save costs, and rely on the client’s internal testing
to find all bugs.
&lt;/p&gt;
&lt;/blockquote&gt; &lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=9f35db14-51c6-4baa-b3bd-3f9370881091" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,9f35db14-51c6-4baa-b3bd-3f9370881091.aspx</comments>
      <category>Business</category>
      <category>Testing</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=5e745d33-9ded-4796-a9fa-a1617b659d13</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,5e745d33-9ded-4796-a9fa-a1617b659d13.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,5e745d33-9ded-4796-a9fa-a1617b659d13.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=5e745d33-9ded-4796-a9fa-a1617b659d13</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
As Lead QA, I have the fun responsibility of screening resumes and conducting phone
interviews. I weed out the hackers from the script kiddies before we bring them in
to face the firing squad. It never fails to amaze me how people embellish their resume
beyond reasonable limits. I am particularly fond of people that list skills they can
not define, and of people who don’t proof read their resume when applying for a detail-oriented
position.
</p>
        <p>
As I run through my stack of paper I came across one unfortunate soul that did both.
I was quite amused in a genuinely entertained sense. He proclaimed is proficiency
in ‘Quick Teat Professional 8.0′, presumably an application through which you can
automate cow milking, complete with data drivers and checkpoints. “OK. So he missed
the ’s’ and didn’t catch it. So what?” Well, he also bolded the misspelling, perhaps
to point out his attentiveness. This was only slightly before listing its usage in
2003 for a former employer that he also misspelled. (Note: QTP v8.0 was not available
until the summer of 2004.)
</p>
        <p>
However, and forgivably, my recruiter is not aware of such things and had already
scheduled a phone interview for me and my entertaining candidate; I honored the call,
giving the prospective a chance at redemption.
</p>
        <p>
He failed.
</p>
        <p>
Question number two asks the candidate to list the types of testing with which s/he
has experience. This reply included integration testing (also stated in his resume,
correctly spelled). My follow-up asked him to define integration testing; a common
ploy to make sure I’m not just being fed buzz-words. It was a definition he could
not supply, or even attempt.
</p>
        <p>
A candidate should be able to define every ‘word’ he claims experience with. If you
can not define it you obviously do not have enough experience in it to make it applicable.
If you can not define ‘integration testing’, I will not hold it against you providing
you do not list experience in it. Similarly, if you do not list it, and I ask you
what you know about it, be straight; tell me straight-up that you cannot define it.
You will rate higher in my book than someone who stumbles through an obviously concocted
and blatantly incorrect response.
</p>
        <p>
BTW, if you are looking for a position as a quality analyst, and can work in the Brighton,
Michigan area, drop me a line and a resume. I would be happy to hear from you. Ability
to define ‘integration testing’ a plus.
</p>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=5e745d33-9ded-4796-a9fa-a1617b659d13" />
      </body>
      <title>White lies and resumes</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,5e745d33-9ded-4796-a9fa-a1617b659d13.aspx</guid>
      <link>http://www.cptloadtest.com/2005/08/16/White-Lies-And-Resumes.aspx</link>
      <pubDate>Tue, 16 Aug 2005 17:29:53 GMT</pubDate>
      <description>&lt;p&gt;
As Lead QA, I have the fun responsibility of screening resumes and conducting phone
interviews. I weed out the hackers from the script kiddies before we bring them in
to face the firing squad. It never fails to amaze me how people embellish their resume
beyond reasonable limits. I am particularly fond of people that list skills they can
not define, and of people who don’t proof read their resume when applying for a detail-oriented
position.
&lt;/p&gt;
&lt;p&gt;
As I run through my stack of paper I came across one unfortunate soul that did both.
I was quite amused in a genuinely entertained sense. He proclaimed is proficiency
in ‘Quick Teat Professional 8.0′, presumably an application through which you can
automate cow milking, complete with data drivers and checkpoints. “OK. So he missed
the ’s’ and didn’t catch it. So what?” Well, he also bolded the misspelling, perhaps
to point out his attentiveness. This was only slightly before listing its usage in
2003 for a former employer that he also misspelled. (Note: QTP v8.0 was not available
until the summer of 2004.)
&lt;/p&gt;
&lt;p&gt;
However, and forgivably, my recruiter is not aware of such things and had already
scheduled a phone interview for me and my entertaining candidate; I honored the call,
giving the prospective a chance at redemption.
&lt;/p&gt;
&lt;p&gt;
He failed.
&lt;/p&gt;
&lt;p&gt;
Question number two asks the candidate to list the types of testing with which s/he
has experience. This reply included integration testing (also stated in his resume,
correctly spelled). My follow-up asked him to define integration testing; a common
ploy to make sure I’m not just being fed buzz-words. It was a definition he could
not supply, or even attempt.
&lt;/p&gt;
&lt;p&gt;
A candidate should be able to define every ‘word’ he claims experience with. If you
can not define it you obviously do not have enough experience in it to make it applicable.
If you can not define ‘integration testing’, I will not hold it against you providing
you do not list experience in it. Similarly, if you do not list it, and I ask you
what you know about it, be straight; tell me straight-up that you cannot define it.
You will rate higher in my book than someone who stumbles through an obviously concocted
and blatantly incorrect response.
&lt;/p&gt;
&lt;p&gt;
BTW, if you are looking for a position as a quality analyst, and can work in the Brighton,
Michigan area, drop me a line and a resume. I would be happy to hear from you. Ability
to define ‘integration testing’ a plus.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=5e745d33-9ded-4796-a9fa-a1617b659d13" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,5e745d33-9ded-4796-a9fa-a1617b659d13.aspx</comments>
      <category>Business</category>
      <category>Testing</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=4f0ceb20-3f16-487c-aab3-1773030be95a</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,4f0ceb20-3f16-487c-aab3-1773030be95a.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,4f0ceb20-3f16-487c-aab3-1773030be95a.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=4f0ceb20-3f16-487c-aab3-1773030be95a</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Scott Hanselman is my new hero. He is filling the hole—the one thing preventing Watir
from becoming real competitor in the automated functional test market: script recording.
Watch out Mercury; by creating <a href="http://www.hanselman.com/blog/IntroducingWatirMakerRecordingForRubybasedWatir.aspx">WatirMaker</a>,
Scott is opening the flood gates, and Watir is going to come pouring through.
</p>
        <p>
This changes everything.
</p>
        <p>
I started out my career as a developer, but as I noted in an earlier blog, I get much
more enjoyment from breaking things than I do building things, so I jumped ship. With
my development experience I can delve in to making some rather wicked scripts for
QTP, LoadRunner, and lately, Watir. However, my testers don’t share my skill set.
My biggest hurdle in ousting QTP and making Watir our standard is the lack of recording;
I can not expect every tester to start coding away in Ruby. It should come as no surprise
that when I opened <a href="http://www.hanselman.com/blog/">Scott’s blog</a> this
morning, I was so excited that I nearly wet myself.
</p>
        <p>
It is a work in progress, but soon Scott hopes to have a fully functional recording
tool for Watir. With WatirMaker, my testers can hit a button and start clicking away
in IE; the tool will happily watch like a little kid on the sidelines, learning every
move. My testers can all adopt Watir with open arms, and we can wave goodbye to that
Mercury maintenance contract.
</p>
        <p>
The only thing left to say is: “Scott…thanks!”
</p>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=4f0ceb20-3f16-487c-aab3-1773030be95a" />
      </body>
      <title>WatirMaker: GUI recording for Watir</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,4f0ceb20-3f16-487c-aab3-1773030be95a.aspx</guid>
      <link>http://www.cptloadtest.com/2005/07/27/WatirMaker-GUI-Recording-For-Watir.aspx</link>
      <pubDate>Wed, 27 Jul 2005 17:55:50 GMT</pubDate>
      <description>&lt;p&gt;
Scott Hanselman is my new hero. He is filling the hole—the one thing preventing Watir
from becoming real competitor in the automated functional test market: script recording.
Watch out Mercury; by creating &lt;a href="http://www.hanselman.com/blog/IntroducingWatirMakerRecordingForRubybasedWatir.aspx"&gt;WatirMaker&lt;/a&gt;,
Scott is opening the flood gates, and Watir is going to come pouring through.
&lt;/p&gt;
&lt;p&gt;
This changes everything.
&lt;/p&gt;
&lt;p&gt;
I started out my career as a developer, but as I noted in an earlier blog, I get much
more enjoyment from breaking things than I do building things, so I jumped ship. With
my development experience I can delve in to making some rather wicked scripts for
QTP, LoadRunner, and lately, Watir. However, my testers don’t share my skill set.
My biggest hurdle in ousting QTP and making Watir our standard is the lack of recording;
I can not expect every tester to start coding away in Ruby. It should come as no surprise
that when I opened &lt;a href="http://www.hanselman.com/blog/"&gt;Scott’s blog&lt;/a&gt; this
morning, I was so excited that I nearly wet myself.
&lt;/p&gt;
&lt;p&gt;
It is a work in progress, but soon Scott hopes to have a fully functional recording
tool for Watir. With WatirMaker, my testers can hit a button and start clicking away
in IE; the tool will happily watch like a little kid on the sidelines, learning every
move. My testers can all adopt Watir with open arms, and we can wave goodbye to that
Mercury maintenance contract.
&lt;/p&gt;
&lt;p&gt;
The only thing left to say is: “Scott…thanks!”
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=4f0ceb20-3f16-487c-aab3-1773030be95a" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,4f0ceb20-3f16-487c-aab3-1773030be95a.aspx</comments>
      <category>Programming</category>
      <category>Testing</category>
      <category>Tools</category>
      <category>Watir</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=54ce24e9-eb51-4843-bcf1-bfbac2d16f4d</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,54ce24e9-eb51-4843-bcf1-bfbac2d16f4d.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,54ce24e9-eb51-4843-bcf1-bfbac2d16f4d.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=54ce24e9-eb51-4843-bcf1-bfbac2d16f4d</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
If you are anything like me, you probably have the latest version of Internet Explorer
and/or Firefox on your machine.<br />
If you are anything like me, you have clients that don’t. They are often still supporting
Internet Explorer 5, or some archaic version of Netscape.
</p>
        <p>
Though it is a little dated, I found a rather helpful post on <a href="http://www.thunderguy.com/semicolon/">semicolon</a>,
today. The post on <a href="http://www.thunderguy.com/semicolon/2005/04/11/multiple-internet-explorer-versions-in-windows/">multiple
Internet Explorer versions in Windows</a> discusses stand-alone versions of Internet
Explorer available through an Internet Explorer <a href="http://browsers.evolt.org/?ie/32bit/standalone">browser
archive</a> from <a href="http://www.evolt.org/">evolt.com</a>. The post goes one
step further, identifying a defect in IE where every version uses common registry
settings causing it to always identify itself as v6, even if you are using a different
version. The post contains a workaround; drag this <a href="javascript:alert(navigator.appVersion)">Version</a> bookmarklet
to your links toolbar, and when you click it, it will show your actual version.
</p>
        <p>
I would also like to take his post one step further. The <a href="http://browsers.evolt.org/">full
browser archive</a>, which semicolon does not mention. Not only does evolt include
Internet Explorer, but seemingly every browser ever available, such as <a href="http://browsers.evolt.org/?navigator/">Netscape
Navigator</a>, <a href="http://browsers.evolt.org/?opera/">Opera</a>, and <a href="http://browsers.evolt.org/?lynx/">Lynx</a>.
</p>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=54ce24e9-eb51-4843-bcf1-bfbac2d16f4d" />
      </body>
      <title>Testing sites in old browsers</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,54ce24e9-eb51-4843-bcf1-bfbac2d16f4d.aspx</guid>
      <link>http://www.cptloadtest.com/2005/07/25/Testing-Sites-In-Old-Browsers.aspx</link>
      <pubDate>Mon, 25 Jul 2005 17:59:37 GMT</pubDate>
      <description>&lt;p&gt;
If you are anything like me, you probably have the latest version of Internet Explorer
and/or Firefox on your machine.&lt;br&gt;
If you are anything like me, you have clients that don’t. They are often still supporting
Internet Explorer 5, or some archaic version of Netscape.
&lt;/p&gt;
&lt;p&gt;
Though it is a little dated, I found a rather helpful post on &lt;a href="http://www.thunderguy.com/semicolon/"&gt;semicolon&lt;/a&gt;,
today. The post on &lt;a href="http://www.thunderguy.com/semicolon/2005/04/11/multiple-internet-explorer-versions-in-windows/"&gt;multiple
Internet Explorer versions in Windows&lt;/a&gt; discusses stand-alone versions of Internet
Explorer available through an Internet Explorer &lt;a href="http://browsers.evolt.org/?ie/32bit/standalone"&gt;browser
archive&lt;/a&gt; from &lt;a href="http://www.evolt.org/"&gt;evolt.com&lt;/a&gt;. The post goes one
step further, identifying a defect in IE where every version uses common registry
settings causing it to always identify itself as v6, even if you are using a different
version. The post contains a workaround; drag this &lt;a href="javascript:alert(navigator.appVersion)"&gt;Version&lt;/a&gt; bookmarklet
to your links toolbar, and when you click it, it will show your actual version.
&lt;/p&gt;
&lt;p&gt;
I would also like to take his post one step further. The &lt;a href="http://browsers.evolt.org/"&gt;full
browser archive&lt;/a&gt;, which semicolon does not mention. Not only does evolt include
Internet Explorer, but seemingly every browser ever available, such as &lt;a href="http://browsers.evolt.org/?navigator/"&gt;Netscape
Navigator&lt;/a&gt;, &lt;a href="http://browsers.evolt.org/?opera/"&gt;Opera&lt;/a&gt;, and &lt;a href="http://browsers.evolt.org/?lynx/"&gt;Lynx&lt;/a&gt;.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=54ce24e9-eb51-4843-bcf1-bfbac2d16f4d" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,54ce24e9-eb51-4843-bcf1-bfbac2d16f4d.aspx</comments>
      <category>Testing</category>
      <category>Tools</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=5f6e9d02-e647-4f4c-bb62-314c4727d285</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,5f6e9d02-e647-4f4c-bb62-314c4727d285.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,5f6e9d02-e647-4f4c-bb62-314c4727d285.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=5f6e9d02-e647-4f4c-bb62-314c4727d285</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
In case you haven’t heard of it yet, <a href="http://wtr.rubyforge.org/">Watir</a> is
the greatest thing to hit automated functional testing since…well…ever. Watir (pronounced
“water”), or Web Application Testing In Ruby, is an open source automated functional
testing tool powered by <a href="http://www.rubycentral.com/">Ruby</a>. My company
has been living off <a href="http://www.mercury.com/us/products/quality-center/functional-testing/quicktest-professional/">QuickTest
Pro</a>, and it is not much of a leap to Watir. Much like QTP, it automates an instance
of Internet Explorer and navigates its way around your web site, however <em>unlike</em> QTP,
it doesn’t hijack your computer when you do it; with Watir, the IE window doesn’t
have to be the foreground window, so you can get something else done while your test
is executing. Watir also allows various checks much like QTP, but though programming
includes the capability of checking much more, such as object hierarchy or object
style. (Yes, Watir can make sure that your validation messages are red!)
</p>
        <p>
Your money manager will love Watir, too. Our switch from QTP will save us thousands
of dollars per year from Mercury’s annual support costs. For a moment, I think our
company president’s pupils turned to dollar signs like a cartoon.
</p>
        <p>
If you are like me, and spend your QTP days in ‘Expert’ view (Source code), you will
pick Watir up quickly. I even find it <em>better</em> than QTP. Additionally, since
it is just a source code file, edited in Notepad if you like, it can be stored in
your favorite source control application AND (this is a big ‘and’) your <em>developers</em> can
execute the automated tests themselves without proprietary software like QTP. Its
easy integration with NUnit will also tie your automated functional tests in with
applications like Nant and CruiseControl.
</p>
        <h3>More Information
</h3>
Read all about <a href="http://wtr.rubyforge.org/">Watir</a>.<br />
Read Bret Pettichord’s (a Watir creator) <a href="http://www.io.com/%7Ewazmo/blog/archives/2004_08.html">blog
entry</a> about Watir.
<img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=5f6e9d02-e647-4f4c-bb62-314c4727d285" /></body>
      <title>Watir, Watir, everywhere</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,5f6e9d02-e647-4f4c-bb62-314c4727d285.aspx</guid>
      <link>http://www.cptloadtest.com/2005/07/15/Watir-Watir-Everywhere.aspx</link>
      <pubDate>Fri, 15 Jul 2005 18:19:59 GMT</pubDate>
      <description>&lt;p&gt;
In case you haven’t heard of it yet, &lt;a href="http://wtr.rubyforge.org/"&gt;Watir&lt;/a&gt; is
the greatest thing to hit automated functional testing since…well…ever. Watir (pronounced
“water”), or Web Application Testing In Ruby, is an open source automated functional
testing tool powered by &lt;a href="http://www.rubycentral.com/"&gt;Ruby&lt;/a&gt;. My company
has been living off &lt;a href="http://www.mercury.com/us/products/quality-center/functional-testing/quicktest-professional/"&gt;QuickTest
Pro&lt;/a&gt;, and it is not much of a leap to Watir. Much like QTP, it automates an instance
of Internet Explorer and navigates its way around your web site, however &lt;em&gt;unlike&lt;/em&gt; QTP,
it doesn’t hijack your computer when you do it; with Watir, the IE window doesn’t
have to be the foreground window, so you can get something else done while your test
is executing. Watir also allows various checks much like QTP, but though programming
includes the capability of checking much more, such as object hierarchy or object
style. (Yes, Watir can make sure that your validation messages are red!)
&lt;/p&gt;
&lt;p&gt;
Your money manager will love Watir, too. Our switch from QTP will save us thousands
of dollars per year from Mercury’s annual support costs. For a moment, I think our
company president’s pupils turned to dollar signs like a cartoon.
&lt;/p&gt;
&lt;p&gt;
If you are like me, and spend your QTP days in ‘Expert’ view (Source code), you will
pick Watir up quickly. I even find it &lt;em&gt;better&lt;/em&gt; than QTP. Additionally, since
it is just a source code file, edited in Notepad if you like, it can be stored in
your favorite source control application AND (this is a big ‘and’) your &lt;em&gt;developers&lt;/em&gt; can
execute the automated tests themselves without proprietary software like QTP. Its
easy integration with NUnit will also tie your automated functional tests in with
applications like Nant and CruiseControl.
&lt;/p&gt;
&lt;h3&gt;More Information
&lt;/h3&gt;
Read all about &lt;a href="http://wtr.rubyforge.org/"&gt;Watir&lt;/a&gt;.&lt;br&gt;
Read Bret Pettichord’s (a Watir creator) &lt;a href="http://www.io.com/%7Ewazmo/blog/archives/2004_08.html"&gt;blog
entry&lt;/a&gt; about Watir.&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=5f6e9d02-e647-4f4c-bb62-314c4727d285" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,5f6e9d02-e647-4f4c-bb62-314c4727d285.aspx</comments>
      <category>Programming</category>
      <category>Testing</category>
      <category>Tools</category>
      <category>Watir</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=22cfb7ee-7403-46d1-b810-fe545d6e2d68</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,22cfb7ee-7403-46d1-b810-fe545d6e2d68.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,22cfb7ee-7403-46d1-b810-fe545d6e2d68.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=22cfb7ee-7403-46d1-b810-fe545d6e2d68</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Fictional scenario: Trek–Lance Armstrong’s bicycle sponsor–is behind
schedule and over-budget on creating a new cycle. They need to find a way to get their
product out the door, find it now, and find it cheap. Now, imagine that they threw
my grandmother on their bike, had her drive it around the block, and declared it fully
tested and ready for mass-production. Would you be satisfied? If it found 300 grandmothers
and had them drive around the block twice, would that satisfy you? How about if they
used 300 average Joes? Would that satisfy Lance Armstrong? Would he have full confidence
in his ride for twenty-one days and over 3,500 km in the tour? I doubt it. That bike
wouldn’t even make it out of the warehouse, let alone to the starting line.
That bike would not earn respect until it was rigorously tested in a scenario that
at least simulates its intended use. So why do so many fail to put their web applications
through the same trials?
</p>
        <p>
Money? It will cost more money to fix it after launch than it will to test it during
development, identify the issues early, and get them fixed before the product goes
out the door.
</p>
        <p>
Time? Well, time is money, so see above.
</p>
        <p>
Experience? There are a lot of good, quality testers out there. If my mechanic doesn’t
properly fix my car, I’ll take my car to a different mechanic.
</p>
        <p>
I’m curious about the thoughts of everyone out there.
</p>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=22cfb7ee-7403-46d1-b810-fe545d6e2d68" />
      </body>
      <title>Down with the minute-man</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,22cfb7ee-7403-46d1-b810-fe545d6e2d68.aspx</guid>
      <link>http://www.cptloadtest.com/2005/06/24/Down-With-The-Minuteman.aspx</link>
      <pubDate>Fri, 24 Jun 2005 17:32:42 GMT</pubDate>
      <description>&lt;p&gt;
Fictional scenario: Trek&amp;#8211;Lance Armstrong&amp;#8217;s bicycle sponsor&amp;#8211;is behind
schedule and over-budget on creating a new cycle. They need to find a way to get their
product out the door, find it now, and find it cheap. Now, imagine that they threw
my grandmother on their bike, had her drive it around the block, and declared it fully
tested and ready for mass-production. Would you be satisfied? If it found 300 grandmothers
and had them drive around the block twice, would that satisfy you? How about if they
used 300 average Joes? Would that satisfy Lance Armstrong? Would he have full confidence
in his ride for twenty-one days and over 3,500 km in the tour? I doubt it. That bike
wouldn&amp;#8217;t even make it out of the warehouse, let alone to the starting line.
That bike would not earn respect until it was rigorously tested in a scenario that
at least simulates its intended use. So why do so many fail to put their web applications
through the same trials?
&lt;/p&gt;
&lt;p&gt;
Money? It will cost more money to fix it after launch than it will to test it during
development, identify the issues early, and get them fixed before the product goes
out the door.
&lt;/p&gt;
&lt;p&gt;
Time? Well, time is money, so see above.
&lt;/p&gt;
&lt;p&gt;
Experience? There are a lot of good, quality testers out there. If my mechanic doesn&amp;#8217;t
properly fix my car, I&amp;#8217;ll take my car to a different mechanic.
&lt;/p&gt;
&lt;p&gt;
I&amp;#8217;m curious about the thoughts of everyone out there.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=22cfb7ee-7403-46d1-b810-fe545d6e2d68" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,22cfb7ee-7403-46d1-b810-fe545d6e2d68.aspx</comments>
      <category>Business</category>
      <category>Testing</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=9aaef8ba-d0bd-4780-9529-79393630fce2</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,9aaef8ba-d0bd-4780-9529-79393630fce2.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,9aaef8ba-d0bd-4780-9529-79393630fce2.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=9aaef8ba-d0bd-4780-9529-79393630fce2</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
We’ve all been there. You’re cruising down I-5, minding your own business, when the
big SUV next to you decides that it is time to change lanes, and that it wants to
occupy the space you are currently claiming for yourself. Or there’s the motor home
doing 61 in the left lane passing the tractor-trailer in the right lane that’s doing
60. There’s the guy that passes everyone at the construction zone, repeatedly ignoring
“Lane Ends. Merge Left,” and expects that someone will let him in when pylons encroach,
and he will force the issue if they don’t.
</p>
        <p>
All of this traffic congestion, incompetence, and utter disregard for fellow citizens
pollutes your driving experience. You work day is stressful enough. Why must you go
through it on the way home?
</p>
        <p>
Your web applications have to go through the same thing: A poorly-coded neighbor with
the memory leak, that just keeps taking and taking from the available RAM, until there
is nothing left for your app, just like that SUV; An application that didn’t get properly
optimized, and hogs all of your available bandwidth, slowing down your application
like that 40-foot RV; An evil report that thinks it is superior, and locks the entire
database from outside access until it is finished generating that 400-page PDF.
</p>
        <p>
When you are testing the performance of your application, make sure that the environment
you are about to stuff it in to is up to par. No matter how pristine your application
looks in Staging, it is only going to be as good as the environment that you launch
it to. If you ignore the big picture, and your application succumbs to the web environment
pollution, your application will be to blame. No matter how mediocre the environment
is without your application, your superiors or clients will still say “the environment
works just fine without your app.”
</p>
        <p>
Build a testing environment that mimics production, and that includes any other applications
or components that you will be sharing resources with. Create some generic scripts
that will generate traffic against these neighbors and execute tests against your
application. This will help identify any integration issues between you and your environment,
and help eliminate any surprises when you launch.
</p>
        <p>
The environment is supposed to work just fine <em>with</em> your app, too.
</p>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=9aaef8ba-d0bd-4780-9529-79393630fce2" />
      </body>
      <title>Beware: Web environment pollution</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,9aaef8ba-d0bd-4780-9529-79393630fce2.aspx</guid>
      <link>http://www.cptloadtest.com/2005/06/13/Beware-Web-Environment-Pollution.aspx</link>
      <pubDate>Mon, 13 Jun 2005 18:49:19 GMT</pubDate>
      <description>&lt;p&gt;
We’ve all been there. You’re cruising down I-5, minding your own business, when the
big SUV next to you decides that it is time to change lanes, and that it wants to
occupy the space you are currently claiming for yourself. Or there’s the motor home
doing 61 in the left lane passing the tractor-trailer in the right lane that’s doing
60. There’s the guy that passes everyone at the construction zone, repeatedly ignoring
“Lane Ends. Merge Left,” and expects that someone will let him in when pylons encroach,
and he will force the issue if they don’t.
&lt;/p&gt;
&lt;p&gt;
All of this traffic congestion, incompetence, and utter disregard for fellow citizens
pollutes your driving experience. You work day is stressful enough. Why must you go
through it on the way home?
&lt;/p&gt;
&lt;p&gt;
Your web applications have to go through the same thing: A poorly-coded neighbor with
the memory leak, that just keeps taking and taking from the available RAM, until there
is nothing left for your app, just like that SUV; An application that didn’t get properly
optimized, and hogs all of your available bandwidth, slowing down your application
like that 40-foot RV; An evil report that thinks it is superior, and locks the entire
database from outside access until it is finished generating that 400-page PDF.
&lt;/p&gt;
&lt;p&gt;
When you are testing the performance of your application, make sure that the environment
you are about to stuff it in to is up to par. No matter how pristine your application
looks in Staging, it is only going to be as good as the environment that you launch
it to. If you ignore the big picture, and your application succumbs to the web environment
pollution, your application will be to blame. No matter how mediocre the environment
is without your application, your superiors or clients will still say “the environment
works just fine without your app.”
&lt;/p&gt;
&lt;p&gt;
Build a testing environment that mimics production, and that includes any other applications
or components that you will be sharing resources with. Create some generic scripts
that will generate traffic against these neighbors and execute tests against your
application. This will help identify any integration issues between you and your environment,
and help eliminate any surprises when you launch.
&lt;/p&gt;
&lt;p&gt;
The environment is supposed to work just fine &lt;em&gt;with&lt;/em&gt; your app, too.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=9aaef8ba-d0bd-4780-9529-79393630fce2" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,9aaef8ba-d0bd-4780-9529-79393630fce2.aspx</comments>
      <category>Testing</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=5fce494c-19d2-4615-a8f4-54e490b71921</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,5fce494c-19d2-4615-a8f4-54e490b71921.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,5fce494c-19d2-4615-a8f4-54e490b71921.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=5fce494c-19d2-4615-a8f4-54e490b71921</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
In the QA forums I frequent, there are often questions about how to properly load
test when you don’t have access to production or an identically built environment.
Most companies won’t spring the cash to build an environment that is identical
to production; generally, testing environments are made up of hand-me-down servers
that <em>used</em> to be in production. Of course, there is also the cost of test
suite licensing to produce a productional load, and the near impossibility of mimicking
real production traffic.
</p>
        <p>
Though a production clone would be ideal, a watered down environment can be sufficient,
and in some ways better. Bottlenecks are achieved faster, without having to push through
50 Mbps of data. Additionally, a “lesser” environment will be more sensitive
to changes; your transaction may take 0.5 seconds on production-grade servers, and
a defect that doubles it to 1.0 seconds is hardly noticeable, but on a lesser environment
where that transaction takes 6.0 seconds, doubling it to twelve throws up red flags.
</p>
        <p>
For a watered-down environment, try to lessen the horsepower of your system while
matching the architecture. If your productional environment is eight web servers that
are all quad 3.2 Ghz Xeons running Windows Server 2003 Web Edition, and all load balanced
through a hardware load balancer, you can bring it down to two web servers with less
horsepower–perhaps dual 700Mhz P3s–but the servers should still run Windows
Server 2003 Web Edition and be balanced with a hardware balancer. Do not drop below
two web servers because you will still want a load balanced environment, and do not
switch to Windows 2000 or use Microsoft’s NLB (Network Load Balancing). If your
production web environment uses Windows 2000 and NLB, obviously use that technology
in your testing environment; do not switch to Windows 2003 or a hardware load balancer.
</p>
        <p>
Additionally, try to reduce equally throughout your environment. Don’t drop
your web servers from Pentium 4s to Pentium 3s while dropping your database servers
from Pentium 4s to an old 486 desktop. Equal reductions maintain your continuity,
and in the end, your sanity. Unequal reductions introduce new problems that don’t
exist in production, but will still happily waste your time and money. A major bottleneck
might exist on your web servers, but the defect could be masked because you were database-bound
by using that old 486.
</p>
        <p>
The idea behind this is that many bugs can be introduced by a specific revision of
your OS (Think of the problems from Windows XP SP2), from your style of network infrastructure,
the version of your graphics driver, etc. You want as many common points as possible
between your testing and production environments to eliminate any surprises when you
launch your application. Ideally, your testing environment is an exact replica of
your production environment, but unless you are making desktop applications, it is
only a fantasy, so just try to get as close as you can. Use the same OS version, including
the same service pack and the same installed hot fixes. Use the same driver versions,
and configure the same settings on your web server software. You are trying to create
a miniature version of your production environment, like a model car or a ship in
a bottle. Pay attention to the details and you will be okay. To your application,
the environments should be exactly the same; one is just a little snug.
</p>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=5fce494c-19d2-4615-a8f4-54e490b71921" />
      </body>
      <title>A watered down test environment</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,5fce494c-19d2-4615-a8f4-54e490b71921.aspx</guid>
      <link>http://www.cptloadtest.com/2005/05/25/A-Watered-Down-Test-Environment.aspx</link>
      <pubDate>Wed, 25 May 2005 18:32:15 GMT</pubDate>
      <description>&lt;p&gt;
In the QA forums I frequent, there are often questions about how to properly load
test when you don&amp;#8217;t have access to production or an identically built environment.
Most companies won&amp;#8217;t spring the cash to build an environment that is identical
to production; generally, testing environments are made up of hand-me-down servers
that &lt;em&gt;used&lt;/em&gt; to be in production. Of course, there is also the cost of test
suite licensing to produce a productional load, and the near impossibility of mimicking
real production traffic.
&lt;/p&gt;
&lt;p&gt;
Though a production clone would be ideal, a watered down environment can be sufficient,
and in some ways better. Bottlenecks are achieved faster, without having to push through
50 Mbps of data. Additionally, a &amp;#8220;lesser&amp;#8221; environment will be more sensitive
to changes; your transaction may take 0.5 seconds on production-grade servers, and
a defect that doubles it to 1.0 seconds is hardly noticeable, but on a lesser environment
where that transaction takes 6.0 seconds, doubling it to twelve throws up red flags.
&lt;/p&gt;
&lt;p&gt;
For a watered-down environment, try to lessen the horsepower of your system while
matching the architecture. If your productional environment is eight web servers that
are all quad 3.2 Ghz Xeons running Windows Server 2003 Web Edition, and all load balanced
through a hardware load balancer, you can bring it down to two web servers with less
horsepower&amp;#8211;perhaps dual 700Mhz P3s&amp;#8211;but the servers should still run Windows
Server 2003 Web Edition and be balanced with a hardware balancer. Do not drop below
two web servers because you will still want a load balanced environment, and do not
switch to Windows 2000 or use Microsoft&amp;#8217;s NLB (Network Load Balancing). If your
production web environment uses Windows 2000 and NLB, obviously use that technology
in your testing environment; do not switch to Windows 2003 or a hardware load balancer.
&lt;/p&gt;
&lt;p&gt;
Additionally, try to reduce equally throughout your environment. Don&amp;#8217;t drop
your web servers from Pentium 4s to Pentium 3s while dropping your database servers
from Pentium 4s to an old 486 desktop. Equal reductions maintain your continuity,
and in the end, your sanity. Unequal reductions introduce new problems that don&amp;#8217;t
exist in production, but will still happily waste your time and money. A major bottleneck
might exist on your web servers, but the defect could be masked because you were database-bound
by using that old 486.
&lt;/p&gt;
&lt;p&gt;
The idea behind this is that many bugs can be introduced by a specific revision of
your OS (Think of the problems from Windows XP SP2), from your style of network infrastructure,
the version of your graphics driver, etc. You want as many common points as possible
between your testing and production environments to eliminate any surprises when you
launch your application. Ideally, your testing environment is an exact replica of
your production environment, but unless you are making desktop applications, it is
only a fantasy, so just try to get as close as you can. Use the same OS version, including
the same service pack and the same installed hot fixes. Use the same driver versions,
and configure the same settings on your web server software. You are trying to create
a miniature version of your production environment, like a model car or a ship in
a bottle. Pay attention to the details and you will be okay. To your application,
the environments should be exactly the same; one is just a little snug.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=5fce494c-19d2-4615-a8f4-54e490b71921" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,5fce494c-19d2-4615-a8f4-54e490b71921.aspx</comments>
      <category>Performance</category>
      <category>Testing</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=1a8479d9-2dcb-4bd5-9336-4f1ace96cb21</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,1a8479d9-2dcb-4bd5-9336-4f1ace96cb21.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,1a8479d9-2dcb-4bd5-9336-4f1ace96cb21.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=1a8479d9-2dcb-4bd5-9336-4f1ace96cb21</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
For love of all things QA, before you launch a new application, test production!
</p>
        <p>
“What? That’s stupid! Why would I want to perform a load test production and risk
an outage? That impacts my <a href="http://en.wikipedia.org/wiki/Service_Level_Agreement">SLAs</a>.
I can’t impact my SLAs!”
</p>
        <p>
Remember the number one rule of quality control: if you don’t find it, your customers
will.
</p>
        <p>
When you are about to launch a brand new application into your production environment,
test that application against production. However, this only applies for <em>new</em> applications.
New applications will introduce new, additional load on the environment, while existing,
revised applications already have added that load to the system. Essentially, with
an existing application, you already know how well the production environment can
handle the additional demand generated by the application’s audience. New applications
have not yet generated that load, and production has yet to prove itself.
</p>
        <p>
There is no hard evidence that production can take the additional demand. Maybe your
production load balancer can only handle another 5 MB/s, and your new application
will demand another 7. Perhaps it is one of the switches, instead. Or for my recent
life, maybe it is your ISP. You will not know until you test it, until you measure
it, and “if you didn’t measure it, you didn’t do it.”
</p>
        <p>
With a past project, my company created an intranet application for our client, and
our application just happened to be hosted off-site. The off-site environment was
green, and wasn’t hosting anything else, so our client had no issue with us testing
this environment fully since it <em>was</em> going to be production, but wasn’t <em>yet</em>.
The hosting company and their ISP rated the environment at 45 Mbps (That’s megabits–lower-case
‘b’), and based on the clients traffic expectations, we needed about 30. It is a good
thing we tested the site because we found an issue with the load balancer at about
15 Mbps, a problem with server memory when it was processing enough transactions to
produce 20 Mbps, a problem with the database switches when we were generating 22 Mbps,
and–this one is the kicker–a bandwidth ceiling at 28. Though all of the routers, switches,
balancers, and servers were performing well, we couldn’t get more than 28 Mbps to
the web servers. It turns out that the ISP didn’t ever expect anyone to <em>use</em> that
45 Mbps rating, and never tested to make sure they could handle it.
</p>
        <blockquote>“If you didn’t measure it, you didn’t do it.”</blockquote>
        <p>
Through two months of midnight through 0600 testing, we upgraded the load balancer,
added more memory, put in gigabit switches, had the ISP tweak their infrastructure,
pushed through all of the data we needed, and successfully proved that the off-site
environment and our new application could handle the load. But, the environment still
wasn’t fully tested. Our client used everyone’s favorite single-signon, SiteMinder.
However, they wouldn’t let us test the application while integrating their productional
SiteMinder policy servers. We could only use staging, and when the staging servers
couldn’t handle the load, “that’s okay because it’s staging.” But no matter how much
we advocated, we couldn’t test production. We might impact the environment and the
SLAs. So, we launched without testing it, and guess what happened? The policy servers
failed, and they severely impacted their SLAs.
</p>
        <p>
And to think, we could have tested that at 1:00 AM on a Saturday, and they even if
we fried the policy servers, they would have had all weekend to fix it. And most importantly,
we would have identified it before the end-user did. But what really cooked their
goose was the difference between productional load and performance testing load: performance
tests can be stopped. It is a lot harder to fix a jet engine at 30,000 ft.
</p>
        <p>
The moral of the story: when launching a new application, always test production.
Always.
</p>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=1a8479d9-2dcb-4bd5-9336-4f1ace96cb21" />
      </body>
      <title>Performance test production!</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,1a8479d9-2dcb-4bd5-9336-4f1ace96cb21.aspx</guid>
      <link>http://www.cptloadtest.com/2005/05/23/Performance-Test-Production.aspx</link>
      <pubDate>Mon, 23 May 2005 18:35:26 GMT</pubDate>
      <description>&lt;p&gt;
For love of all things QA, before you launch a new application, test production!
&lt;/p&gt;
&lt;p&gt;
“What? That’s stupid! Why would I want to perform a load test production and risk
an outage? That impacts my &lt;a href="http://en.wikipedia.org/wiki/Service_Level_Agreement"&gt;SLAs&lt;/a&gt;.
I can’t impact my SLAs!”
&lt;/p&gt;
&lt;p&gt;
Remember the number one rule of quality control: if you don’t find it, your customers
will.
&lt;/p&gt;
&lt;p&gt;
When you are about to launch a brand new application into your production environment,
test that application against production. However, this only applies for &lt;em&gt;new&lt;/em&gt; applications.
New applications will introduce new, additional load on the environment, while existing,
revised applications already have added that load to the system. Essentially, with
an existing application, you already know how well the production environment can
handle the additional demand generated by the application’s audience. New applications
have not yet generated that load, and production has yet to prove itself.
&lt;/p&gt;
&lt;p&gt;
There is no hard evidence that production can take the additional demand. Maybe your
production load balancer can only handle another 5 MB/s, and your new application
will demand another 7. Perhaps it is one of the switches, instead. Or for my recent
life, maybe it is your ISP. You will not know until you test it, until you measure
it, and “if you didn’t measure it, you didn’t do it.”
&lt;/p&gt;
&lt;p&gt;
With a past project, my company created an intranet application for our client, and
our application just happened to be hosted off-site. The off-site environment was
green, and wasn’t hosting anything else, so our client had no issue with us testing
this environment fully since it &lt;em&gt;was&lt;/em&gt; going to be production, but wasn’t &lt;em&gt;yet&lt;/em&gt;.
The hosting company and their ISP rated the environment at 45 Mbps (That’s megabits–lower-case
‘b’), and based on the clients traffic expectations, we needed about 30. It is a good
thing we tested the site because we found an issue with the load balancer at about
15 Mbps, a problem with server memory when it was processing enough transactions to
produce 20 Mbps, a problem with the database switches when we were generating 22 Mbps,
and–this one is the kicker–a bandwidth ceiling at 28. Though all of the routers, switches,
balancers, and servers were performing well, we couldn’t get more than 28 Mbps to
the web servers. It turns out that the ISP didn’t ever expect anyone to &lt;em&gt;use&lt;/em&gt; that
45 Mbps rating, and never tested to make sure they could handle it.
&lt;/p&gt;
&lt;blockquote&gt;“If you didn’t measure it, you didn’t do it.”&lt;/blockquote&gt; 
&lt;p&gt;
Through two months of midnight through 0600 testing, we upgraded the load balancer,
added more memory, put in gigabit switches, had the ISP tweak their infrastructure,
pushed through all of the data we needed, and successfully proved that the off-site
environment and our new application could handle the load. But, the environment still
wasn’t fully tested. Our client used everyone’s favorite single-signon, SiteMinder.
However, they wouldn’t let us test the application while integrating their productional
SiteMinder policy servers. We could only use staging, and when the staging servers
couldn’t handle the load, “that’s okay because it’s staging.” But no matter how much
we advocated, we couldn’t test production. We might impact the environment and the
SLAs. So, we launched without testing it, and guess what happened? The policy servers
failed, and they severely impacted their SLAs.
&lt;/p&gt;
&lt;p&gt;
And to think, we could have tested that at 1:00 AM on a Saturday, and they even if
we fried the policy servers, they would have had all weekend to fix it. And most importantly,
we would have identified it before the end-user did. But what really cooked their
goose was the difference between productional load and performance testing load: performance
tests can be stopped. It is a lot harder to fix a jet engine at 30,000 ft.
&lt;/p&gt;
&lt;p&gt;
The moral of the story: when launching a new application, always test production.
Always.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=1a8479d9-2dcb-4bd5-9336-4f1ace96cb21" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,1a8479d9-2dcb-4bd5-9336-4f1ace96cb21.aspx</comments>
      <category>Performance</category>
      <category>Testing</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=15f0eb79-2b7f-4ede-bb7d-0c669335b45d</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,15f0eb79-2b7f-4ede-bb7d-0c669335b45d.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,15f0eb79-2b7f-4ede-bb7d-0c669335b45d.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=15f0eb79-2b7f-4ede-bb7d-0c669335b45d</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
When testing .Net web application forms that use postback, it is always a good idea
to leave the form and come back. Postback is when a page refreshes or submits to itself;
generally, identified by the pre- and post-submit URL being the same page. Often times,
the status of the form fields is saved in the .Net ViewState after a submit, rather
than retrieved from the database. You might have checked the “Display me” checkbox
and clicked submit. The “cached” version from the ViewState says that this control
should be checked, so when the page reloads, it is. However, the value may have not
been saved to the database, so when the value is loaded from the DB, the box is not
checked, but you would not have known since the ViewState version was used. When testing,
to make sure you are getting the actual values and not the “cached” counterparts,
make sure you leave the page and come back.
</p>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=15f0eb79-2b7f-4ede-bb7d-0c669335b45d" />
      </body>
      <title>QA tip: Go away, then come back</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,15f0eb79-2b7f-4ede-bb7d-0c669335b45d.aspx</guid>
      <link>http://www.cptloadtest.com/2005/05/18/QA-Tip-Go-Away-Then-Come-Back.aspx</link>
      <pubDate>Wed, 18 May 2005 18:37:22 GMT</pubDate>
      <description>&lt;p&gt;
When testing .Net web application forms that use postback, it is always a good idea
to leave the form and come back. Postback is when a page refreshes or submits to itself;
generally, identified by the pre- and post-submit URL being the same page. Often times,
the status of the form fields is saved in the .Net ViewState after a submit, rather
than retrieved from the database. You might have checked the “Display me” checkbox
and clicked submit. The “cached” version from the ViewState says that this control
should be checked, so when the page reloads, it is. However, the value may have not
been saved to the database, so when the value is loaded from the DB, the box is not
checked, but you would not have known since the ViewState version was used. When testing,
to make sure you are getting the actual values and not the “cached” counterparts,
make sure you leave the page and come back.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=15f0eb79-2b7f-4ede-bb7d-0c669335b45d" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,15f0eb79-2b7f-4ede-bb7d-0c669335b45d.aspx</comments>
      <category>Testing</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=49eed949-f57a-4de0-a3c7-2a58dd13f54f</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,49eed949-f57a-4de0-a3c7-2a58dd13f54f.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,49eed949-f57a-4de0-a3c7-2a58dd13f54f.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=49eed949-f57a-4de0-a3c7-2a58dd13f54f</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <strong>Screen Hunter 4.0 Free</strong> - <a href="http://www.wisdom-soft.com/">www.wisdom-soft.com</a><br />
Screen Capture Tool<br />
Cost: Free
</p>
        <p>
Quite possible the most essential task for any tester is taking a snapshot of the
current screen to give their developer a visual representation of the logged error.
The classic Windows hotkey, [Alt] + [PrtScn], will take a screen capture of the entire
active window. However, sometimes the text on a link is spelled wrong, a button uses
the wrong icon, or an error message displays in the wrong style; in these scenarios
an entire screen grab is overkill and often confusing. Yet there are few things that
a tester can do about that short of opening up MS Paint or <a href="http://www.macromedia.com/software/fireworks/">Macromedia
Fireworks</a> and cropping the image, completely wasting valuable time and causing
pointed comments from the Project Manager about diddling in <a href="http://www.adobe.com/products/photoshop/">Photoshop</a>.
</p>
        <p>
          <a href="http://www.wisdom-soft.com/products/screenhunter.htm">Screen Hunter 4.0 Free</a> allows
you to capture the important pixels quickly and effortlessly. Tap F6 (The default
hotkey, but it can be modified), and your cursor changes to a cross-hair. Click-drag
a box around whatever you want to capture, and it’s done. Instantly cropped
screen capture for your bug-tracking pleasure.
</p>
        <p>
The developers will be happier, too.
</p>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=49eed949-f57a-4de0-a3c7-2a58dd13f54f" />
      </body>
      <title>Screen Hunter 4.0 Free</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,49eed949-f57a-4de0-a3c7-2a58dd13f54f.aspx</guid>
      <link>http://www.cptloadtest.com/2005/05/11/Screen-Hunter-40-Free.aspx</link>
      <pubDate>Wed, 11 May 2005 18:46:01 GMT</pubDate>
      <description>&lt;p&gt;
&lt;strong&gt;Screen Hunter 4.0 Free&lt;/strong&gt; - &lt;a href="http://www.wisdom-soft.com/"&gt;www.wisdom-soft.com&lt;/a&gt;
&lt;br /&gt;
Screen Capture Tool&lt;br /&gt;
Cost: Free
&lt;/p&gt;
&lt;p&gt;
Quite possible the most essential task for any tester is taking a snapshot of the
current screen to give their developer a visual representation of the logged error.
The classic Windows hotkey, [Alt] + [PrtScn], will take a screen capture of the entire
active window. However, sometimes the text on a link is spelled wrong, a button uses
the wrong icon, or an error message displays in the wrong style; in these scenarios
an entire screen grab is overkill and often confusing. Yet there are few things that
a tester can do about that short of opening up MS Paint or &lt;a href="http://www.macromedia.com/software/fireworks/"&gt;Macromedia
Fireworks&lt;/a&gt; and cropping the image, completely wasting valuable time and causing
pointed comments from the Project Manager about diddling in &lt;a href="http://www.adobe.com/products/photoshop/"&gt;Photoshop&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.wisdom-soft.com/products/screenhunter.htm"&gt;Screen Hunter 4.0 Free&lt;/a&gt; allows
you to capture the important pixels quickly and effortlessly. Tap F6 (The default
hotkey, but it can be modified), and your cursor changes to a cross-hair. Click-drag
a box around whatever you want to capture, and it&amp;#8217;s done. Instantly cropped
screen capture for your bug-tracking pleasure.
&lt;/p&gt;
&lt;p&gt;
The developers will be happier, too.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=49eed949-f57a-4de0-a3c7-2a58dd13f54f" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,49eed949-f57a-4de0-a3c7-2a58dd13f54f.aspx</comments>
      <category>Reviews</category>
      <category>Testing</category>
      <category>Tools</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=9e8839a2-9f66-44e1-8488-a65fdb9e47c1</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,9e8839a2-9f66-44e1-8488-a65fdb9e47c1.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,9e8839a2-9f66-44e1-8488-a65fdb9e47c1.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=9e8839a2-9f66-44e1-8488-a65fdb9e47c1</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
So your wonderful little creation is finished, and it does exactly what it was designed
to do. But, have you prevented it from doing what it’s not supposed to do?
</p>
        <p>
Enter the forgotten art of negative testing. This is the safeguard from user error,
malicious attacks, and blatant developer oversight. Negative testing is taking your
calculator application and trying to add “Hello” and “Goodnight”. Negative testing
is trying to supply an invalid email address–.anything@something.q–into your mailing
list form. Negative testing is trying to cause a buffer overflow on your lead-developer’s
computer because you were able to sneak in a script injection.
</p>
        <p>
The key word here is “try.”
</p>
        <p>
If everyone has done their job, you will get nowhere. Unfortunately, rarely is this
job done right. In 3 minutes I could considerably alter my best friend’s blog, and
he doesn’t even know it. In 10 minutes I could corrupt the online database of a Fortune
500’s web site–both company and URL to remain anonymous. And, what scares me the most,
in 20 minutes I could download the entire database of a certain benefits company,
including the complete identity–SSN included–of a few thousand people.
</p>
        <p>
For years, I have been paid to break things as much as build them. When that calculator
finally adds 2 and 2 correctly, don’t be satisfied. Try to add “Hello” and “Goodnight”.
Will it give you a neatly handled error message informing you that it couldn’t complete
the procedure, or did it return a fatal exception and die a miserable death because
it expected a Double and you gave it a String? Optimally, it shouldn’t allow you to
even <em>type</em> characters into the input area unless you are working in hex; even
then, only A-F.
</p>
        <p>
If instructions tell you to do one thing, enter the opposite. If you see a value in
the URL, change it. If a field asks for an integer between 0 and 5, try 0, 2, 5, -1,
9, 3.5, and “Q”, and see how it handles “unexpected inputs.” If a querystring is “?UserID=6″,
change the 6 to a 7, to see if you get information on User 7, and try invalid items
like 3.5 and “Q” to see if it fails on unexpected inputs. If a client-side cookie
has a value of “User”, try changing it to “Admin” or “Administrator” and see if your
access-level is increased.
</p>
        <p>
Find the weaknesses, find the holes, and find the bugs so that they can get fixed.
You are the demolition man. You get paid to blow things up. Do it. Do it with purpose.
Pretend you are a hacker trying to get into the system. Pretend you are a teenager-hacker-wannabe
trying to screw with the system. Pretend you are a grandma that doesn’t know what
to do with the system. Do all of the things that you aren’t supposed to do to the
application and do them on purpose, because if by ignorance or intelligence, your
users will find what was missed.<br /></p>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=9e8839a2-9f66-44e1-8488-a65fdb9e47c1" />
      </body>
      <title>Negative testing: The forgotten art</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,9e8839a2-9f66-44e1-8488-a65fdb9e47c1.aspx</guid>
      <link>http://www.cptloadtest.com/2005/05/10/Negative-Testing-The-Forgotten-Art.aspx</link>
      <pubDate>Tue, 10 May 2005 18:55:41 GMT</pubDate>
      <description>&lt;p&gt;
So your wonderful little creation is finished, and it does exactly what it was designed
to do. But, have you prevented it from doing what it’s not supposed to do?
&lt;/p&gt;
&lt;p&gt;
Enter the forgotten art of negative testing. This is the safeguard from user error,
malicious attacks, and blatant developer oversight. Negative testing is taking your
calculator application and trying to add “Hello” and “Goodnight”. Negative testing
is trying to supply an invalid email address–.anything@something.q–into your mailing
list form. Negative testing is trying to cause a buffer overflow on your lead-developer’s
computer because you were able to sneak in a script injection.
&lt;/p&gt;
&lt;p&gt;
The key word here is “try.”
&lt;/p&gt;
&lt;p&gt;
If everyone has done their job, you will get nowhere. Unfortunately, rarely is this
job done right. In 3 minutes I could considerably alter my best friend’s blog, and
he doesn’t even know it. In 10 minutes I could corrupt the online database of a Fortune
500’s web site–both company and URL to remain anonymous. And, what scares me the most,
in 20 minutes I could download the entire database of a certain benefits company,
including the complete identity–SSN included–of a few thousand people.
&lt;/p&gt;
&lt;p&gt;
For years, I have been paid to break things as much as build them. When that calculator
finally adds 2 and 2 correctly, don’t be satisfied. Try to add “Hello” and “Goodnight”.
Will it give you a neatly handled error message informing you that it couldn’t complete
the procedure, or did it return a fatal exception and die a miserable death because
it expected a Double and you gave it a String? Optimally, it shouldn’t allow you to
even &lt;em&gt;type&lt;/em&gt; characters into the input area unless you are working in hex; even
then, only A-F.
&lt;/p&gt;
&lt;p&gt;
If instructions tell you to do one thing, enter the opposite. If you see a value in
the URL, change it. If a field asks for an integer between 0 and 5, try 0, 2, 5, -1,
9, 3.5, and “Q”, and see how it handles “unexpected inputs.” If a querystring is “?UserID=6″,
change the 6 to a 7, to see if you get information on User 7, and try invalid items
like 3.5 and “Q” to see if it fails on unexpected inputs. If a client-side cookie
has a value of “User”, try changing it to “Admin” or “Administrator” and see if your
access-level is increased.
&lt;/p&gt;
&lt;p&gt;
Find the weaknesses, find the holes, and find the bugs so that they can get fixed.
You are the demolition man. You get paid to blow things up. Do it. Do it with purpose.
Pretend you are a hacker trying to get into the system. Pretend you are a teenager-hacker-wannabe
trying to screw with the system. Pretend you are a grandma that doesn’t know what
to do with the system. Do all of the things that you aren’t supposed to do to the
application and do them on purpose, because if by ignorance or intelligence, your
users will find what was missed.&lt;br&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=9e8839a2-9f66-44e1-8488-a65fdb9e47c1" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,9e8839a2-9f66-44e1-8488-a65fdb9e47c1.aspx</comments>
      <category>Programming</category>
      <category>Testing</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=0964d50c-1006-43e1-9252-214ea493e598</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,0964d50c-1006-43e1-9252-214ea493e598.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,0964d50c-1006-43e1-9252-214ea493e598.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=0964d50c-1006-43e1-9252-214ea493e598</wfw:commentRss>
      <slash:comments>6</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
For my needs, the biggest hole in Mercury LoadRunner is its lack of page size monitoring.
LoadRunner can monitor anything else imaginable, including transaction counts, transaction
times, errors, and all Windows Performance Monitor metrics. However, monitoring page
size, download times, and HTTP Return codes are only available through programming.
</p>
        <p>
The following function will monitor the page size of all responses, logging an error
if it exceeds you specified limit, as well as track all values on the user-defined
graphs.
</p>
        <pre name="code" class="cpp">si_page_size_limit(int PageLimit, char* PageName, char *PageURL, long TransactionID){
//
// Page Size Limit Monitor
// Author: Jay Harris, http://www.cptloadtest.com, (c) 2004 Jason Harris
// License: This work is licensed under a
//    Creative Commons Attribution 3.0 United States License.
//    http://creativecommons.org/licenses/by/3.0/us/
//
// Created: 10-Aug-2004
// Last Modified: 10-May-2005, Jay Harris
//
// Description:
// Logs an error to the log, pass or fail, including the applicable status, if logging is enabled.
// Plots page size datapoint to User Defined graph.
//
// Inputs:
// int PageLimit Maximum page size allowed, in bytes
// char* PageName Name of the page, such as the Title. For identification in logs.
// char* PageURL URL of the page. For reference in logs. FOr identification in logs.
// long TransactionID Transaction ID for the current request.
// Note: Transaction must be explicitly opened via lr_start_transaction_instance.
// Note: TransactionID is returned by lr_start_transaction_instance.
//
 
    int iPageSize = web_get_int_property(HTTP_INFO_DOWNLOAD_SIZE);
    char DataPointName[1024] = “Response Size [”;
    strcat(DataPointName, PageName);
    strcat(DataPointName, “]”);

    if (PageLimit &lt; iPageSize) {
        lr_continue_on_error(1);
        lr_debug_message(LR_MSG_CLASS_BRIEF_LOG | LR_MSG_CLASS_EXTENDED_LOG,
	    “Page Size Check FAILED - %s [%s] exceeds specified page size limit of %d (Total: %d)”,
	    PageName,PageURL,PageLimit,iPageSize);
        lr_continue_on_error(0);
    } else {
        lr_debug_message(LR_MSG_CLASS_BRIEF_LOG | LR_MSG_CLASS_EXTENDED_LOG,
	    “Page Size Check PASSED - %s [%s] meets specified page size limit of %d (Total: %d)”,
	    PageName,PageURL,PageLimit,iPageSize);
    }
    if (lr_get_trans_instance_status(TransactionID) == LR_PASS) {
        lr_user_data_point_instance_ex(DataPointName,iPageSize,TransactionID,DP_FLAGS_EXTENDED_LOG);
    }
    return 0;
}</pre>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=0964d50c-1006-43e1-9252-214ea493e598" />
      </body>
      <title>Page Size Monitor in LoadRunner</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,0964d50c-1006-43e1-9252-214ea493e598.aspx</guid>
      <link>http://www.cptloadtest.com/2005/05/10/Page-Size-Monitor-In-LoadRunner.aspx</link>
      <pubDate>Tue, 10 May 2005 18:51:58 GMT</pubDate>
      <description>&lt;p&gt;
For my needs, the biggest hole in Mercury LoadRunner is its lack of page size monitoring.
LoadRunner can monitor anything else imaginable, including transaction counts, transaction
times, errors, and all Windows Performance Monitor metrics. However, monitoring page
size, download times, and HTTP Return codes are only available through programming.
&lt;/p&gt;
&lt;p&gt;
The following function will monitor the page size of all responses, logging an error
if it exceeds you specified limit, as well as track all values on the user-defined
graphs.
&lt;/p&gt;
&lt;pre name="code" class="cpp"&gt;si_page_size_limit(int PageLimit, char* PageName, char *PageURL, long TransactionID){
//
// Page Size Limit Monitor
// Author: Jay Harris, http://www.cptloadtest.com, (c) 2004 Jason Harris
// License: This work is licensed under a
//    Creative Commons Attribution 3.0 United States License.
//    http://creativecommons.org/licenses/by/3.0/us/
//
// Created: 10-Aug-2004
// Last Modified: 10-May-2005, Jay Harris
//
// Description:
// Logs an error to the log, pass or fail, including the applicable status, if logging is enabled.
// Plots page size datapoint to User Defined graph.
//
// Inputs:
// int PageLimit Maximum page size allowed, in bytes
// char* PageName Name of the page, such as the Title. For identification in logs.
// char* PageURL URL of the page. For reference in logs. FOr identification in logs.
// long TransactionID Transaction ID for the current request.
// Note: Transaction must be explicitly opened via lr_start_transaction_instance.
// Note: TransactionID is returned by lr_start_transaction_instance.
//
 
    int iPageSize = web_get_int_property(HTTP_INFO_DOWNLOAD_SIZE);
    char DataPointName[1024] = “Response Size [”;
    strcat(DataPointName, PageName);
    strcat(DataPointName, “]”);

    if (PageLimit &amp;lt; iPageSize) {
        lr_continue_on_error(1);
        lr_debug_message(LR_MSG_CLASS_BRIEF_LOG | LR_MSG_CLASS_EXTENDED_LOG,
	    “Page Size Check FAILED - %s [%s] exceeds specified page size limit of %d (Total: %d)”,
	    PageName,PageURL,PageLimit,iPageSize);
        lr_continue_on_error(0);
    } else {
        lr_debug_message(LR_MSG_CLASS_BRIEF_LOG | LR_MSG_CLASS_EXTENDED_LOG,
	    “Page Size Check PASSED - %s [%s] meets specified page size limit of %d (Total: %d)”,
	    PageName,PageURL,PageLimit,iPageSize);
    }
    if (lr_get_trans_instance_status(TransactionID) == LR_PASS) {
        lr_user_data_point_instance_ex(DataPointName,iPageSize,TransactionID,DP_FLAGS_EXTENDED_LOG);
    }
    return 0;
}&lt;/pre&gt;&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=0964d50c-1006-43e1-9252-214ea493e598" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,0964d50c-1006-43e1-9252-214ea493e598.aspx</comments>
      <category>LoadRunner</category>
      <category>Performance</category>
      <category>Testing</category>
    </item>
  </channel>
</rss>