<?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 - Tools</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=084a817f-c549-4ad4-9dab-ffc998c7b487</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,084a817f-c549-4ad4-9dab-ffc998c7b487.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,084a817f-c549-4ad4-9dab-ffc998c7b487.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=084a817f-c549-4ad4-9dab-ffc998c7b487</wfw:commentRss>
      <slash:comments>5</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Increasing or decreasing the font size of your code in Visual Studio's text editor
is almost required whenever VS is fired up on a projector. Anyone who has had to demo
code, or give a talk at a user group, or present new technologies to their team has
experienced the pain of increasing the font size through the <em>Tools -&gt; Options</em> menu,
followed by an inquiry to the crowd: "How's that? Is this font size readable by everyone?"
Often times the selected size is not quite the right solution, and the process is
repeated. Life as a presenter would be easier if only you could modify the font size
through a simple keyboard command, similar to how browsers enable you adjust the font
through the <em>ctrl+</em> and <em>ctrl-</em> commands.
</p>
        <blockquote>
          <p>
            <strong>Macros.Samples.Accessibility.DecreaseTextEditorFontSize<br /></strong>Decreases the text editor font size in Visual Studio
</p>
          <p>
            <strong>Macros.Samples.Accessibility.IncreaseTextEditorFontSize<br /></strong>Increases the text editor font size in Visual Studio
</p>
        </blockquote>
        <p>
Fortunately, this is easy with the help of Visual Studio's Sample Macros. To help
show you the ropes of writing custom macros, VS ships with a collection samples, and
two of these samples respectively increase and decrease the font size of the text
editor. Right out of the box, Visual Studio comes with the ability to modify the font
size for your code; all that remains is mapping these macros to the keyboard.
</p>
        <h3>
          <img style="margin: 0px 0px 10px 20px" alt="Visual Studio Options Window, Assigning Macro to Keyboard Command" src="http://www.cptloadtest.com/content/binary/VSMacroIncreaseTextOptionsWindow.jpg" align="right" />Mapping
to the Keyboard
</h3>
        <p>
Anchoring these macros to specific keyboard commands is a simple process.
</p>
        <ol>
          <li>
From Visual Studio, access the <em>Tools -&gt; Options</em> menu.</li>
          <li>
In the <em>Options</em> window, navigate to <em>Environment -&gt; Keyboard</em>.</li>
          <li>
Using the "<em>Show commands containing"</em> input, enter in <em>IncreaseText</em> or <em>DecreaseText</em>.
The list of available commands will automatically filter as you type, reducing the
list to the applicable macro.</li>
          <li>
Select the macro command, and select the "<em>Press shortcut keys"</em> input, and
enter your desired keyboard command. Click the <em>Assign</em> button to set the command.
I use "<em>Ctrl, Alt, Shift, =</em>" (plus) and "<em>Ctrl, Alt, Shift, -</em>" for
my Increase and Decrease commands, respectively.</li>
        </ol>
        <div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:af70b901-9836-405b-a0dc-b38bbcf6bff5" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px">Technorati
Tags: <a href="http://technorati.com/tags/Visual%20Studio" rel="tag">Visual Studio</a>,<a href="http://technorati.com/tags/Presenting" rel="tag">Presenting</a>,<a href="http://technorati.com/tags/Speaking" rel="tag">Speaking</a>,<a href="http://technorati.com/tags/Macros" rel="tag">Macros</a></div>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=084a817f-c549-4ad4-9dab-ffc998c7b487" />
      </body>
      <title>Visual Studio Macro: Modify Text Editor Font Size</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,084a817f-c549-4ad4-9dab-ffc998c7b487.aspx</guid>
      <link>http://www.cptloadtest.com/2009/01/26/Visual-Studio-Macro-Modify-Text-Editor-Font-Size.aspx</link>
      <pubDate>Mon, 26 Jan 2009 16:38:48 GMT</pubDate>
      <description>&lt;p&gt;
Increasing or decreasing the font size of your code in Visual Studio's text editor
is almost required whenever VS is fired up on a projector. Anyone who has had to demo
code, or give a talk at a user group, or present new technologies to their team has
experienced the pain of increasing the font size through the &lt;em&gt;Tools -&amp;gt; Options&lt;/em&gt; menu,
followed by an inquiry to the crowd: "How's that? Is this font size readable by everyone?"
Often times the selected size is not quite the right solution, and the process is
repeated. Life as a presenter would be easier if only you could modify the font size
through a simple keyboard command, similar to how browsers enable you adjust the font
through the &lt;em&gt;ctrl+&lt;/em&gt; and &lt;em&gt;ctrl-&lt;/em&gt; commands.
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&lt;strong&gt;Macros.Samples.Accessibility.DecreaseTextEditorFontSize&lt;br&gt;
&lt;/strong&gt;Decreases the text editor font size in Visual Studio
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Macros.Samples.Accessibility.IncreaseTextEditorFontSize&lt;br&gt;
&lt;/strong&gt;Increases the text editor font size in Visual Studio
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
Fortunately, this is easy with the help of Visual Studio's Sample Macros. To help
show you the ropes of writing custom macros, VS ships with a collection samples, and
two of these samples respectively increase and decrease the font size of the text
editor. Right out of the box, Visual Studio comes with the ability to modify the font
size for your code; all that remains is mapping these macros to the keyboard.
&lt;/p&gt;
&lt;h3&gt;&lt;img style="margin: 0px 0px 10px 20px" alt="Visual Studio Options Window, Assigning Macro to Keyboard Command" src="http://www.cptloadtest.com/content/binary/VSMacroIncreaseTextOptionsWindow.jpg" align="right"&gt;Mapping
to the Keyboard
&lt;/h3&gt;
&lt;p&gt;
Anchoring these macros to specific keyboard commands is a simple process.
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
From Visual Studio, access the &lt;em&gt;Tools -&amp;gt; Options&lt;/em&gt; menu.&lt;/li&gt;
&lt;li&gt;
In the &lt;em&gt;Options&lt;/em&gt; window, navigate to &lt;em&gt;Environment -&amp;gt; Keyboard&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
Using the "&lt;em&gt;Show commands containing"&lt;/em&gt; input, enter in &lt;em&gt;IncreaseText&lt;/em&gt; or &lt;em&gt;DecreaseText&lt;/em&gt;.
The list of available commands will automatically filter as you type, reducing the
list to the applicable macro.&lt;/li&gt;
&lt;li&gt;
Select the macro command, and select the "&lt;em&gt;Press shortcut keys"&lt;/em&gt; input, and
enter your desired keyboard command. Click the &lt;em&gt;Assign&lt;/em&gt; button to set the command.
I use "&lt;em&gt;Ctrl, Alt, Shift, =&lt;/em&gt;" (plus) and "&lt;em&gt;Ctrl, Alt, Shift, -&lt;/em&gt;" for
my Increase and Decrease commands, respectively.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:af70b901-9836-405b-a0dc-b38bbcf6bff5" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati
Tags: &lt;a href="http://technorati.com/tags/Visual%20Studio" rel="tag"&gt;Visual Studio&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Presenting" rel="tag"&gt;Presenting&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Speaking" rel="tag"&gt;Speaking&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Macros" rel="tag"&gt;Macros&lt;/a&gt;
&lt;/div&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=084a817f-c549-4ad4-9dab-ffc998c7b487" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,084a817f-c549-4ad4-9dab-ffc998c7b487.aspx</comments>
      <category>Speaking</category>
      <category>Tools</category>
      <category>Visual Studio</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=e54fb1b0-d25c-4f0b-a4cd-eefa8c3715e9</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,e54fb1b0-d25c-4f0b-a4cd-eefa8c3715e9.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,e54fb1b0-d25c-4f0b-a4cd-eefa8c3715e9.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=e54fb1b0-d25c-4f0b-a4cd-eefa8c3715e9</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
As I discussed in an earlier post (<a title="Jay Harris, Blog Post: Blog your code using Google Syntax Highlighter" href="http://www.cptloadtest.com/2008/11/24/BlogYourCodeUsingGoogleSyntaxHighlighter.aspx">Blog
your code using Google Syntax Highlighter</a>), Google Syntax Highlighter is a simple
tool that allows bloggers to easily display code in a format that is familiar end
users. The tool renders the code in a very consumable fashion that includes colored
syntax highlighting, line highlighting, and line numbers. Out of the box it supports
most of the common languages of today, and a few from yesterday, but some common languages
are unsupported. Perl, ColdFusion, and Flash's ActionScript all are unloved by Google
Syntax Highlighter, as are many others that you may want to post to your blog. For
these languages, the solution is a custom brush.
</p>
        <h3>Syntax Highlighting Brushes
</h3>
        <p>
For Google Syntax Highlighter, brushes are JavaScript files that govern the syntax
highlighting process, with names following the format of shBrushLanguage.js, such
as shBrushXml.js. Brushes contain information about the keywords, functions, and operators
of a language, as well as the syntax for comments, strings, and other syntax characteristics.
Keyword-level syntax is applied to any specific word in the language, including keywords,
functions, and any word operators, such as <em>and</em>, <em>or</em>, and <em>not</em>.
Regular expressions apply character-level syntax to code, and identifies items such
as character operators, the remainder of an inline comment, or the entire contents
of a comment block. Finally, aliases are defined for the brush; these are the language
aliases that are used within the <em>class</em> attribute of the Google Syntax Highlighter
&lt;PRE&gt; tag. With this information, the brush applies the syntax highlighting
styles according to the CSS defined for each component of the language. 
</p>
        <h3>Breaking Down Brushes
</h3>
        <h4>Decomposing the SQL Brush
</h4>
        <p>
In JavaScript, everything is an object that can be assigned to a variable, whether
its a number, string, function, or class. Brushes are each a delegate function. The
variable name of the brush must match <em>dp.sh.Brushes.SomeLanguage</em>.
</p>
        <pre class="js:nocontrols:firstline[1]" name="code">dp.sh.Brushes.Sql = function() {</pre>
        <p>
Next, define the list of keywords for applying syntax highlighting. Each list is not
an array, but rather a single-space delimited string of keywords that will be highlighted.
Also, multiple keyword lists can exist, such as one list for function names, another
for keywords, and perhaps another for types, and unique styling can be applied to
each grouping (we'll get to styling a little later). 
</p>
        <pre class="js:nocontrols:firstline[2]" name="code">  var funcs = 'abs avg case cast coalesce convert count current_timestamp ' +
    'current_user day isnull left lower month nullif replace right ' +
    'session_user space substring sum system_user upper user year';

  var keywords = 'absolute action add after alter as asc at authorization ' +
    'begin bigint binary bit by cascade char character check checkpoint ' +
    'close collate column commit committed connect connection constraint ' +
    'contains continue create cube current current_date current_time ' +
    'cursor database date deallocate dec decimal declare default delete ' +
    'desc distinct double drop dynamic else end end-exec escape except ' +
    'exec execute false fetch first float for force foreign forward free ' +
    'from full function global goto grant group grouping having hour ' +
    'ignore index inner insensitive insert instead int integer intersect ' +
    'into is isolation key last level load local max min minute modify ' +
    'move name national nchar next no numeric of off on only open option ' +
    'order out output partial password precision prepare primary prior ' +
    'privileges procedure public read real references relative repeatable ' +
    'restrict return returns revoke rollback rollup rows rule schema ' +
    'scroll second section select sequence serializable set size smallint ' +
    'static statistics table temp temporary then time timestamp to top ' +
    'transaction translation trigger true truncate uncommitted union ' +
    'unique update values varchar varying view when where with work';

  var operators = 'all and any between cross in join like not null or ' +
    'outer some';</pre>
        <p>
Following the keyword definitions is the Regular Expression pattern and Style definition
object list. The list, <em>this.regexList</em>, is an array of pattern/style objects: <em>{regex:
regexPattern, css: classString}</em>. The <em>regexPattern</em> is a JavaScript <em>RegExp</em> object,
and defines the pattern to match in the source code; this pattern can be created using
one of three options within Google Syntax Highlighter. 
</p>
        <dl>
          <dt>Predefined Patterns </dt>
          <dd>Within Google Syntax Highlighter, <em>dp.sh.RegexLib</em> contains five predefined
regular expression patterns. <em>MultiLineCComments</em> is used for any language
that uses C-style multi-line comment blocks: <em>/* my comment block */</em>. <em>SingleLineCComments</em> is
used for any language that uses C-style single line or inline comments: <em>// my
comment</em>. <em>SingleLinePerlComments</em> applies for Perl-style single line comments: <em>#
my comment</em>. <em>DoubleQuotedString</em> identifies any string wrapped in double-quotes
and <em>SingleQuotedString</em> identifies strings wrapped in single-quotes. These
options are used in place of creating a new instance of the <em>RegExp</em> object. 
</dd>
          <dt>Keyword Patterns </dt>
          <dd>Google Syntax Highlighter has a <em>GetKeywords(string)</em> function which will
build a pattern string based on one of the brush's defined keyword strings. However,
this is only the pattern string, and not the <em>RegExp</em> object. Pass this value
into the <em>RegExp</em> constructor: <em>new RegExp(this.GetKeyword(keywords), 'gmi')</em></dd>
          <dt>Custom Pattern Definition </dt>
          <dd>Create a new <em>RegExp</em> object using a custom pattern. For example, use <em>new
RegExp('--(.*)$', 'gm')</em> to match all Sql comments, such as <em>--my comment</em>.</dd>
        </dl>
        <p>
For these pattern/style objects, the regular expression pattern is followed by the
name of the CSS class to apply to any regular expression matches. The style sheet
packaged with Google Syntax Highlighter, SyntaxHighlighter.css, already defines the
many CSS classes used by GSH; place the additional styles for your custom brushes
within this file, in a new file, in your HTML, or defined them within the brush using
JavaScript.
</p>
        <pre class="js:nocontrols:firstline[27]" name="code">  this.regexList = [
    {regex: new RegExp('--(.*)$', 'gm'), css: 'comment'},
    {regex: dp.sh.RegexLib.DoubleQuotedString, css: 'string'},
    {regex: dp.sh.RegexLib.SingleQuotedString, css: 'string'},
    {regex: new RegExp(this.GetKeywords(funcs), 'gmi'), css: 'func'},
    {regex: new RegExp(this.GetKeywords(operators), 'gmi'), css: 'op'},
    {regex: new RegExp(this.GetKeywords(keywords), 'gmi'), css: 'keyword'}
  ];</pre>
        <p>
The delegate definition ends with any style specifications. Apply a style sheet to
the entire code block using <em>this.CssClass</em>. Also, as mentioned above, the
brush can define custom CSS using this.Style as an alternative to placing the CSS
in HTML or a CSS file. When finished, close the delegate.
</p>
        <pre class="js:nocontrols:firstline[36]" name="code">  this.CssClass = 'dp-sql';
  this.Style = '.dp-sql .func { color: #ff1493; }' +
    '.dp-sql .op { color: #808080; }'; }
</pre>
        <p>
The final component of a Brush, set outside of your delegate, contains the prototype
declaration and any aliases to apply to the Brush. Aliases consist of a string array
(a real array this time, not a space-delimited string) of language aliases to use,
such as ['c#','c-sharp','csharp']. Alias values must be unique across all defined
brushes that you have included into your site.
</p>
        <pre class="js:nocontrols:firstline[40]" name="code">dp.sh.Brushes.Sql.prototype = new dp.sh.Highlighter();
dp.sh.Brushes.Sql.Aliases = ['sql'];</pre>
        <h3>Making a Custom Brush (for ActionScript) 
</h3>
        <p>
I like rich media applications, such as those developed in Flash or Silverlight. I
was surprised when I found that Google Syntax Highlighter does not ship with an ActionScript
brush, and more surprised when I found out that no one has written one, yet. So, using
the methods from above, I created one. This isn't meant to be an exhaustive brush,
but more like <a href="http://en.wikipedia.org/wiki/Stone_soup">Stone Soup</a>. It's
a start. Please feel free to add to it.
</p>
        <pre class="js" name="code">dp.sh.Brushes.ActionScript = function() {

  var keywords = 'and break case catch class continue default do dynamic else ' +
    'extends false finally for if implements import in interface NaN new not ' +
    'null or private public return static super switch this throw true try ' +
    'undefined var void while with';

  this.regexList = [{regex: dp.sh.RegexLib.SingleLineCComments, css: 'comment'},
    {regex: dp.sh.RegexLib.MultiLineCComments, css: 'comment'},
    {regex: dp.sh.RegexLib.DoubleQuotedString, css: 'string'},
    {regex: dp.sh.RegexLib.SingleQuotedString, css: 'string'},
    {regex: new RegExp(this.GetKeywords(keywords), 'gm'), css: 'keyword'}];

    this.CssClass = 'dp-as';
}

dp.sh.Brushes.ActionScript.prototype = new dp.sh.Highlighter();
dp.sh.Brushes.ActionScript.Aliases = ['actionscript', 'as'];</pre>
        <div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:51b61cce-ee33-4c5c-9de4-a3c6cf350c46" style="margin: 0px; padding: 0px; display: inline;">Technorati
Tags: <a href="http://technorati.com/tags/Syntax%20Highlighter" rel="tag">Syntax Highlighter</a>,<a href="http://technorati.com/tags/SyntaxHighlighter" rel="tag">SyntaxHighlighter</a>,<a href="http://technorati.com/tags/Google%20Code" rel="tag">Google
Code</a>,<a href="http://technorati.com/tags/ActionScript" rel="tag">ActionScript</a></div>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=e54fb1b0-d25c-4f0b-a4cd-eefa8c3715e9" />
      </body>
      <title>Extending Language Support in Google Syntax Highlighter</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,e54fb1b0-d25c-4f0b-a4cd-eefa8c3715e9.aspx</guid>
      <link>http://www.cptloadtest.com/2008/12/10/Extending-Language-Support-In-Google-Syntax-Highlighter.aspx</link>
      <pubDate>Wed, 10 Dec 2008 21:47:27 GMT</pubDate>
      <description>&lt;p&gt;
As I discussed in an earlier post (&lt;a title="Jay Harris, Blog Post: Blog your code using Google Syntax Highlighter" href="http://www.cptloadtest.com/2008/11/24/BlogYourCodeUsingGoogleSyntaxHighlighter.aspx"&gt;Blog
your code using Google Syntax Highlighter&lt;/a&gt;), Google Syntax Highlighter is a simple
tool that allows bloggers to easily display code in a format that is familiar end
users. The tool renders the code in a very consumable fashion that includes colored
syntax highlighting, line highlighting, and line numbers. Out of the box it supports
most of the common languages of today, and a few from yesterday, but some common languages
are unsupported. Perl, ColdFusion, and Flash's ActionScript all are unloved by Google
Syntax Highlighter, as are many others that you may want to post to your blog. For
these languages, the solution is a custom brush.
&lt;/p&gt;
&lt;h3&gt;Syntax Highlighting Brushes
&lt;/h3&gt;
&lt;p&gt;
For Google Syntax Highlighter, brushes are JavaScript files that govern the syntax
highlighting process, with names following the format of shBrushLanguage.js, such
as shBrushXml.js. Brushes contain information about the keywords, functions, and operators
of a language, as well as the syntax for comments, strings, and other syntax characteristics.
Keyword-level syntax is applied to any specific word in the language, including keywords,
functions, and any word operators, such as &lt;em&gt;and&lt;/em&gt;, &lt;em&gt;or&lt;/em&gt;, and &lt;em&gt;not&lt;/em&gt;.
Regular expressions apply character-level syntax to code, and identifies items such
as character operators, the remainder of an inline comment, or the entire contents
of a comment block. Finally, aliases are defined for the brush; these are the language
aliases that are used within the &lt;em&gt;class&lt;/em&gt; attribute of the Google Syntax Highlighter
&amp;lt;PRE&amp;gt; tag. With this information, the brush applies the syntax highlighting
styles according to the CSS defined for each component of the language. 
&lt;/p&gt;
&lt;h3&gt;Breaking Down Brushes
&lt;/h3&gt;
&lt;h4&gt;Decomposing the SQL Brush
&lt;/h4&gt;
&lt;p&gt;
In JavaScript, everything is an object that can be assigned to a variable, whether
its a number, string, function, or class. Brushes are each a delegate function. The
variable name of the brush must match &lt;em&gt;dp.sh.Brushes.SomeLanguage&lt;/em&gt;.
&lt;/p&gt;
&lt;pre class="js:nocontrols:firstline[1]" name="code"&gt;dp.sh.Brushes.Sql = function() {&lt;/pre&gt;
&lt;p&gt;
Next, define the list of keywords for applying syntax highlighting. Each list is not
an array, but rather a single-space delimited string of keywords that will be highlighted.
Also, multiple keyword lists can exist, such as one list for function names, another
for keywords, and perhaps another for types, and unique styling can be applied to
each grouping (we'll get to styling a little later). 
&lt;/p&gt;
&lt;pre class="js:nocontrols:firstline[2]" name="code"&gt;  var funcs = 'abs avg case cast coalesce convert count current_timestamp ' +
    'current_user day isnull left lower month nullif replace right ' +
    'session_user space substring sum system_user upper user year';

  var keywords = 'absolute action add after alter as asc at authorization ' +
    'begin bigint binary bit by cascade char character check checkpoint ' +
    'close collate column commit committed connect connection constraint ' +
    'contains continue create cube current current_date current_time ' +
    'cursor database date deallocate dec decimal declare default delete ' +
    'desc distinct double drop dynamic else end end-exec escape except ' +
    'exec execute false fetch first float for force foreign forward free ' +
    'from full function global goto grant group grouping having hour ' +
    'ignore index inner insensitive insert instead int integer intersect ' +
    'into is isolation key last level load local max min minute modify ' +
    'move name national nchar next no numeric of off on only open option ' +
    'order out output partial password precision prepare primary prior ' +
    'privileges procedure public read real references relative repeatable ' +
    'restrict return returns revoke rollback rollup rows rule schema ' +
    'scroll second section select sequence serializable set size smallint ' +
    'static statistics table temp temporary then time timestamp to top ' +
    'transaction translation trigger true truncate uncommitted union ' +
    'unique update values varchar varying view when where with work';

  var operators = 'all and any between cross in join like not null or ' +
    'outer some';&lt;/pre&gt;
&lt;p&gt;
Following the keyword definitions is the Regular Expression pattern and Style definition
object list. The list, &lt;em&gt;this.regexList&lt;/em&gt;, is an array of pattern/style objects: &lt;em&gt;{regex:
regexPattern, css: classString}&lt;/em&gt;. The &lt;em&gt;regexPattern&lt;/em&gt; is a JavaScript &lt;em&gt;RegExp&lt;/em&gt; object,
and defines the pattern to match in the source code; this pattern can be created using
one of three options within Google Syntax Highlighter. 
&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;Predefined Patterns &lt;/dt&gt;
&lt;dd&gt;Within Google Syntax Highlighter, &lt;em&gt;dp.sh.RegexLib&lt;/em&gt; contains five predefined
regular expression patterns. &lt;em&gt;MultiLineCComments&lt;/em&gt; is used for any language
that uses C-style multi-line comment blocks: &lt;em&gt;/* my comment block */&lt;/em&gt;. &lt;em&gt;SingleLineCComments&lt;/em&gt; is
used for any language that uses C-style single line or inline comments: &lt;em&gt;// my
comment&lt;/em&gt;. &lt;em&gt;SingleLinePerlComments&lt;/em&gt; applies for Perl-style single line comments: &lt;em&gt;#
my comment&lt;/em&gt;. &lt;em&gt;DoubleQuotedString&lt;/em&gt; identifies any string wrapped in double-quotes
and &lt;em&gt;SingleQuotedString&lt;/em&gt; identifies strings wrapped in single-quotes. These
options are used in place of creating a new instance of the &lt;em&gt;RegExp&lt;/em&gt; object. 
&lt;/dd&gt;
&lt;dt&gt;Keyword Patterns &lt;/dt&gt;
&lt;dd&gt;Google Syntax Highlighter has a &lt;em&gt;GetKeywords(string)&lt;/em&gt; function which will
build a pattern string based on one of the brush's defined keyword strings. However,
this is only the pattern string, and not the &lt;em&gt;RegExp&lt;/em&gt; object. Pass this value
into the &lt;em&gt;RegExp&lt;/em&gt; constructor: &lt;em&gt;new RegExp(this.GetKeyword(keywords), 'gmi')&lt;/em&gt; 
&lt;/dd&gt;
&lt;dt&gt;Custom Pattern Definition &lt;/dt&gt;
&lt;dd&gt;Create a new &lt;em&gt;RegExp&lt;/em&gt; object using a custom pattern. For example, use &lt;em&gt;new
RegExp('--(.*)$', 'gm')&lt;/em&gt; to match all Sql comments, such as &lt;em&gt;--my comment&lt;/em&gt;.&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;
For these pattern/style objects, the regular expression pattern is followed by the
name of the CSS class to apply to any regular expression matches. The style sheet
packaged with Google Syntax Highlighter, SyntaxHighlighter.css, already defines the
many CSS classes used by GSH; place the additional styles for your custom brushes
within this file, in a new file, in your HTML, or defined them within the brush using
JavaScript.
&lt;/p&gt;
&lt;pre class="js:nocontrols:firstline[27]" name="code"&gt;  this.regexList = [
    {regex: new RegExp('--(.*)$', 'gm'), css: 'comment'},
    {regex: dp.sh.RegexLib.DoubleQuotedString, css: 'string'},
    {regex: dp.sh.RegexLib.SingleQuotedString, css: 'string'},
    {regex: new RegExp(this.GetKeywords(funcs), 'gmi'), css: 'func'},
    {regex: new RegExp(this.GetKeywords(operators), 'gmi'), css: 'op'},
    {regex: new RegExp(this.GetKeywords(keywords), 'gmi'), css: 'keyword'}
  ];&lt;/pre&gt;
&lt;p&gt;
The delegate definition ends with any style specifications. Apply a style sheet to
the entire code block using &lt;em&gt;this.CssClass&lt;/em&gt;. Also, as mentioned above, the
brush can define custom CSS using this.Style as an alternative to placing the CSS
in HTML or a CSS file. When finished, close the delegate.
&lt;/p&gt;
&lt;pre class="js:nocontrols:firstline[36]" name="code"&gt;  this.CssClass = 'dp-sql';
  this.Style = '.dp-sql .func { color: #ff1493; }' +
    '.dp-sql .op { color: #808080; }'; }
&lt;/pre&gt;
&lt;p&gt;
The final component of a Brush, set outside of your delegate, contains the prototype
declaration and any aliases to apply to the Brush. Aliases consist of a string array
(a real array this time, not a space-delimited string) of language aliases to use,
such as ['c#','c-sharp','csharp']. Alias values must be unique across all defined
brushes that you have included into your site.
&lt;/p&gt;
&lt;pre class="js:nocontrols:firstline[40]" name="code"&gt;dp.sh.Brushes.Sql.prototype = new dp.sh.Highlighter();
dp.sh.Brushes.Sql.Aliases = ['sql'];&lt;/pre&gt;
&lt;h3&gt;Making a Custom Brush (for ActionScript) 
&lt;/h3&gt;
&lt;p&gt;
I like rich media applications, such as those developed in Flash or Silverlight. I
was surprised when I found that Google Syntax Highlighter does not ship with an ActionScript
brush, and more surprised when I found out that no one has written one, yet. So, using
the methods from above, I created one. This isn't meant to be an exhaustive brush,
but more like &lt;a href="http://en.wikipedia.org/wiki/Stone_soup"&gt;Stone Soup&lt;/a&gt;. It's
a start. Please feel free to add to it.
&lt;/p&gt;
&lt;pre class="js" name="code"&gt;dp.sh.Brushes.ActionScript = function() {

  var keywords = 'and break case catch class continue default do dynamic else ' +
    'extends false finally for if implements import in interface NaN new not ' +
    'null or private public return static super switch this throw true try ' +
    'undefined var void while with';

  this.regexList = [{regex: dp.sh.RegexLib.SingleLineCComments, css: 'comment'},
    {regex: dp.sh.RegexLib.MultiLineCComments, css: 'comment'},
    {regex: dp.sh.RegexLib.DoubleQuotedString, css: 'string'},
    {regex: dp.sh.RegexLib.SingleQuotedString, css: 'string'},
    {regex: new RegExp(this.GetKeywords(keywords), 'gm'), css: 'keyword'}];

    this.CssClass = 'dp-as';
}

dp.sh.Brushes.ActionScript.prototype = new dp.sh.Highlighter();
dp.sh.Brushes.ActionScript.Aliases = ['actionscript', 'as'];&lt;/pre&gt;
&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:51b61cce-ee33-4c5c-9de4-a3c6cf350c46" style="margin: 0px; padding: 0px; display: inline;"&gt;Technorati
Tags: &lt;a href="http://technorati.com/tags/Syntax%20Highlighter" rel="tag"&gt;Syntax Highlighter&lt;/a&gt;,&lt;a href="http://technorati.com/tags/SyntaxHighlighter" rel="tag"&gt;SyntaxHighlighter&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Google%20Code" rel="tag"&gt;Google
Code&lt;/a&gt;,&lt;a href="http://technorati.com/tags/ActionScript" rel="tag"&gt;ActionScript&lt;/a&gt;
&lt;/div&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=e54fb1b0-d25c-4f0b-a4cd-eefa8c3715e9" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,e54fb1b0-d25c-4f0b-a4cd-eefa8c3715e9.aspx</comments>
      <category>Blogging</category>
      <category>Flash</category>
      <category>JavaScript</category>
      <category>Programming</category>
      <category>Tools</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=417c2df3-d32c-436c-8c5c-46e1fe4b2808</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,417c2df3-d32c-436c-8c5c-46e1fe4b2808.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,417c2df3-d32c-436c-8c5c-46e1fe4b2808.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=417c2df3-d32c-436c-8c5c-46e1fe4b2808</wfw:commentRss>
      <slash:comments>9</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <a href="http://code.google.com/p/syntaxhighlighter/">Google Syntax Highlighter</a> is
a simple tool that allows bloggers to easily display code in a format that is familiar
end users. The tool renders the code in a very consumable fashion that includes colored
syntax highlighting, line highlighting, and line numbers.
</p>
        <pre class="csharp:nocontrols" name="code">/*
This is an example of how Google
Syntax Highlighter can highlight and display syntax
to you, the end user
*/
public void HelloWorld()
{
  // I have some comments
  Console.WriteLine("Hello, World!");
}</pre>
        <p>
It is purely a client-side tool, as all of the processing is done strictly within
the browser through JavaScript. There is no server-side processing. Since it is all
JavaScript, you don't need special Copy/Paste plugins and macros installed to your
favorite IDE or your blog authoring tool. (I am leery of random plugins and installing
them into the software that I use to feed my family.) To including code in your blog
post, copy your code from Visual Studio, Notepad, Flash, Firebug, or any tool that
displays text, and paste it in to your post. As of v1.5.1, Google Syntax Highlighter
supports C, C++, C#, CSS, Delphi, HTML, Java, JavaScript, PHP, Pascal, Python, Ruby,
SQL, VB, VB.NET, XML, XSLT, and all of this is just what comes out of the box.
</p>
        <h3>Setting Up Syntax Highlighter
</h3>
        <p>
To get Syntax Highlighter running on your blog, <a href="http://code.google.com/p/syntaxhighlighter/downloads/list">download</a> the
latest version of the RAR archive and extract the code. The archive contains a parent
folder, <em>dp.SyntaxHighlighter</em>, with three child folders:
</p>
        <blockquote>
          <pre>dp.SyntaxHighlighter
  \Scripts         //Production-ready (Compressed) scripts
  \Styles          //CSS
  \Uncompressed    //Human-readable (Uncompressed/Debug) scripts</pre>
        </blockquote>
        <p>
Once the archive is extracted, upload <em>dp.SyntaxHighlighter</em> to your blog.
Feel free to rename the folder if you like, though I did not. It is not necessary
to upload the <em>Uncompressed</em> folder and its files; they are best used for debugging
or for viewing the code, as the files in the <em>Scripts</em> folder have been compressed
to reduce bandwidth by having most of their whitespace removed.
</p>
        <p>
After you have uploaded the files, you will need to add script and style references
to your site's HTML. This is code is not for your posts, but rather for your blog
template. In DasBlog, I place this code in the &lt;HEAD&gt; block of my <em>homeTemplate.blogtemplate</em> file.
Remember to change the file paths to match the path to where you uploaded the code.
</p>
        <pre class="html:nocontrols:nogutter" name="code">&lt;link type="text/css" rel="stylesheet"
  href="dp.SyntaxHighlighter/Styles/SyntaxHighlighter.css"&gt;&lt;/link&gt;
&lt;script language="javascript" src="dp.SyntaxHighlighter/Scripts/shCore.js"&gt;&lt;/script&gt;
&lt;script language="javascript" src="dp.SyntaxHighlighter/Scripts/shBrushCSharp.js"&gt;&lt;/script&gt;
&lt;script language="javascript" src="dp.SyntaxHighlighter/Scripts/shBrushXml.js"&gt;&lt;/script&gt;
&lt;script language="javascript"&gt;
window.onload = function () {
  dp.SyntaxHighlighter.ClipboardSwf = 'dp.SyntaxHighlighter/Scripts/clipboard.swf';
  dp.SyntaxHighlighter.HighlightAll('code');
}
&lt;/script&gt;</pre>
        <p>
To make the tool most efficient, including minimizing the code download by the client
browser, highlighting is only enabled for the languages that you specify. The highlighting
rules for each language is available through a file referred to as a Brush. The code
sample above enables only C# and XML/HTML by including the core file, <em>shCore.js</em>,
the C# brush, <em>shBrushCSharp.js</em> and the XML/HTML brush, <em>shBrushXml.js</em>.
A unique brush file is available for each of the supported languages, and only the
core file is required. These brushes are located in your <em>Scripts</em> directory
(the human-readable version is in the <em>Uncompressed</em> folder). Include only
the brushes that you like; if you forgot a language brush, the code will still display
on your page, but as unformatted text.
</p>
        <pre>&lt;!-- Unformatted HTML Code / No Brush --&gt;
&lt;p id="greeting"&gt;Hi, mom &amp; dad!&lt;/p&gt;</pre>
        <pre class="html:nogutter:nocontrols" name="code">&lt;!-- Formatted HTML Code --&gt;
&lt;p id="greeting"&gt;Hi, mom &amp; dad!&lt;/p&gt;</pre>
        <h3>Making Syntax Highlighter Go
</h3>
        <p>
Now that the application is deployed to the site, how does it get applied to a post?
Paste the code into the HTML view of your post, inside of a &lt;PRE&gt; tag. Create
a <em>name</em> attribute on your tag with a value of <em>code</em>, and a <em>class</em> attribute
set to the language and options you are using.
</p>
        <pre class="html:nocontrols:nogutter" name="code">&lt;pre name="code" class="c-sharp"&gt;
  public void HelloWorld()
  {
    Console.WriteLine("Hello, World!");
  }
&lt;/pre&gt;</pre>
        <p>
One catch is the code must be first made HTML-safe. All angle-brackets, <em>&lt;tag&gt;</em>,
must be converted to their HTML equivalent, <em>&amp;lt;tag&amp;gt;</em>, as well
as ampersands, <em>&amp;</em> to <em>&amp;amp;</em>. I also find it helpful if your
code-indentation uses two-spaces, rather than tabs.
</p>
        <pre class="html:nocontrols" name="code">&lt;!-- Pre-converted code --&gt;
&lt;p&gt;Hi, mom &amp; dad!&lt;/p&gt;</pre>
        <pre class="html:nocontrols" name="code">&lt;!-- Converted code --&gt;
&lt;pre name="code" class="html"&gt;
  &amp;lt;p&amp;gt;Hi, mom &amp;amp; dad!&amp;lt;/p&amp;gt;
&lt;/pre&gt;</pre>
        <p>
The <em>class</em> attribute is made up of both language and option aliases. These
aliases consist of one language followed by your desired options, all in a colon delimited
list.
</p>
        <p>
class="language[:option[:option[:option]]]"
</p>
        <p>
The value of language is any of Syntax Highlighter's defined language aliases, such
as <em>c#</em>, <em>csharp</em>, or <em>c-sharp</em> for C#, or <em>rb</em>, <em>ruby</em>, <em>rails</em>,
or <em>ror</em> for Ruby. See: <a href="http://code.google.com/p/syntaxhighlighter/wiki/Languages">full
list</a> of available languages.
</p>
        <p>
Options allow for such things as turning off the plain text / copy / about controls
(<em>nocontrols</em>), turning off the line number gutter (<em>nogutter</em>), or
specifying the number of the first line (<em>firstline[n]</em>). A JavaScript code
block with no controls header, and starting the line numbering at 34 would have a <em>class</em> attribute
value of <em>class="js:nocontrols:linenumber[34]"</em>. See: <a href="http://code.google.com/p/syntaxhighlighter/wiki/Configuration">full
list</a> of available options.
</p>
        <h3>Extending Syntax Highlighter
</h3>
        <p>
Because Google Syntax Highlighter is entirely in JavaScript, you have access to all
of the code. Edit it however you like to suit your needs. Additionally, brushes are
very easy to create, and include little more than a list of a highlighted language's
keywords in a string and an array of language aliases. Creating a brush for ActionScript
or QBasic would not take much time. Language brushes exist in the wild for <a href="http://nevstokes.com/includes/syntax/scripts/shBrushPerl.js">Perl</a>, <a href="http://pcnorb.blogspot.com/2008/10/shbrushbatch-for-google.html">DOS
Batch</a>, and <a href="http://blog.tech-cats.com/2007/10/syntax-highlighting-for-coldfusion.html">ColdFusion</a>.
</p>
        <p>
In a future post I plan on discussing Brush Creation in depth through creating a brush
for ActionScript.
</p>
        <h3>Comparing Syntax Highlighter to Others
</h3>
        <p>
I am a fan of this tool, though that should be obvious considering it is what I use
on this blog. I like how readable the code is, how extendable it is, and how easy
it is to use. I don't like its compatibility--or lack thereof--with RSS; since all
of the work is done in JavaScript, and RSS doesn't do JavaScript, there is no syntax
highlighting, numbers, or options within a feed, though the code formatting is still
maintained. Other tools, like the <em><a href="http://www.jtleigh.com/people/colin/software/CopySourceAsHtml/">CopySourceAsHtml</a></em> plugin
for Visual Studio or <em><a href="http://lvildosola.blogspot.com/2007/02/code-snippet-plugin-for-windows-live.html">Insert
Code Snippet</a></em> for Windows Live Writer convert your code into formatted HTML,
where all of the syntax highlighting is applied through HTML attributes and embedded
CSS. Their methods are much easier than Syntax Highlighter, since there are no stylesheets
or JavaScript files to include in your HTML, and you don't have to worry about making
your code HTML-safe. Also, their method works in RSS feeds. However, there isn't the
same level of control. Through Syntax Highlighter's extendibility, I can theme my
code views, such as if I wanted them to look like my personal Visual Studio theme.
Through Syntax Highlighter, I can also make changes at a later time, and those changes
will immediately reflected in all past posts, whereas making modifications to the
HTML/embedded CSS pattern is much more difficult.
</p>
        <h3>Final Thoughts
</h3>
        <p>
I like CopySourceAsHtml in Visual Studio. I used it for years on this blog. But I
code in more languages than VB.Net or C#, and the plugin isn't available within the
Flash or LoadRunner IDE. I was also frustrated with pasting my code in, only to find
that it was too wide for my blog theme's margins, and would have to go back to Visual
Studio, change my line endings, and repeat the process. I'm sticking with Google Syntax
Highlighter. It works for all of my languages (as soon as I finish writing my ActionScript
brush), and when my line endings are too long, I simply change my HTML. And in my
HTML, my code still looks like code, rather than a mess of embedded style. I have
to sacrifice RSS formatting, but as a presentation developer that is very particular
about his HTML, I am glad for the customization and control.
</p>
        <div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:5e03f5f4-120c-4ce0-96ea-32867691f7e7" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px">Technorati
Tags: <a href="http://technorati.com/tags/SyntaxHighlighter" rel="tag">SyntaxHighlighter</a>,<a href="http://technorati.com/tags/Syntax%20Highlighter" rel="tag">Syntax
Highlighter</a>,<a href="http://technorati.com/tags/Google%20Code" rel="tag">Google
Code</a></div>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=417c2df3-d32c-436c-8c5c-46e1fe4b2808" />
      </body>
      <title>Blog your code using Google Syntax Highlighter</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,417c2df3-d32c-436c-8c5c-46e1fe4b2808.aspx</guid>
      <link>http://www.cptloadtest.com/2008/11/24/Blog-Your-Code-Using-Google-Syntax-Highlighter.aspx</link>
      <pubDate>Mon, 24 Nov 2008 15:41:50 GMT</pubDate>
      <description>&lt;p&gt;
&lt;a href="http://code.google.com/p/syntaxhighlighter/"&gt;Google Syntax Highlighter&lt;/a&gt; is
a simple tool that allows bloggers to easily display code in a format that is familiar
end users. The tool renders the code in a very consumable fashion that includes colored
syntax highlighting, line highlighting, and line numbers.
&lt;/p&gt;
&lt;pre class="csharp:nocontrols" name="code"&gt;/*
This is an example of how Google
Syntax Highlighter can highlight and display syntax
to you, the end user
*/
public void HelloWorld()
{
  // I have some comments
  Console.WriteLine("Hello, World!");
}&lt;/pre&gt;
&lt;p&gt;
It is purely a client-side tool, as all of the processing is done strictly within
the browser through JavaScript. There is no server-side processing. Since it is all
JavaScript, you don't need special Copy/Paste plugins and macros installed to your
favorite IDE or your blog authoring tool. (I am leery of random plugins and installing
them into the software that I use to feed my family.) To including code in your blog
post, copy your code from Visual Studio, Notepad, Flash, Firebug, or any tool that
displays text, and paste it in to your post. As of v1.5.1, Google Syntax Highlighter
supports C, C++, C#, CSS, Delphi, HTML, Java, JavaScript, PHP, Pascal, Python, Ruby,
SQL, VB, VB.NET, XML, XSLT, and all of this is just what comes out of the box.
&lt;/p&gt;
&lt;h3&gt;Setting Up Syntax Highlighter
&lt;/h3&gt;
&lt;p&gt;
To get Syntax Highlighter running on your blog, &lt;a href="http://code.google.com/p/syntaxhighlighter/downloads/list"&gt;download&lt;/a&gt; the
latest version of the RAR archive and extract the code. The archive contains a parent
folder, &lt;em&gt;dp.SyntaxHighlighter&lt;/em&gt;, with three child folders:
&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;dp.SyntaxHighlighter
  \Scripts         //Production-ready (Compressed) scripts
  \Styles          //CSS
  \Uncompressed    //Human-readable (Uncompressed/Debug) scripts&lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
Once the archive is extracted, upload &lt;em&gt;dp.SyntaxHighlighter&lt;/em&gt; to your blog.
Feel free to rename the folder if you like, though I did not. It is not necessary
to upload the &lt;em&gt;Uncompressed&lt;/em&gt; folder and its files; they are best used for debugging
or for viewing the code, as the files in the &lt;em&gt;Scripts&lt;/em&gt; folder have been compressed
to reduce bandwidth by having most of their whitespace removed.
&lt;/p&gt;
&lt;p&gt;
After you have uploaded the files, you will need to add script and style references
to your site's HTML. This is code is not for your posts, but rather for your blog
template. In DasBlog, I place this code in the &amp;lt;HEAD&amp;gt; block of my &lt;em&gt;homeTemplate.blogtemplate&lt;/em&gt; file.
Remember to change the file paths to match the path to where you uploaded the code.
&lt;/p&gt;
&lt;pre class="html:nocontrols:nogutter" name="code"&gt;&amp;lt;link type="text/css" rel="stylesheet"
  href="dp.SyntaxHighlighter/Styles/SyntaxHighlighter.css"&amp;gt;&amp;lt;/link&amp;gt;
&amp;lt;script language="javascript" src="dp.SyntaxHighlighter/Scripts/shCore.js"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script language="javascript" src="dp.SyntaxHighlighter/Scripts/shBrushCSharp.js"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script language="javascript" src="dp.SyntaxHighlighter/Scripts/shBrushXml.js"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script language="javascript"&amp;gt;
window.onload = function () {
  dp.SyntaxHighlighter.ClipboardSwf = 'dp.SyntaxHighlighter/Scripts/clipboard.swf';
  dp.SyntaxHighlighter.HighlightAll('code');
}
&amp;lt;/script&amp;gt;&lt;/pre&gt;
&lt;p&gt;
To make the tool most efficient, including minimizing the code download by the client
browser, highlighting is only enabled for the languages that you specify. The highlighting
rules for each language is available through a file referred to as a Brush. The code
sample above enables only C# and XML/HTML by including the core file, &lt;em&gt;shCore.js&lt;/em&gt;,
the C# brush, &lt;em&gt;shBrushCSharp.js&lt;/em&gt; and the XML/HTML brush, &lt;em&gt;shBrushXml.js&lt;/em&gt;.
A unique brush file is available for each of the supported languages, and only the
core file is required. These brushes are located in your &lt;em&gt;Scripts&lt;/em&gt; directory
(the human-readable version is in the &lt;em&gt;Uncompressed&lt;/em&gt; folder). Include only
the brushes that you like; if you forgot a language brush, the code will still display
on your page, but as unformatted text.
&lt;/p&gt;
&lt;pre&gt;&amp;lt;!-- Unformatted HTML Code / No Brush --&amp;gt;
&amp;lt;p id="greeting"&amp;gt;Hi, mom &amp;amp; dad!&amp;lt;/p&amp;gt;&lt;/pre&gt;&lt;pre class="html:nogutter:nocontrols" name="code"&gt;&amp;lt;!-- Formatted HTML Code --&amp;gt;
&amp;lt;p id="greeting"&amp;gt;Hi, mom &amp;amp; dad!&amp;lt;/p&amp;gt;&lt;/pre&gt;
&lt;h3&gt;Making Syntax Highlighter Go
&lt;/h3&gt;
&lt;p&gt;
Now that the application is deployed to the site, how does it get applied to a post?
Paste the code into the HTML view of your post, inside of a &amp;lt;PRE&amp;gt; tag. Create
a &lt;em&gt;name&lt;/em&gt; attribute on your tag with a value of &lt;em&gt;code&lt;/em&gt;, and a &lt;em&gt;class&lt;/em&gt; attribute
set to the language and options you are using.
&lt;/p&gt;
&lt;pre class="html:nocontrols:nogutter" name="code"&gt;&amp;lt;pre name="code" class="c-sharp"&amp;gt;
  public void HelloWorld()
  {
    Console.WriteLine("Hello, World!");
  }
&amp;lt;/pre&amp;gt;&lt;/pre&gt;
&lt;p&gt;
One catch is the code must be first made HTML-safe. All angle-brackets, &lt;em&gt;&amp;lt;tag&amp;gt;&lt;/em&gt;,
must be converted to their HTML equivalent, &lt;em&gt;&amp;amp;lt;tag&amp;amp;gt;&lt;/em&gt;, as well
as ampersands, &lt;em&gt;&amp;amp;&lt;/em&gt; to &lt;em&gt;&amp;amp;amp;&lt;/em&gt;. I also find it helpful if your
code-indentation uses two-spaces, rather than tabs.
&lt;/p&gt;
&lt;pre class="html:nocontrols" name="code"&gt;&amp;lt;!-- Pre-converted code --&amp;gt;
&amp;lt;p&amp;gt;Hi, mom &amp;amp; dad!&amp;lt;/p&amp;gt;&lt;/pre&gt;&lt;pre class="html:nocontrols" name="code"&gt;&amp;lt;!-- Converted code --&amp;gt;
&amp;lt;pre name="code" class="html"&amp;gt;
  &amp;amp;lt;p&amp;amp;gt;Hi, mom &amp;amp;amp; dad!&amp;amp;lt;/p&amp;amp;gt;
&amp;lt;/pre&amp;gt;&lt;/pre&gt;
&lt;p&gt;
The &lt;em&gt;class&lt;/em&gt; attribute is made up of both language and option aliases. These
aliases consist of one language followed by your desired options, all in a colon delimited
list.
&lt;/p&gt;
&lt;p&gt;
class="language[:option[:option[:option]]]"
&lt;/p&gt;
&lt;p&gt;
The value of language is any of Syntax Highlighter's defined language aliases, such
as &lt;em&gt;c#&lt;/em&gt;, &lt;em&gt;csharp&lt;/em&gt;, or &lt;em&gt;c-sharp&lt;/em&gt; for C#, or &lt;em&gt;rb&lt;/em&gt;, &lt;em&gt;ruby&lt;/em&gt;, &lt;em&gt;rails&lt;/em&gt;,
or &lt;em&gt;ror&lt;/em&gt; for Ruby. See: &lt;a href="http://code.google.com/p/syntaxhighlighter/wiki/Languages"&gt;full
list&lt;/a&gt; of available languages.
&lt;/p&gt;
&lt;p&gt;
Options allow for such things as turning off the plain text / copy / about controls
(&lt;em&gt;nocontrols&lt;/em&gt;), turning off the line number gutter (&lt;em&gt;nogutter&lt;/em&gt;), or
specifying the number of the first line (&lt;em&gt;firstline[n]&lt;/em&gt;). A JavaScript code
block with no controls header, and starting the line numbering at 34 would have a &lt;em&gt;class&lt;/em&gt; attribute
value of &lt;em&gt;class="js:nocontrols:linenumber[34]"&lt;/em&gt;. See: &lt;a href="http://code.google.com/p/syntaxhighlighter/wiki/Configuration"&gt;full
list&lt;/a&gt; of available options.
&lt;/p&gt;
&lt;h3&gt;Extending Syntax Highlighter
&lt;/h3&gt;
&lt;p&gt;
Because Google Syntax Highlighter is entirely in JavaScript, you have access to all
of the code. Edit it however you like to suit your needs. Additionally, brushes are
very easy to create, and include little more than a list of a highlighted language's
keywords in a string and an array of language aliases. Creating a brush for ActionScript
or QBasic would not take much time. Language brushes exist in the wild for &lt;a href="http://nevstokes.com/includes/syntax/scripts/shBrushPerl.js"&gt;Perl&lt;/a&gt;, &lt;a href="http://pcnorb.blogspot.com/2008/10/shbrushbatch-for-google.html"&gt;DOS
Batch&lt;/a&gt;, and &lt;a href="http://blog.tech-cats.com/2007/10/syntax-highlighting-for-coldfusion.html"&gt;ColdFusion&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
In a future post I plan on discussing Brush Creation in depth through creating a brush
for ActionScript.
&lt;/p&gt;
&lt;h3&gt;Comparing Syntax Highlighter to Others
&lt;/h3&gt;
&lt;p&gt;
I am a fan of this tool, though that should be obvious considering it is what I use
on this blog. I like how readable the code is, how extendable it is, and how easy
it is to use. I don't like its compatibility--or lack thereof--with RSS; since all
of the work is done in JavaScript, and RSS doesn't do JavaScript, there is no syntax
highlighting, numbers, or options within a feed, though the code formatting is still
maintained. Other tools, like the &lt;em&gt;&lt;a href="http://www.jtleigh.com/people/colin/software/CopySourceAsHtml/"&gt;CopySourceAsHtml&lt;/a&gt;&lt;/em&gt; plugin
for Visual Studio or &lt;em&gt;&lt;a href="http://lvildosola.blogspot.com/2007/02/code-snippet-plugin-for-windows-live.html"&gt;Insert
Code Snippet&lt;/a&gt;&lt;/em&gt; for Windows Live Writer convert your code into formatted HTML,
where all of the syntax highlighting is applied through HTML attributes and embedded
CSS. Their methods are much easier than Syntax Highlighter, since there are no stylesheets
or JavaScript files to include in your HTML, and you don't have to worry about making
your code HTML-safe. Also, their method works in RSS feeds. However, there isn't the
same level of control. Through Syntax Highlighter's extendibility, I can theme my
code views, such as if I wanted them to look like my personal Visual Studio theme.
Through Syntax Highlighter, I can also make changes at a later time, and those changes
will immediately reflected in all past posts, whereas making modifications to the
HTML/embedded CSS pattern is much more difficult.
&lt;/p&gt;
&lt;h3&gt;Final Thoughts
&lt;/h3&gt;
&lt;p&gt;
I like CopySourceAsHtml in Visual Studio. I used it for years on this blog. But I
code in more languages than VB.Net or C#, and the plugin isn't available within the
Flash or LoadRunner IDE. I was also frustrated with pasting my code in, only to find
that it was too wide for my blog theme's margins, and would have to go back to Visual
Studio, change my line endings, and repeat the process. I'm sticking with Google Syntax
Highlighter. It works for all of my languages (as soon as I finish writing my ActionScript
brush), and when my line endings are too long, I simply change my HTML. And in my
HTML, my code still looks like code, rather than a mess of embedded style. I have
to sacrifice RSS formatting, but as a presentation developer that is very particular
about his HTML, I am glad for the customization and control.
&lt;/p&gt;
&lt;div class="wlWriterSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:5e03f5f4-120c-4ce0-96ea-32867691f7e7" style="padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Technorati
Tags: &lt;a href="http://technorati.com/tags/SyntaxHighlighter" rel="tag"&gt;SyntaxHighlighter&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Syntax%20Highlighter" rel="tag"&gt;Syntax
Highlighter&lt;/a&gt;,&lt;a href="http://technorati.com/tags/Google%20Code" rel="tag"&gt;Google
Code&lt;/a&gt;
&lt;/div&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=417c2df3-d32c-436c-8c5c-46e1fe4b2808" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,417c2df3-d32c-436c-8c5c-46e1fe4b2808.aspx</comments>
      <category>Blogging</category>
      <category>JavaScript</category>
      <category>Programming</category>
      <category>Reviews</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=a4b7be94-d409-4e74-abfa-a39cc4cdff77</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,a4b7be94-d409-4e74-abfa-a39cc4cdff77.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,a4b7be94-d409-4e74-abfa-a39cc4cdff77.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=a4b7be94-d409-4e74-abfa-a39cc4cdff77</wfw:commentRss>
      <slash:comments>5</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Scott Hanselman posted an entry yesterday about <a href="http://www.hanselman.com/blog/ManagingMultipleConfigurationFileEnvironmentsWithPreBuildEvents.aspx">Managing
Multiple Configuration File Environments with Pre-build Events</a>. His design uses
pre-build events in Visual Studio to copy specific configuration files to the default
file name, such as having "web.config.debug" and a "web.config.release" configuration
files and the pre-build copying the appropriate file to "web.config" based on which
build configuration you are in. This is a great idea, but large web.config files can
get tedious to maintain, and there is a lot of repeated code. Even using include files
as Scott suggests would help, but major blocks, such as Application Settings, may
have to be repeated even though only the values change. This exposes human error,
since an app setting may be forgotten or misspelled in one of your web.config versions.
</p>
        <p>
At Latitude, we manage this problem through NAnt. One of our former developers, Erik
Nelsestuen–brilliant guy–authored the original version of what we call "ConfigMerge".
Essentially, our projects have no web.config under source control. Instead, we have
a web.format.config. The format config is nearly identical to the web.config, except
all of the application settings and connection strings have been replaced with NAnt
property strings. Rather than have a seperate web.config for each environment and
build configuration, we simply have NAnt property files. Our build events (as well
as our automated build scripts) pass the location of the format file and the location
of the property file and the output is a valid web.config, with the NAnt property
strings replaced with their values from the environment property file.
</p>
        <p>
It's simple. It only takes one NAnt COPY command.
</p>
        <p>
          <strong>default.build</strong>
        </p>
        <pre name="code" class="xml">&lt;project default="configMerge"&gt;
  &lt;property name="destinationfile"
    value="web.config" overwrite="false" /&gt;
  &lt;property name="propertyfile"
    value="invalid.file" overwrite="false" /&gt;
  &lt;property name="sourcefile"
    value="web.format.config" overwrite="false" /&gt;
 
  &lt;include buildfile="${propertyfile}" failonerror="false"
    unless="${string::contains(propertyfile, 'invalid.file')}" /&gt;
 
  &lt;target name="configMerge"&gt;
    &lt;copy file="${sourcefile}"
        tofile="${destinationfile}" overwrite="true"&gt;
      &lt;filterchain&gt;
        &lt;expandproperties /&gt;
      &lt;/filterchain&gt;
    &lt;/copy&gt;
  &lt;/target&gt;
&lt;/project&gt;</pre>
        <p>
For an example, lets start with a partial web.config, just so you get the idea. I've
stripped out most of the goo from a basic web.config, and am left with this:
</p>
        <p>
          <strong>web.confg</strong>
        </p>
        <pre name="code" class="xml:nocontrols">&lt;configuration&gt;
  &lt;system.web&gt;
    &lt;compilation defaultLanguage="c#" debug="true" /&gt;
    &lt;customErrors mode="RemoteOnly" /&gt; 
  &lt;/system.web&gt;
&lt;/configuration&gt;</pre>
        <p>
In a debug environment, we may want to enable debugging and turn off custom errors,
but in release mode disable debugging and turn on RemoteOnly custom errors. The first
thing we will need to do is create a format file, and then convert the values that
we want to make dynamic into NAnt property strings.
</p>
        <p>
          <strong>web.format.config</strong>
        </p>
        <pre name="code" class="xml:nocontrols">&lt;configuration&gt;
  &lt;system.web&gt;
    &lt;compilation defaultLanguage="c#" debug="${debugValue}" /&gt;
    &lt;customErrors mode="${customErrorsValue}" /&gt; 
  &lt;/system.web&gt;
&lt;/configuration&gt;</pre>
        <p>
Next, we need to make NAnt property files, and add in values for each NAnt property
that we've created. These property files will include the values to be injected into
the web.config output. For the sake of simplicity, I always give my property files
a '.property' file extension, but nant will accept any file name; you can use '.foo'
if you like.<!--]--></p>
        <p>
          <strong>debugBuild.property</strong>
        </p>
        <pre name="code" class="xml:nocontrols">&lt;project&gt;
   &lt;property name="debugValue" value="true" /&gt;
   &lt;property name="configMergeValue" value="Off" /&gt;
&lt;/project&gt;</pre>
        <p>
          <strong>releaseBuild.property</strong>
        </p>
        <pre name="code" class="xml:nocontrols">&lt;project&gt;
   &lt;property name="debugValue" value="false" /&gt;
   &lt;property name="configMergeValue" value="RemoteOnly" /&gt;
&lt;/project&gt;</pre>
        <p>
Finally, we just execute the NAnt script, passing in the appropriate source, destination
and property file locations to produce our environment-specific web.config.
</p>
        <p>
          <strong>nant configMerge -D:sourcefile=web.format.config -D:propertyfile=debugBuild.property
-D:destinationfile=web.config</strong>
          <br />
          <em>web.config output</em>
        </p>
        <pre name="code" class="xml:nocontrols">&lt;configuration&gt;
  &lt;system.web&gt;
    &lt;compilation defaultLanguage="c#" debug="true" /&gt;
    &lt;customErrors mode="Off" /&gt; 
  &lt;/system.web&gt;
&lt;/configuration&gt;</pre>
        <p>
And that's all there is to it. This is extendable further using the powers of NAnt.
Using NAnt includes, you can put all of your base or default values in one property
file that's referenced in your debugBuild.property or releaseBuild.property, further
minimizing code. You can use Scott's pre-build event idea to have each build configuration
have its own NAnt command to make mode-specific configuration files.
</p>
        <p>
Feel free to use the above NAnt script however you like; but, as always YMMV. Use
it at your own risk.
</p>
        <p>
Enjoy.
</p>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=a4b7be94-d409-4e74-abfa-a39cc4cdff77" />
      </body>
      <title>Managing Multiple Environment Configurations through NAnt</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,a4b7be94-d409-4e74-abfa-a39cc4cdff77.aspx</guid>
      <link>http://www.cptloadtest.com/2007/09/22/Managing-Multiple-Environment-Configurations-Through-NAnt.aspx</link>
      <pubDate>Sat, 22 Sep 2007 02:00:26 GMT</pubDate>
      <description>&lt;p&gt;
Scott Hanselman posted an entry yesterday about &lt;a href="http://www.hanselman.com/blog/ManagingMultipleConfigurationFileEnvironmentsWithPreBuildEvents.aspx"&gt;Managing
Multiple Configuration File Environments with Pre-build Events&lt;/a&gt;. His design uses
pre-build events in Visual Studio to copy specific configuration files to the default
file name, such as having "web.config.debug" and a "web.config.release" configuration
files and the pre-build copying the appropriate file to "web.config" based on which
build configuration you are in. This is a great idea, but large web.config files can
get tedious to maintain, and there is a lot of repeated code. Even using include files
as Scott suggests would help, but major blocks, such as Application Settings, may
have to be repeated even though only the values change. This exposes human error,
since an app setting may be forgotten or misspelled in one of your web.config versions.
&lt;/p&gt;
&lt;p&gt;
At Latitude, we manage this problem through NAnt. One of our former developers, Erik
Nelsestuen–brilliant guy–authored the original version of what we call "ConfigMerge".
Essentially, our projects have no web.config under source control. Instead, we have
a web.format.config. The format config is nearly identical to the web.config, except
all of the application settings and connection strings have been replaced with NAnt
property strings. Rather than have a seperate web.config for each environment and
build configuration, we simply have NAnt property files. Our build events (as well
as our automated build scripts) pass the location of the format file and the location
of the property file and the output is a valid web.config, with the NAnt property
strings replaced with their values from the environment property file.
&lt;/p&gt;
&lt;p&gt;
It's simple. It only takes one NAnt COPY command.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;default.build&lt;/strong&gt;
&lt;/p&gt;
&lt;pre name="code" class="xml"&gt;&amp;lt;project default="configMerge"&amp;gt;
  &amp;lt;property name="destinationfile"
    value="web.config" overwrite="false" /&amp;gt;
  &amp;lt;property name="propertyfile"
    value="invalid.file" overwrite="false" /&amp;gt;
  &amp;lt;property name="sourcefile"
    value="web.format.config" overwrite="false" /&amp;gt;
 
  &amp;lt;include buildfile="${propertyfile}" failonerror="false"
    unless="${string::contains(propertyfile, 'invalid.file')}" /&amp;gt;
 
  &amp;lt;target name="configMerge"&amp;gt;
    &amp;lt;copy file="${sourcefile}"
        tofile="${destinationfile}" overwrite="true"&amp;gt;
      &amp;lt;filterchain&amp;gt;
        &amp;lt;expandproperties /&amp;gt;
      &amp;lt;/filterchain&amp;gt;
    &amp;lt;/copy&amp;gt;
  &amp;lt;/target&amp;gt;
&amp;lt;/project&amp;gt;&lt;/pre&gt;
&lt;p&gt;
For an example, lets start with a partial web.config, just so you get the idea. I've
stripped out most of the goo from a basic web.config, and am left with this:
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;web.confg&lt;/strong&gt;
&lt;/p&gt;
&lt;pre name="code" class="xml:nocontrols"&gt;&amp;lt;configuration&amp;gt;
  &amp;lt;system.web&amp;gt;
    &amp;lt;compilation defaultLanguage="c#" debug="true" /&amp;gt;
    &amp;lt;customErrors mode="RemoteOnly" /&amp;gt; 
  &amp;lt;/system.web&amp;gt;
&amp;lt;/configuration&amp;gt;&lt;/pre&gt;
&lt;p&gt;
In a debug environment, we may want to enable debugging and turn off custom errors,
but in release mode disable debugging and turn on RemoteOnly custom errors. The first
thing we will need to do is create a format file, and then convert the values that
we want to make dynamic into NAnt property strings.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;web.format.config&lt;/strong&gt;
&lt;/p&gt;
&lt;pre name="code" class="xml:nocontrols"&gt;&amp;lt;configuration&amp;gt;
  &amp;lt;system.web&amp;gt;
    &amp;lt;compilation defaultLanguage="c#" debug="${debugValue}" /&amp;gt;
    &amp;lt;customErrors mode="${customErrorsValue}" /&amp;gt; 
  &amp;lt;/system.web&amp;gt;
&amp;lt;/configuration&amp;gt;&lt;/pre&gt;
&lt;p&gt;
Next, we need to make NAnt property files, and add in values for each NAnt property
that we've created. These property files will include the values to be injected into
the web.config output. For the sake of simplicity, I always give my property files
a '.property' file extension, but nant will accept any file name; you can use '.foo'
if you like.&lt;!--]--&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;debugBuild.property&lt;/strong&gt;
&lt;/p&gt;
&lt;pre name="code" class="xml:nocontrols"&gt;&amp;lt;project&amp;gt;
   &amp;lt;property name="debugValue" value="true" /&amp;gt;
   &amp;lt;property name="configMergeValue" value="Off" /&amp;gt;
&amp;lt;/project&amp;gt;&lt;/pre&gt;
&lt;p&gt;
&lt;strong&gt;releaseBuild.property&lt;/strong&gt;
&lt;/p&gt;
&lt;pre name="code" class="xml:nocontrols"&gt;&amp;lt;project&amp;gt;
   &amp;lt;property name="debugValue" value="false" /&amp;gt;
   &amp;lt;property name="configMergeValue" value="RemoteOnly" /&amp;gt;
&amp;lt;/project&amp;gt;&lt;/pre&gt;
&lt;p&gt;
Finally, we just execute the NAnt script, passing in the appropriate source, destination
and property file locations to produce our environment-specific web.config.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;nant configMerge -D:sourcefile=web.format.config -D:propertyfile=debugBuild.property
-D:destinationfile=web.config&lt;/strong&gt;
&lt;br&gt;
&lt;em&gt;web.config output&lt;/em&gt;
&lt;/p&gt;
&lt;pre name="code" class="xml:nocontrols"&gt;&amp;lt;configuration&amp;gt;
  &amp;lt;system.web&amp;gt;
    &amp;lt;compilation defaultLanguage="c#" debug="true" /&amp;gt;
    &amp;lt;customErrors mode="Off" /&amp;gt; 
  &amp;lt;/system.web&amp;gt;
&amp;lt;/configuration&amp;gt;&lt;/pre&gt;
&lt;p&gt;
And that's all there is to it. This is extendable further using the powers of NAnt.
Using NAnt includes, you can put all of your base or default values in one property
file that's referenced in your debugBuild.property or releaseBuild.property, further
minimizing code. You can use Scott's pre-build event idea to have each build configuration
have its own NAnt command to make mode-specific configuration files.
&lt;/p&gt;
&lt;p&gt;
Feel free to use the above NAnt script however you like; but, as always YMMV. Use
it at your own risk.
&lt;/p&gt;
&lt;p&gt;
Enjoy.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=a4b7be94-d409-4e74-abfa-a39cc4cdff77" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,a4b7be94-d409-4e74-abfa-a39cc4cdff77.aspx</comments>
      <category>NAnt</category>
      <category>Task Automation</category>
      <category>Tools</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=cb1c56a9-80c4-422a-9ce1-3edf3fe40c8a</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,cb1c56a9-80c4-422a-9ce1-3edf3fe40c8a.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,cb1c56a9-80c4-422a-9ce1-3edf3fe40c8a.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=cb1c56a9-80c4-422a-9ce1-3edf3fe40c8a</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
CruiseControl.Net 1.3 was <a href="http://confluence.public.thoughtworks.org/display/CCNET/2007/06/21/CruiseControl.NET+1.3+Released">released</a> this
morning. To me, most important was the new Build Queue functionality, stopping multiple
projects from building at the same time. If ProjectB depends on ProjectA, and they
both get code changes committed at the same time, they will fail from contention.
Either ProjectA will fail because it can’t delete its old assemblies (because ProjectB
has a lock on them) or ProjectB will fail because it can’t find the ProjectA assemblies
(because ProjectA deleted them in its rebuild).
</p>
        <p>
No more.
</p>
        <p>
I’m so excited that I am already upgrading our servers!
</p>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=cb1c56a9-80c4-422a-9ce1-3edf3fe40c8a" />
      </body>
      <title>CruiseControl.Net 1.3 Released</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,cb1c56a9-80c4-422a-9ce1-3edf3fe40c8a.aspx</guid>
      <link>http://www.cptloadtest.com/2007/06/23/CruiseControlNet-13-Released.aspx</link>
      <pubDate>Sat, 23 Jun 2007 02:19:30 GMT</pubDate>
      <description>&lt;p&gt;
CruiseControl.Net 1.3 was &lt;a href="http://confluence.public.thoughtworks.org/display/CCNET/2007/06/21/CruiseControl.NET+1.3+Released"&gt;released&lt;/a&gt; this
morning. To me, most important was the new Build Queue functionality, stopping multiple
projects from building at the same time. If ProjectB depends on ProjectA, and they
both get code changes committed at the same time, they will fail from contention.
Either ProjectA will fail because it can’t delete its old assemblies (because ProjectB
has a lock on them) or ProjectB will fail because it can’t find the ProjectA assemblies
(because ProjectA deleted them in its rebuild).
&lt;/p&gt;
&lt;p&gt;
No more.
&lt;/p&gt;
&lt;p&gt;
I’m so excited that I am already upgrading our servers!
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=cb1c56a9-80c4-422a-9ce1-3edf3fe40c8a" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,cb1c56a9-80c4-422a-9ce1-3edf3fe40c8a.aspx</comments>
      <category>Continuous Integration</category>
      <category>Tools</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=01c0052a-b284-4178-b7df-672c09862d39</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,01c0052a-b284-4178-b7df-672c09862d39.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,01c0052a-b284-4178-b7df-672c09862d39.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=01c0052a-b284-4178-b7df-672c09862d39</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
The day is here: Internet Explorer 7 released this morning, though it is only available
to users running Windows XP SP2 or Windows Server 2003. Though it does not yet appear
on the list of available updates through Windows Update, you can <a href="http://www.microsoft.com/windows/ie/downloads/default.mspx">download</a> it
from Microsoft.com. [ News: <a href="http://news.zdnet.com/2100-9588_22-6127277.html">ZDNet</a> | <a href="http://reviews.cnet.com/Internet_Explorer_7/4505-3514_7-32111537.html?tag=viddet">CNet</a> ]
In a <a href="http://reviews.cnet.com/Internet_Explorer_7/4505-3514_7-32111537.html?tag=viddet">CNet
review</a>, the reviewing editor notes how the browser is still not compliant with
standards set by W3C and recommends switching to Firefox.
</p>
        <blockquote>
          <p>
“IE 7 was Microsoft’s one chance to leapfrog ahead of the competition, but the company
has only barely caught sight of the current front-runners. For more features and greater
security, switch to Mozilla Firefox.” ~ CNet [ <a href="http://reviews.cnet.com/Internet_Explorer_7/4505-3514_7-32111537.html?tag=viddet">article</a> ]
</p>
        </blockquote>
        <p>
There is already a <a href="http://downloads.yahoo.com/internetexplorer/index.php">version
branded by Yahoo!</a> that includes the Yahoo! toolbar, links to Yahoo’s tools (like
Yahoo! Mail), and the default homepage set to Yahoo. Of course, Yahoo! is catching
some flak, since it released its “optimized” version prior to Microsoft’s own official
release. [ <a href="http://news.zdnet.com/2100-9588_22-6127211.html">ZDNet</a> ]
</p>
        <p>
Mozilla plans to release Firefox 2.0 in the coming weeks. You can download the current
beta, Firefox 2.0 RC3, or the current public release, Firefox 1.5.0.7, from Mozilla.com.
[ v2.0 RC3: <a href="http://www.mozilla.org/projects/bonecho/all-rc.html">download</a> | <a href="http://www.mozilla.com/en-US/firefox/2.0/releasenotes/#FAQ">release
notes</a>. v1.5: <a href="http://www.mozilla.org/download.html.">download</a> | <a href="http://www.mozilla.com/firefox/releases/1.5.0.7.html">release
notes</a> ]
</p>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=01c0052a-b284-4178-b7df-672c09862d39" />
      </body>
      <title>IE7 Released</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,01c0052a-b284-4178-b7df-672c09862d39.aspx</guid>
      <link>http://www.cptloadtest.com/2006/10/20/IE7-Released.aspx</link>
      <pubDate>Fri, 20 Oct 2006 02:39:24 GMT</pubDate>
      <description>&lt;p&gt;
The day is here: Internet Explorer 7 released this morning, though it is only available
to users running Windows XP SP2 or Windows Server 2003. Though it does not yet appear
on the list of available updates through Windows Update, you can &lt;a href="http://www.microsoft.com/windows/ie/downloads/default.mspx"&gt;download&lt;/a&gt; it
from Microsoft.com. [ News: &lt;a href="http://news.zdnet.com/2100-9588_22-6127277.html"&gt;ZDNet&lt;/a&gt; | &lt;a href="http://reviews.cnet.com/Internet_Explorer_7/4505-3514_7-32111537.html?tag=viddet"&gt;CNet&lt;/a&gt; ]
In a &lt;a href="http://reviews.cnet.com/Internet_Explorer_7/4505-3514_7-32111537.html?tag=viddet"&gt;CNet
review&lt;/a&gt;, the reviewing editor notes how the browser is still not compliant with
standards set by W3C and recommends switching to Firefox.
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;
“IE 7 was Microsoft’s one chance to leapfrog ahead of the competition, but the company
has only barely caught sight of the current front-runners. For more features and greater
security, switch to Mozilla Firefox.” ~ CNet [ &lt;a href="http://reviews.cnet.com/Internet_Explorer_7/4505-3514_7-32111537.html?tag=viddet"&gt;article&lt;/a&gt; ]
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
There is already a &lt;a href="http://downloads.yahoo.com/internetexplorer/index.php"&gt;version
branded by Yahoo!&lt;/a&gt; that includes the Yahoo! toolbar, links to Yahoo’s tools (like
Yahoo! Mail), and the default homepage set to Yahoo. Of course, Yahoo! is catching
some flak, since it released its “optimized” version prior to Microsoft’s own official
release. [ &lt;a href="http://news.zdnet.com/2100-9588_22-6127211.html"&gt;ZDNet&lt;/a&gt; ]
&lt;/p&gt;
&lt;p&gt;
Mozilla plans to release Firefox 2.0 in the coming weeks. You can download the current
beta, Firefox 2.0 RC3, or the current public release, Firefox 1.5.0.7, from Mozilla.com.
[ v2.0 RC3: &lt;a href="http://www.mozilla.org/projects/bonecho/all-rc.html"&gt;download&lt;/a&gt; | &lt;a href="http://www.mozilla.com/en-US/firefox/2.0/releasenotes/#FAQ"&gt;release
notes&lt;/a&gt;. v1.5: &lt;a href="http://www.mozilla.org/download.html."&gt;download&lt;/a&gt; | &lt;a href="http://www.mozilla.com/firefox/releases/1.5.0.7.html"&gt;release
notes&lt;/a&gt; ]
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=01c0052a-b284-4178-b7df-672c09862d39" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,01c0052a-b284-4178-b7df-672c09862d39.aspx</comments>
      <category>Tools</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=437e304b-0300-43eb-9903-e0728979a949</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,437e304b-0300-43eb-9903-e0728979a949.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,437e304b-0300-43eb-9903-e0728979a949.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=437e304b-0300-43eb-9903-e0728979a949</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Both NAnt and NAntContrib released version 0.85 on Sunday. The changes to NAnt from
0.85 rc4 only include a few bug fixes. NAntContrib has added the ability to specify
the encoding on SQL files. All-in-all, not much has changed since 0.85 rc4, but that
is a good thing, since it indicates the version is finally ready for release. The
first release candidate was made available nearly two years ago.
</p>
        <p>
Despite the minimal changes in the final package, consider upgrading just to get rid
of the ‘release candidate’ tag.
</p>
        <p>
NAnt v0.85 [ <a href="http://nant.sourceforge.net/">homepage</a> | <a href="http://sourceforge.net/project/showfiles.php?group_id=31650">download</a> | <a href="http://nant.sourceforge.net/release/0.85/releasenotes.html">release
notes</a> ]<br />
NAntContrib v0.85 [ <a href="http://nantcontrib.sourceforge.net/">homepage</a> | <a href="http://sourceforge.net/project/showfiles.php?group_id=54790">download</a> | <a href="http://nantcontrib.sourceforge.net/release/0.85/releasenotes.html">release
notes</a> ]
</p>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=437e304b-0300-43eb-9903-e0728979a949" />
      </body>
      <title>NAnt &amp; NantContrib 0.85 Released</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,437e304b-0300-43eb-9903-e0728979a949.aspx</guid>
      <link>http://www.cptloadtest.com/2006/10/18/NAnt-NantContrib-085-Released.aspx</link>
      <pubDate>Wed, 18 Oct 2006 02:42:02 GMT</pubDate>
      <description>&lt;p&gt;
Both NAnt and NAntContrib released version 0.85 on Sunday. The changes to NAnt from
0.85 rc4 only include a few bug fixes. NAntContrib has added the ability to specify
the encoding on SQL files. All-in-all, not much has changed since 0.85 rc4, but that
is a good thing, since it indicates the version is finally ready for release. The
first release candidate was made available nearly two years ago.
&lt;/p&gt;
&lt;p&gt;
Despite the minimal changes in the final package, consider upgrading just to get rid
of the ‘release candidate’ tag.
&lt;/p&gt;
&lt;p&gt;
NAnt v0.85 [ &lt;a href="http://nant.sourceforge.net/"&gt;homepage&lt;/a&gt; | &lt;a href="http://sourceforge.net/project/showfiles.php?group_id=31650"&gt;download&lt;/a&gt; | &lt;a href="http://nant.sourceforge.net/release/0.85/releasenotes.html"&gt;release
notes&lt;/a&gt; ]&lt;br&gt;
NAntContrib v0.85 [ &lt;a href="http://nantcontrib.sourceforge.net/"&gt;homepage&lt;/a&gt; | &lt;a href="http://sourceforge.net/project/showfiles.php?group_id=54790"&gt;download&lt;/a&gt; | &lt;a href="http://nantcontrib.sourceforge.net/release/0.85/releasenotes.html"&gt;release
notes&lt;/a&gt; ]
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=437e304b-0300-43eb-9903-e0728979a949" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,437e304b-0300-43eb-9903-e0728979a949.aspx</comments>
      <category>NAnt</category>
      <category>Task Automation</category>
      <category>Tools</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=b2373965-3820-4cfe-9faf-7b725eccf7a0</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,b2373965-3820-4cfe-9faf-7b725eccf7a0.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,b2373965-3820-4cfe-9faf-7b725eccf7a0.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=b2373965-3820-4cfe-9faf-7b725eccf7a0</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
For those that missed the <a href="http://confluence.public.thoughtworks.org/display/CCNET/2006/10/01/CruiseControl.NET+1.1+is+released.">announcement</a> last
week (like I did), the latest version of <a href="http://confluence.public.thoughtworks.org/display/CCNET/Welcome+to+CruiseControl.NET">CruiseControl.Net</a> has
been released. 
</p>
        <p>
I plan on checking it out this week, then possibly upgrading our Build environment
on Saturday. There are some modifications that I am really excited about:
</p>
        <ul>
          <li>
            <strong>Log4Net is used.</strong> (Default: Rolling file appender for logging server
output.) If the traditional Log4Net configuration block is included in the application
configuration file, I will probably change that to the ADONet appender, instead.</li>
          <li>
            <strong>Users can volunteer to fix a broken build.</strong> How sweet is that!?!</li>
          <li>
            <strong>&lt;prebuild /&gt; section allows custom tasks to run prior to the build.</strong> This
one is a big bonus; previously, if something went wrong with the build, often the
external log files (NUnit, FXCop) from the previous build would get included in the
current build’s report. Now the prebuild can give them the boot.</li>
          <li>
            <strong>Caching is used on WebDashboard.</strong> We have some huge log files and
some not-so-powerful build servers. Sometimes it takes the machine a while to process
the XSL. I am hoping that caching will help with that.</li>
          <li>
            <strong>WebDashboard can stop and start projects.</strong> I am very excited about
the ability to pause individual projects without having to modify the setup or stop
the entire service.</li>
        </ul>
        <p>
This seems like a nice package (<a href="http://confluence.public.thoughtworks.org/display/CCNET/CCNet+1.1+Final+Release+Notes">Release
Notes</a>). I am eager to pull it down and give it a go.
</p>
        <p>
One gotcha that everyone should be aware of: Old versions of the dashboard and CCTray
are incompatible with the new version of the service, so both will need to be replaced.
Give your development team a heads-up, so they know to replace their tray installation
as soon as the new server version is installed and online.
</p>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=b2373965-3820-4cfe-9faf-7b725eccf7a0" />
      </body>
      <title>CruiseControl.Net v1.1 Released Oct. 1</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,b2373965-3820-4cfe-9faf-7b725eccf7a0.aspx</guid>
      <link>http://www.cptloadtest.com/2006/10/10/CruiseControlNet-V11-Released-Oct-1.aspx</link>
      <pubDate>Tue, 10 Oct 2006 02:51:12 GMT</pubDate>
      <description>&lt;p&gt;
For those that missed the &lt;a href="http://confluence.public.thoughtworks.org/display/CCNET/2006/10/01/CruiseControl.NET+1.1+is+released."&gt;announcement&lt;/a&gt; last
week (like I did), the latest version of &lt;a href="http://confluence.public.thoughtworks.org/display/CCNET/Welcome+to+CruiseControl.NET"&gt;CruiseControl.Net&lt;/a&gt; has
been released. 
&lt;/p&gt;
&lt;p&gt;
I plan on checking it out this week, then possibly upgrading our Build environment
on Saturday. There are some modifications that I am really excited about:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Log4Net is used.&lt;/strong&gt; (Default: Rolling file appender for logging server
output.) If the traditional Log4Net configuration block is included in the application
configuration file, I will probably change that to the ADONet appender, instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Users can volunteer to fix a broken build.&lt;/strong&gt; How sweet is that!?!&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&amp;lt;prebuild /&amp;gt; section allows custom tasks to run prior to the build.&lt;/strong&gt; This
one is a big bonus; previously, if something went wrong with the build, often the
external log files (NUnit, FXCop) from the previous build would get included in the
current build’s report. Now the prebuild can give them the boot.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Caching is used on WebDashboard.&lt;/strong&gt; We have some huge log files and
some not-so-powerful build servers. Sometimes it takes the machine a while to process
the XSL. I am hoping that caching will help with that.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WebDashboard can stop and start projects.&lt;/strong&gt; I am very excited about
the ability to pause individual projects without having to modify the setup or stop
the entire service.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
This seems like a nice package (&lt;a href="http://confluence.public.thoughtworks.org/display/CCNET/CCNet+1.1+Final+Release+Notes"&gt;Release
Notes&lt;/a&gt;). I am eager to pull it down and give it a go.
&lt;/p&gt;
&lt;p&gt;
One gotcha that everyone should be aware of: Old versions of the dashboard and CCTray
are incompatible with the new version of the service, so both will need to be replaced.
Give your development team a heads-up, so they know to replace their tray installation
as soon as the new server version is installed and online.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=b2373965-3820-4cfe-9faf-7b725eccf7a0" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,b2373965-3820-4cfe-9faf-7b725eccf7a0.aspx</comments>
      <category>Continuous Integration</category>
      <category>Tools</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=c27ae8ec-ec78-494f-9d73-e51099d0680b</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,c27ae8ec-ec78-494f-9d73-e51099d0680b.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,c27ae8ec-ec78-494f-9d73-e51099d0680b.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=c27ae8ec-ec78-494f-9d73-e51099d0680b</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Microsoft has announced that the upgrade to Internet Explorer 7 will be “high priority”
in Windows Update, essentially forcing the upgrade on XP users everywhere (<a href="http://news.com.com/Microsoft+tags+IE+7+high+priority+update/2100-7350_3-6098500.html">news.com</a>).
Microsoft has released a <a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=4516A6F7-5D44-482B-9DBD-869B4A90159C&amp;displaylang=en">toolkit</a> to
disable automatic delivery of the browser upgrade, however this is a pro-active path;
if a user does nothing, they are <em>going</em> to get the new version. My poor grandma
(<a href="/2005/05/07/UsabilityWhatWouldGrandmaDo.aspx">Usability: What Would Grandma
Do?</a>), who has no idea about any of this, is getting the upgrade. If you have Windows
XP, and you have an internet connection, you pretty much are destined for this upgrade.
</p>
        <p>
Now, I don’t think that is entirely a bad thing. Far too many people just blindly
use this paperweight we call a computer. They don’t read manuals, they don’t educate
themselves on this thing, they just start pressing buttons. When they get a phishing
email about “Your bank account has been compromised. Please send me your account number
and password so that I can fix it,” they reply with their credentials. “Click here
and win an iPod” and they click. “Check out this email attachment of dancing babies”
and they get yet another virus. Because of this we have to monkey-proof computers,
and add far too many security checks on systems, and overall make developer-life a
little more painful. So, I think this is a good thing. Yeah, I drank the Microsoft
kool-aid, but I’m all for this automated upgrade to help make up for the swiss cheese
that is Internet Explorer 6. I’m going to continue using Firefox as my browser, anyway,
but if this makes my OS a little more secure…good!
</p>
        <p>
But what does this mean to us, the development / testing community? Test now. Test
often. In a few short months a few million people will unknowingly get IE7, and at
that time we will no longer have any excuse about whether or not our systems work.
Our stuff needs to work on IE7-Day. So <a href="http://www.microsoft.com/windows/ie/downloads/default.mspx">download</a> the
beta, and start testing your web apps to make sure everything still works. Microsoft
hasn’t been too browser-compliant in the past, and other than competition from Firefox
I don’t see a lot of reason that they would start, so there is good reason to suspect
things might break. Start testing now, or you will be scrambling in a few months when
your help desk lights up like a Christmas tree.
</p>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=c27ae8ec-ec78-494f-9d73-e51099d0680b" />
      </body>
      <title>Upgrade to IE7 Forced. Test early.</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,c27ae8ec-ec78-494f-9d73-e51099d0680b.aspx</guid>
      <link>http://www.cptloadtest.com/2006/07/28/Upgrade-To-IE7-Forced-Test-Early.aspx</link>
      <pubDate>Fri, 28 Jul 2006 12:30:43 GMT</pubDate>
      <description>&lt;p&gt;
Microsoft has announced that the upgrade to Internet Explorer 7 will be “high priority”
in Windows Update, essentially forcing the upgrade on XP users everywhere (&lt;a href="http://news.com.com/Microsoft+tags+IE+7+high+priority+update/2100-7350_3-6098500.html"&gt;news.com&lt;/a&gt;).
Microsoft has released a &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=4516A6F7-5D44-482B-9DBD-869B4A90159C&amp;amp;displaylang=en"&gt;toolkit&lt;/a&gt; to
disable automatic delivery of the browser upgrade, however this is a pro-active path;
if a user does nothing, they are &lt;em&gt;going&lt;/em&gt; to get the new version. My poor grandma
(&lt;a href="/2005/05/07/UsabilityWhatWouldGrandmaDo.aspx"&gt;Usability: What Would Grandma
Do?&lt;/a&gt;), who has no idea about any of this, is getting the upgrade. If you have Windows
XP, and you have an internet connection, you pretty much are destined for this upgrade.
&lt;/p&gt;
&lt;p&gt;
Now, I don’t think that is entirely a bad thing. Far too many people just blindly
use this paperweight we call a computer. They don’t read manuals, they don’t educate
themselves on this thing, they just start pressing buttons. When they get a phishing
email about “Your bank account has been compromised. Please send me your account number
and password so that I can fix it,” they reply with their credentials. “Click here
and win an iPod” and they click. “Check out this email attachment of dancing babies”
and they get yet another virus. Because of this we have to monkey-proof computers,
and add far too many security checks on systems, and overall make developer-life a
little more painful. So, I think this is a good thing. Yeah, I drank the Microsoft
kool-aid, but I’m all for this automated upgrade to help make up for the swiss cheese
that is Internet Explorer 6. I’m going to continue using Firefox as my browser, anyway,
but if this makes my OS a little more secure…good!
&lt;/p&gt;
&lt;p&gt;
But what does this mean to us, the development / testing community? Test now. Test
often. In a few short months a few million people will unknowingly get IE7, and at
that time we will no longer have any excuse about whether or not our systems work.
Our stuff needs to work on IE7-Day. So &lt;a href="http://www.microsoft.com/windows/ie/downloads/default.mspx"&gt;download&lt;/a&gt; the
beta, and start testing your web apps to make sure everything still works. Microsoft
hasn’t been too browser-compliant in the past, and other than competition from Firefox
I don’t see a lot of reason that they would start, so there is good reason to suspect
things might break. Start testing now, or you will be scrambling in a few months when
your help desk lights up like a Christmas tree.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=c27ae8ec-ec78-494f-9d73-e51099d0680b" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,c27ae8ec-ec78-494f-9d73-e51099d0680b.aspx</comments>
      <category>Tools</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=dd8510fd-a780-4c59-8f62-89d7d368221e</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,dd8510fd-a780-4c59-8f62-89d7d368221e.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,dd8510fd-a780-4c59-8f62-89d7d368221e.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=dd8510fd-a780-4c59-8f62-89d7d368221e</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I’m finally catching up on some of the blogs that I haven’t checked out in a while.
I came across an intriguing <a href="http://laputa.sharpdevelop.net/AnalyzingTheCodeInSharpDevelop.aspx">post
(on 04 March 2006)</a> by Daniel Grunwald on the #develop <a href="http://laputa.sharpdevelop.net/default.aspx">teamblog</a>.
It seems that he created a tool to analyze Subversion’s ‘Blame’ output to check the
‘Blame’ data from #develop repository and tell what percentage of the code was committed
by each contributor. (Incidentally, he has contributed 27% of the application, according
to the post’s screenshot.)
</p>
        <blockquote>
          <p>
My analyzer program gets the person who committed each line of code. Additionally,
it searches log messages for the term “patch by” and uses that name instead.
</p>
        </blockquote>
        <p>
He admits that the tool may need some love, and that some of his parameters are hard-coded,
but it may be worth a look. I’m curious to see the contribution stats on our LMS.
</p>
        <p>
Additionally, it is coded in Boo. I’ve been meaning to check out Boo, and getting
Daniel’s app working against our configuration might serve as a great introductory
Boo task for me.
</p>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=dd8510fd-a780-4c59-8f62-89d7d368221e" />
      </body>
      <title>On Subversion Blame Analyzer</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,dd8510fd-a780-4c59-8f62-89d7d368221e.aspx</guid>
      <link>http://www.cptloadtest.com/2006/06/03/On-Subversion-Blame-Analyzer.aspx</link>
      <pubDate>Sat, 03 Jun 2006 14:05:29 GMT</pubDate>
      <description>&lt;p&gt;
I’m finally catching up on some of the blogs that I haven’t checked out in a while.
I came across an intriguing &lt;a href="http://laputa.sharpdevelop.net/AnalyzingTheCodeInSharpDevelop.aspx"&gt;post
(on 04 March 2006)&lt;/a&gt; by Daniel Grunwald on the #develop &lt;a href="http://laputa.sharpdevelop.net/default.aspx"&gt;teamblog&lt;/a&gt;.
It seems that he created a tool to analyze Subversion’s ‘Blame’ output to check the
‘Blame’ data from #develop repository and tell what percentage of the code was committed
by each contributor. (Incidentally, he has contributed 27% of the application, according
to the post’s screenshot.)
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;
My analyzer program gets the person who committed each line of code. Additionally,
it searches log messages for the term “patch by” and uses that name instead.
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
He admits that the tool may need some love, and that some of his parameters are hard-coded,
but it may be worth a look. I’m curious to see the contribution stats on our LMS.
&lt;/p&gt;
&lt;p&gt;
Additionally, it is coded in Boo. I’ve been meaning to check out Boo, and getting
Daniel’s app working against our configuration might serve as a great introductory
Boo task for me.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=dd8510fd-a780-4c59-8f62-89d7d368221e" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,dd8510fd-a780-4c59-8f62-89d7d368221e.aspx</comments>
      <category>Reviews</category>
      <category>Tools</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=8cbaa378-4e19-4a01-b005-78de6bcf4121</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,8cbaa378-4e19-4a01-b005-78de6bcf4121.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,8cbaa378-4e19-4a01-b005-78de6bcf4121.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=8cbaa378-4e19-4a01-b005-78de6bcf4121</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Most of our Visual Studio solutions contain hundreds of files (classes) organized
neatly into dozens of folders (namespaces), but despite all of this organization the
vertical content size of the Solution Explorer can get quite large. Finding a particular
file when the majority of the tree is expanded is tedious and time-consuming, considering
it should be a simple effort of less than five seconds. Fortunately, all of this is
solved by the click of a button (assigned to handy macro).
</p>
        <p>
The most useful macro for Visual Studio that I have ever encountered (and in the running
for most useful VS tool, period) is the CollapseAll macro authored by one current
and one former colleague, Dennis Burton and Mike Shields. In a quick XP effort, Dennis
and Mike created a handy macro that recursively collapses the entire Solution Explorer
tree down to just the solution and its projects.
</p>
        <p>
With the tree collapsed, it is easy to find that desired file.
</p>
        <p>
The macro is functional in all versions of Visual Studio for the Microsoft.Net framework,
including Visual Studio 2003, Visual Studio 2005, and Visual Studio 2008.<br /></p>
        <p>
          <strong>CollapseAll Macro for Microsoft Visual Studio</strong>
          <br />
Dennis Burton &amp; Mike Shields | <em>Published with Permission</em></p>
        <pre name="code" class="vb">Imports System
Imports EnvDTE
Imports System.Diagnostics

Public Module CollapseAll
    Sub CollapseAll()
        ' Get the the Solution Explorer tree
        Dim UIHSolutionExplorer As UIHierarchy
        UIHSolutionExplorer = DTE.Windows.Item(Constants.vsext_wk_SProjectWindow).Object()
        ' Check if there is any open solution
        If (UIHSolutionExplorer.UIHierarchyItems.Count = 0) Then
            ' MsgBox("Nothing to collapse. You must have an open solution.")
            Return
        End If
        ' Get the top node (the name of the solution)
        Dim UIHSolutionRootNode As UIHierarchyItem
        UIHSolutionRootNode = UIHSolutionExplorer.UIHierarchyItems.Item(1)
        UIHSolutionExplorer = Nothing
        UIHSolutionRootNode.DTE.SuppressUI = True
        ' Collapse each project node
        Dim UIHItem As UIHierarchyItem
        For Each UIHItem In UIHSolutionRootNode.UIHierarchyItems
            'UIHItem.UIHierarchyItems.Expanded = False
            If UIHItem.UIHierarchyItems.Expanded Then
                Collapse(UIHItem)
            End If
        Next
        ' Select the solution node, or else when you click
        ' on the solution window
        ' scrollbar, it will synchronize the open document
        ' with the tree and pop
        ' out the corresponding node which is probably not what you want.
        UIHSolutionRootNode.Select(vsUISelectionType.vsUISelectionTypeSelect)
        UIHSolutionRootNode.DTE.SuppressUI = False
        UIHSolutionRootNode = Nothing
    End Sub

    Private Sub Collapse(ByVal item As UIHierarchyItem)
        For Each eitem As UIHierarchyItem In item.UIHierarchyItems
            If eitem.UIHierarchyItems.Expanded AndAlso eitem.UIHierarchyItems.Count &gt; 0 Then
                Collapse(eitem)
            End If
        Next
        item.UIHierarchyItems.Expanded = False
    End Sub
End Module
</pre>
        <p>
          <em>Based on code from <a href="http://www.codeproject.com/macro/collapseall.asp">Edwin
Evans</a></em>
        </p>
        <p>
Here, the macro is so popular that it is a part of our default developer’s build for
every new machine, and is conveniently assigned to a toolbar button. The default button
icon list contains an Up Arrow (in the Change Button Image menu when customizing the
toolbar) that seems quite appropriate. That little button has saved us all from a
lot of pain, five seconds at a time.
</p>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=8cbaa378-4e19-4a01-b005-78de6bcf4121" />
      </body>
      <title>Visual Studio Macro: Solution Explorer Collapse All</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,8cbaa378-4e19-4a01-b005-78de6bcf4121.aspx</guid>
      <link>http://www.cptloadtest.com/2006/05/31/Visual-Studio-Macro-Solution-Explorer-Collapse-All.aspx</link>
      <pubDate>Wed, 31 May 2006 14:19:55 GMT</pubDate>
      <description>&lt;p&gt;
Most of our Visual Studio solutions contain hundreds of files (classes) organized
neatly into dozens of folders (namespaces), but despite all of this organization the
vertical content size of the Solution Explorer can get quite large. Finding a particular
file when the majority of the tree is expanded is tedious and time-consuming, considering
it should be a simple effort of less than five seconds. Fortunately, all of this is
solved by the click of a button (assigned to handy macro).
&lt;/p&gt;
&lt;p&gt;
The most useful macro for Visual Studio that I have ever encountered (and in the running
for most useful VS tool, period) is the CollapseAll macro authored by one current
and one former colleague, Dennis Burton and Mike Shields. In a quick XP effort, Dennis
and Mike created a handy macro that recursively collapses the entire Solution Explorer
tree down to just the solution and its projects.
&lt;/p&gt;
&lt;p&gt;
With the tree collapsed, it is easy to find that desired file.
&lt;/p&gt;
&lt;p&gt;
The macro is functional in all versions of Visual Studio for the Microsoft.Net framework,
including Visual Studio 2003, Visual Studio 2005, and Visual Studio 2008.&lt;br&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;CollapseAll Macro for Microsoft Visual Studio&lt;/strong&gt;
&lt;br&gt;
Dennis Burton &amp;amp; Mike Shields | &lt;em&gt;Published with Permission&lt;/em&gt;
&lt;/p&gt;
&lt;pre name="code" class="vb"&gt;Imports System
Imports EnvDTE
Imports System.Diagnostics

Public Module CollapseAll
    Sub CollapseAll()
        ' Get the the Solution Explorer tree
        Dim UIHSolutionExplorer As UIHierarchy
        UIHSolutionExplorer = DTE.Windows.Item(Constants.vsext_wk_SProjectWindow).Object()
        ' Check if there is any open solution
        If (UIHSolutionExplorer.UIHierarchyItems.Count = 0) Then
            ' MsgBox("Nothing to collapse. You must have an open solution.")
            Return
        End If
        ' Get the top node (the name of the solution)
        Dim UIHSolutionRootNode As UIHierarchyItem
        UIHSolutionRootNode = UIHSolutionExplorer.UIHierarchyItems.Item(1)
        UIHSolutionExplorer = Nothing
        UIHSolutionRootNode.DTE.SuppressUI = True
        ' Collapse each project node
        Dim UIHItem As UIHierarchyItem
        For Each UIHItem In UIHSolutionRootNode.UIHierarchyItems
            'UIHItem.UIHierarchyItems.Expanded = False
            If UIHItem.UIHierarchyItems.Expanded Then
                Collapse(UIHItem)
            End If
        Next
        ' Select the solution node, or else when you click
        ' on the solution window
        ' scrollbar, it will synchronize the open document
        ' with the tree and pop
        ' out the corresponding node which is probably not what you want.
        UIHSolutionRootNode.Select(vsUISelectionType.vsUISelectionTypeSelect)
        UIHSolutionRootNode.DTE.SuppressUI = False
        UIHSolutionRootNode = Nothing
    End Sub

    Private Sub Collapse(ByVal item As UIHierarchyItem)
        For Each eitem As UIHierarchyItem In item.UIHierarchyItems
            If eitem.UIHierarchyItems.Expanded AndAlso eitem.UIHierarchyItems.Count &amp;gt; 0 Then
                Collapse(eitem)
            End If
        Next
        item.UIHierarchyItems.Expanded = False
    End Sub
End Module
&lt;/pre&gt;
&lt;p&gt;
&lt;em&gt;Based on code from &lt;a href="http://www.codeproject.com/macro/collapseall.asp"&gt;Edwin
Evans&lt;/a&gt;&lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;
Here, the macro is so popular that it is a part of our default developer’s build for
every new machine, and is conveniently assigned to a toolbar button. The default button
icon list contains an Up Arrow (in the Change Button Image menu when customizing the
toolbar) that seems quite appropriate. That little button has saved us all from a
lot of pain, five seconds at a time.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=8cbaa378-4e19-4a01-b005-78de6bcf4121" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,8cbaa378-4e19-4a01-b005-78de6bcf4121.aspx</comments>
      <category>Programming</category>
      <category>Tools</category>
      <category>Visual Studio</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=d0a8c19d-e021-4631-820c-f32e0992083a</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,d0a8c19d-e021-4631-820c-f32e0992083a.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,d0a8c19d-e021-4631-820c-f32e0992083a.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=d0a8c19d-e021-4631-820c-f32e0992083a</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
CruiseControl .Net 1.0 has been released. <a href="http://sourceforge.net/project/showfiles.php?group_id=71179&amp;package_id=83198&amp;release_id=370756">download</a> | <a href="http://confluence.public.thoughtworks.org/display/CCNET/CCNet+1.0+Final+Release+Notes">release
notes</a></p>
        <p>
This is a <em>must</em> upgrade for anyone running v0.9 or earlier. There are many
updates that I am excited about, most notably the overhaul to CCTray (the client-side
build monitoring tool that sits in your system tray). Our developers have had to use
Firefox’s CC.Net monitor extension to monitor multiple builds, simultaneously. No
more.
</p>
        <p>
We will be upgrading within the next week.
</p>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=d0a8c19d-e021-4631-820c-f32e0992083a" />
      </body>
      <title>CruiseControl.Net 1.0 released</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,d0a8c19d-e021-4631-820c-f32e0992083a.aspx</guid>
      <link>http://www.cptloadtest.com/2005/11/15/CruiseControlNet-10-Released.aspx</link>
      <pubDate>Tue, 15 Nov 2005 16:34:32 GMT</pubDate>
      <description>&lt;p&gt;
CruiseControl .Net 1.0 has been released. &lt;a href="http://sourceforge.net/project/showfiles.php?group_id=71179&amp;amp;package_id=83198&amp;amp;release_id=370756"&gt;download&lt;/a&gt; | &lt;a href="http://confluence.public.thoughtworks.org/display/CCNET/CCNet+1.0+Final+Release+Notes"&gt;release
notes&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
This is a &lt;em&gt;must&lt;/em&gt; upgrade for anyone running v0.9 or earlier. There are many
updates that I am excited about, most notably the overhaul to CCTray (the client-side
build monitoring tool that sits in your system tray). Our developers have had to use
Firefox’s CC.Net monitor extension to monitor multiple builds, simultaneously. No
more.
&lt;/p&gt;
&lt;p&gt;
We will be upgrading within the next week.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=d0a8c19d-e021-4631-820c-f32e0992083a" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,d0a8c19d-e021-4631-820c-f32e0992083a.aspx</comments>
      <category>Continuous Integration</category>
      <category>Tools</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=8a466c03-70e5-4d01-ab90-bc9052145e1c</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,8a466c03-70e5-4d01-ab90-bc9052145e1c.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,8a466c03-70e5-4d01-ab90-bc9052145e1c.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=8a466c03-70e5-4d01-ab90-bc9052145e1c</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
MSIExec error code 1605 has been a thorn in my side for quite a while. When an MSI
was command-line deployed by one user (manually deployed by me in the middle of the
day), it couldn’t be uninstalled by another (automation during the nightly) due to
the “Just Me” default. If I installed it through using the UI, and installed it for
use by “Everyone”, then the nightly would build just fine. I needed a way to run an
“Everyone” install from the command line, but Google wasn’t helping me out. Unfortunately,
Microsoft does not seem to have a lot of documentation on this functionality, either.
</p>
        <p>
It further frustrated me this morning when my nightlies were failing again, but only
on one server. Of course, I manually deployed the package to this same server to a
few days ago. I tried Google again, and this time hit pay dirt. Executing it with
ALLUSERS=2 in the command line makes it available for everyone. Apparently, it forces
an “Everyone” install for the UI, too.
</p>
        <p>
Finally I can pull the thorn out.
</p>
        <p>
MSIExec /i mypackage .msi … ALLUSERS=2
</p>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=8a466c03-70e5-4d01-ab90-bc9052145e1c" />
      </body>
      <title>MSIExec for Everyone, not Just Me</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,8a466c03-70e5-4d01-ab90-bc9052145e1c.aspx</guid>
      <link>http://www.cptloadtest.com/2005/11/05/MSIExec-For-Everyone-Not-Just-Me.aspx</link>
      <pubDate>Sat, 05 Nov 2005 16:06:26 GMT</pubDate>
      <description>&lt;p&gt;
MSIExec error code 1605 has been a thorn in my side for quite a while. When an MSI
was command-line deployed by one user (manually deployed by me in the middle of the
day), it couldn’t be uninstalled by another (automation during the nightly) due to
the “Just Me” default. If I installed it through using the UI, and installed it for
use by “Everyone”, then the nightly would build just fine. I needed a way to run an
“Everyone” install from the command line, but Google wasn’t helping me out. Unfortunately,
Microsoft does not seem to have a lot of documentation on this functionality, either.
&lt;/p&gt;
&lt;p&gt;
It further frustrated me this morning when my nightlies were failing again, but only
on one server. Of course, I manually deployed the package to this same server to a
few days ago. I tried Google again, and this time hit pay dirt. Executing it with
ALLUSERS=2 in the command line makes it available for everyone. Apparently, it forces
an “Everyone” install for the UI, too.
&lt;/p&gt;
&lt;p&gt;
Finally I can pull the thorn out.
&lt;/p&gt;
&lt;p&gt;
MSIExec /i mypackage .msi … ALLUSERS=2
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=8a466c03-70e5-4d01-ab90-bc9052145e1c" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,8a466c03-70e5-4d01-ab90-bc9052145e1c.aspx</comments>
      <category>Continuous Integration</category>
      <category>Tools</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=185d4fd2-87ca-49d8-b7f9-b06b3068559e</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,185d4fd2-87ca-49d8-b7f9-b06b3068559e.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,185d4fd2-87ca-49d8-b7f9-b06b3068559e.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=185d4fd2-87ca-49d8-b7f9-b06b3068559e</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
“It compiles! Ship it!”
</p>
        <p>
Microsoft has sent Visual Studio 2005 to the printers. That brings .Net 2.0 to the
table in all of its glory. The official release date is still November 7, and though
it is available now to all of us MSDN subscribers (though the site is too flooded
to ping, let alone download), there is still some question on if the media will be
ready in time to go in all of the pretty little VS05 boxes at your local Microsoft
store.
</p>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=185d4fd2-87ca-49d8-b7f9-b06b3068559e" />
      </body>
      <title>Visual Studio 2005 goes gold</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,185d4fd2-87ca-49d8-b7f9-b06b3068559e.aspx</guid>
      <link>http://www.cptloadtest.com/2005/10/28/Visual-Studio-2005-Goes-Gold.aspx</link>
      <pubDate>Fri, 28 Oct 2005 17:40:03 GMT</pubDate>
      <description>&lt;p&gt;
“It compiles! Ship it!”
&lt;/p&gt;
&lt;p&gt;
Microsoft has sent Visual Studio 2005 to the printers. That brings .Net 2.0 to the
table in all of its glory. The official release date is still November 7, and though
it is available now to all of us MSDN subscribers (though the site is too flooded
to ping, let alone download), there is still some question on if the media will be
ready in time to go in all of the pretty little VS05 boxes at your local Microsoft
store.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=185d4fd2-87ca-49d8-b7f9-b06b3068559e" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,185d4fd2-87ca-49d8-b7f9-b06b3068559e.aspx</comments>
      <category>ASP.Net</category>
      <category>Programming</category>
      <category>Tools</category>
      <category>Visual Studio</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=2daf105a-c324-4e4b-b720-d4d0ffbe3d2b</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,2daf105a-c324-4e4b-b720-d4d0ffbe3d2b.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,2daf105a-c324-4e4b-b720-d4d0ffbe3d2b.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=2daf105a-c324-4e4b-b720-d4d0ffbe3d2b</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Hopefully this will save a few of you some time: I have created a registry entry that
will create file associations and commands for your NAnt .build files. It will associate
.build files as “NAnt Build Files” and create two commands for right-clicking a .build
file in Explorer: “Edit” will open the file in Notepad; “Run” will execute the file
in NAnt using a persistent command window (the window won’t disappear when the script
is finished).
</p>
        <h3>NAnt Build File Associations
</h3>
        <blockquote>
          <p>
Windows Registry Editor Version 5.00
</p>
          <p>
[HKEY_CLASSES_ROOT\.build]<br />
@=”build_auto_file”
</p>
          <p>
[HKEY_CLASSES_ROOT\build_auto_file]<br />
@=”NAnt Build File”<br />
“EditFlags”=dword:00000000<br />
“BrowserFlags”=dword:00000008
</p>
          <p>
[HKEY_CLASSES_ROOT\build_auto_file\shell]<br />
@=”Edit”
</p>
          <p>
[HKEY_CLASSES_ROOT\build_auto_file\shell\&amp;Run]<br />
@=”Run”
</p>
          <p>
[HKEY_CLASSES_ROOT\build_auto_file\shell\&amp;Run\command]<br />
@=”C:\WINDOWS\system32\CMD.EXE /k “C:\Program Files\NAnt\bin\NAnt.exe” -buildfile:%1″
</p>
          <p>
[HKEY_CLASSES_ROOT\build_auto_file\shell\&amp;Run\ddeexec]
</p>
          <p>
[HKEY_CLASSES_ROOT\build_auto_file\shell\&amp;Run\ddeexec\Application]<br />
@=”NAnt”
</p>
          <p>
[HKEY_CLASSES_ROOT\build_auto_file\shell\&amp;Run\ddeexec\Topic]<br />
@=”System”
</p>
          <p>
[HKEY_CLASSES_ROOT\build_auto_file\shell\edit]<br />
@=”&amp;Edit”
</p>
          <p>
[HKEY_CLASSES_ROOT\build_auto_file\shell\edit\command]<br />
@=”C:\WINDOWS\system32\NOTEPAD.EXE %1″
</p>
          <p>
[HKEY_CLASSES_ROOT\build_auto_file\shell\edit\ddeexec]
</p>
          <p>
[HKEY_CLASSES_ROOT\build_auto_file\shell\edit\ddeexec\Application]<br />
@=”NOTEPAD”
</p>
          <p>
[HKEY_CLASSES_ROOT\build_auto_file\shell\edit\ddeexec\Topic]<br />
@=”System” 
</p>
        </blockquote>
        <p>
Use this code/file at your own risk. I offer it as is, without any support. By downloading
this file or using this code you take full responsibility for any repercussions that
it may have on your computer.
</p>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=2daf105a-c324-4e4b-b720-d4d0ffbe3d2b" />
      </body>
      <title>Run NAnt .build files from explorer</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,2daf105a-c324-4e4b-b720-d4d0ffbe3d2b.aspx</guid>
      <link>http://www.cptloadtest.com/2005/08/11/Run-NAnt-Build-Files-From-Explorer.aspx</link>
      <pubDate>Thu, 11 Aug 2005 17:46:23 GMT</pubDate>
      <description>&lt;p&gt;
Hopefully this will save a few of you some time: I have created a registry entry that
will create file associations and commands for your NAnt .build files. It will associate
.build files as “NAnt Build Files” and create two commands for right-clicking a .build
file in Explorer: “Edit” will open the file in Notepad; “Run” will execute the file
in NAnt using a persistent command window (the window won’t disappear when the script
is finished).
&lt;/p&gt;
&lt;h3&gt;NAnt Build File Associations
&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;
Windows Registry Editor Version 5.00
&lt;/p&gt;
&lt;p&gt;
[HKEY_CLASSES_ROOT\.build]&lt;br&gt;
@=”build_auto_file”
&lt;/p&gt;
&lt;p&gt;
[HKEY_CLASSES_ROOT\build_auto_file]&lt;br&gt;
@=”NAnt Build File”&lt;br&gt;
“EditFlags”=dword:00000000&lt;br&gt;
“BrowserFlags”=dword:00000008
&lt;/p&gt;
&lt;p&gt;
[HKEY_CLASSES_ROOT\build_auto_file\shell]&lt;br&gt;
@=”Edit”
&lt;/p&gt;
&lt;p&gt;
[HKEY_CLASSES_ROOT\build_auto_file\shell\&amp;amp;Run]&lt;br&gt;
@=”Run”
&lt;/p&gt;
&lt;p&gt;
[HKEY_CLASSES_ROOT\build_auto_file\shell\&amp;amp;Run\command]&lt;br&gt;
@=”C:\WINDOWS\system32\CMD.EXE /k “C:\Program Files\NAnt\bin\NAnt.exe” -buildfile:%1″
&lt;/p&gt;
&lt;p&gt;
[HKEY_CLASSES_ROOT\build_auto_file\shell\&amp;amp;Run\ddeexec]
&lt;/p&gt;
&lt;p&gt;
[HKEY_CLASSES_ROOT\build_auto_file\shell\&amp;amp;Run\ddeexec\Application]&lt;br&gt;
@=”NAnt”
&lt;/p&gt;
&lt;p&gt;
[HKEY_CLASSES_ROOT\build_auto_file\shell\&amp;amp;Run\ddeexec\Topic]&lt;br&gt;
@=”System”
&lt;/p&gt;
&lt;p&gt;
[HKEY_CLASSES_ROOT\build_auto_file\shell\edit]&lt;br&gt;
@=”&amp;amp;Edit”
&lt;/p&gt;
&lt;p&gt;
[HKEY_CLASSES_ROOT\build_auto_file\shell\edit\command]&lt;br&gt;
@=”C:\WINDOWS\system32\NOTEPAD.EXE %1″
&lt;/p&gt;
&lt;p&gt;
[HKEY_CLASSES_ROOT\build_auto_file\shell\edit\ddeexec]
&lt;/p&gt;
&lt;p&gt;
[HKEY_CLASSES_ROOT\build_auto_file\shell\edit\ddeexec\Application]&lt;br&gt;
@=”NOTEPAD”
&lt;/p&gt;
&lt;p&gt;
[HKEY_CLASSES_ROOT\build_auto_file\shell\edit\ddeexec\Topic]&lt;br&gt;
@=”System” 
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
Use this code/file at your own risk. I offer it as is, without any support. By downloading
this file or using this code you take full responsibility for any repercussions that
it may have on your computer.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=2daf105a-c324-4e4b-b720-d4d0ffbe3d2b" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,2daf105a-c324-4e4b-b720-d4d0ffbe3d2b.aspx</comments>
      <category>NAnt</category>
      <category>Task Automation</category>
      <category>Tools</category>
    </item>
    <item>
      <trackback:ping>http://www.cptloadtest.com/Trackback.aspx?guid=af2c4ce7-f9b6-47bd-bb51-bbb8cf12da76</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,af2c4ce7-f9b6-47bd-bb51-bbb8cf12da76.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,af2c4ce7-f9b6-47bd-bb51-bbb8cf12da76.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=af2c4ce7-f9b6-47bd-bb51-bbb8cf12da76</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <h3>Must Have Tools
</h3>
        <ul>
          <li>
            <strong>
              <a href="http://www.flos-freeware.ch/notepad2.html">Notepad2</a>
            </strong>:
A vital, essential, notepad replacement. Color-codes your text using syntax schemes
identified by the file’s extention. I followed <a href="http://www.hanselman.com/blog/ScottHanselmans2005UltimateDeveloperAndPowerUsersToolList.aspx">Scott
Hanselman</a> and “renamed ‘Notepad2.exe’ to ‘n.exe’ which saves me a few dozen ‘otepad’s
a day.”</li>
          <li>
            <strong>
              <a href="http://www.sysinternals.com/Utilities/PsExec.html">PsExec</a>
            </strong>:
[<a href="http://www.cptloadtest.com/?p=32">blog entry</a>] Execute remote applications,
remotely. Great for installing an MSI on a remote box without resorting to Remote
Desktop. Also great for launching solitaire on your buddy’s machine and harrassing
him for slacking at work.</li>
        </ul>
        <h3>Testing Tools
</h3>
        <ul>
          <li>
            <strong>
              <a href="http://www.wisdom-soft.com/products/screenhunter.htm">Screen Hunter
4.0 Free</a>
            </strong>: [<a href="http://www.cptloadtest.com/?p=14">blog entry</a>]
Free screen capture tool that is a requirement in any tester’s toolbelt.</li>
          <li>
            <strong>
              <a href="http://wtr.rubyforge.org/">Watir</a>
            </strong>: [<a href="http://www.cptloadtest.com/?p=28">blog
entry</a>] Web Application Testing In Ruby. An automated functional testing tool for
automated browser tests in IE. Scripts are written in Ruby.</li>
        </ul>
        <h3>Continuous Integration Tools
</h3>
        <ul>
          <li>
            <strong>
              <a href="http://confluence.public.thoughtworks.org/display/CCNET/">CruiseControl.Net</a>
            </strong>:
Monitor your source. Can be used to manage automated builds, build status, and reports
from NUnit, FXCop, etc.</li>
          <li>
            <strong>
              <a href="http://nant.sourceforge.net/">NAnt</a>
            </strong>: Free build tool
for .Net. Use with CruiseControl.net to automatically build nightlies or whenever
a code change occurs.</li>
          <li>
            <strong>
              <a href="http://nantcontrib.sourceforge.net/">NantContrib</a>
            </strong>: An
extention for NAnt. Adds some useful tasks that NAnt does not include, such as integration
with VSS.</li>
        </ul>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=af2c4ce7-f9b6-47bd-bb51-bbb8cf12da76" />
      </body>
      <title>Must Have Tools</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,af2c4ce7-f9b6-47bd-bb51-bbb8cf12da76.aspx</guid>
      <link>http://www.cptloadtest.com/2005/07/27/Must-Have-Tools.aspx</link>
      <pubDate>Wed, 27 Jul 2005 18:07:10 GMT</pubDate>
      <description>&lt;h3&gt;Must Have Tools
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="http://www.flos-freeware.ch/notepad2.html"&gt;Notepad2&lt;/a&gt;&lt;/strong&gt;:
A vital, essential, notepad replacement. Color-codes your text using syntax schemes
identified by the file’s extention. I followed &lt;a href="http://www.hanselman.com/blog/ScottHanselmans2005UltimateDeveloperAndPowerUsersToolList.aspx"&gt;Scott
Hanselman&lt;/a&gt; and “renamed ‘Notepad2.exe’ to ‘n.exe’ which saves me a few dozen ‘otepad’s
a day.”&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="http://www.sysinternals.com/Utilities/PsExec.html"&gt;PsExec&lt;/a&gt;&lt;/strong&gt;:
[&lt;a href="http://www.cptloadtest.com/?p=32"&gt;blog entry&lt;/a&gt;] Execute remote applications,
remotely. Great for installing an MSI on a remote box without resorting to Remote
Desktop. Also great for launching solitaire on your buddy’s machine and harrassing
him for slacking at work.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Testing Tools
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="http://www.wisdom-soft.com/products/screenhunter.htm"&gt;Screen Hunter
4.0 Free&lt;/a&gt;&lt;/strong&gt;: [&lt;a href="http://www.cptloadtest.com/?p=14"&gt;blog entry&lt;/a&gt;]
Free screen capture tool that is a requirement in any tester’s toolbelt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="http://wtr.rubyforge.org/"&gt;Watir&lt;/a&gt;&lt;/strong&gt;: [&lt;a href="http://www.cptloadtest.com/?p=28"&gt;blog
entry&lt;/a&gt;] Web Application Testing In Ruby. An automated functional testing tool for
automated browser tests in IE. Scripts are written in Ruby.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Continuous Integration Tools
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="http://confluence.public.thoughtworks.org/display/CCNET/"&gt;CruiseControl.Net&lt;/a&gt;&lt;/strong&gt;:
Monitor your source. Can be used to manage automated builds, build status, and reports
from NUnit, FXCop, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="http://nant.sourceforge.net/"&gt;NAnt&lt;/a&gt;&lt;/strong&gt;: Free build tool
for .Net. Use with CruiseControl.net to automatically build nightlies or whenever
a code change occurs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="http://nantcontrib.sourceforge.net/"&gt;NantContrib&lt;/a&gt;&lt;/strong&gt;: An
extention for NAnt. Adds some useful tasks that NAnt does not include, such as integration
with VSS.&lt;/li&gt;
&lt;/ul&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=af2c4ce7-f9b6-47bd-bb51-bbb8cf12da76" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,af2c4ce7-f9b6-47bd-bb51-bbb8cf12da76.aspx</comments>
      <category>Mush</category>
      <category>Tools</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=06a099a6-6f14-4f25-a729-caacec5191bc</trackback:ping>
      <pingback:server>http://www.cptloadtest.com/pingback.aspx</pingback:server>
      <pingback:target>http://www.cptloadtest.com/PermaLink,guid,06a099a6-6f14-4f25-a729-caacec5191bc.aspx</pingback:target>
      <dc:creator>Jay Harris</dc:creator>
      <wfw:comment>http://www.cptloadtest.com/CommentView,guid,06a099a6-6f14-4f25-a729-caacec5191bc.aspx</wfw:comment>
      <wfw:commentRss>http://www.cptloadtest.com/SyndicationService.asmx/GetEntryCommentsRss?guid=06a099a6-6f14-4f25-a729-caacec5191bc</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
In code deployment, it is often necessary to perform tasks that must be executed locally
on the destination box, such as installing through an MSI or installing assemblies
to the GAC through GACUtils. Thankfully, there is a way that this can all be done
remotely, with any process, as long as it can be accessed through a command prompt.
The destination computer will think that you are working on it directly, though it
may just be your NAnt script doing the work for you.
</p>
        <p>
          <a href="http://www.sysinternals.com/">SysInternals</a> publishes a tool called <a href="http://www.sysinternals.com/Utilities/PsExec.html">PsExec</a>.
It allows you to execute a program remotely on a remote machine. To the remote machine
the process is running locally. Because of this, you can use traditional command line
tools to run programs and utilities, such as GACUtil to install a new assembly to
the GAC on a remote box–a feature that most other options don’t support.
</p>
        <blockquote>
          <p>
            <code>PSExec \MyServer "C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\GACUtil.exe"
"C:\bin\MyAssembly.dll"</code>
          </p>
          <p>
Note: the paths are all ‘local’ paths on \\MyServer, just as you would enter from
a command prompt in an RDP session to MyServer. You will also need to customize the
paths to include whatever location and framework version your remote machine uses.
</p>
        </blockquote>
        <p>
As for me, because our web applications make thorough use of the GAC, our only deployment
method is a VS.Net Deployment project to create a MSI. We have NAnt scripts that upload
the MSI to remote machines then execute PsExec run the installation (MSIExec) in unattended
mode. It has brought our deployment time down from a manual 30-45 minutes to an automated
15 minutes, and allows code managers to spend those 30-45 minutes doing something
else. We save even more time when we deploy to production, which contains an 8-server
web farm.
</p>
        <img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=06a099a6-6f14-4f25-a729-caacec5191bc" />
      </body>
      <title>Remote deployment to the GAC</title>
      <guid isPermaLink="false">http://www.cptloadtest.com/PermaLink,guid,06a099a6-6f14-4f25-a729-caacec5191bc.aspx</guid>
      <link>http://www.cptloadtest.com/2005/07/26/Remote-Deployment-To-The-GAC.aspx</link>
      <pubDate>Tue, 26 Jul 2005 15:39:49 GMT</pubDate>
      <description>&lt;p&gt;
In code deployment, it is often necessary to perform tasks that must be executed locally
on the destination box, such as installing through an MSI or installing assemblies
to the GAC through GACUtils. Thankfully, there is a way that this can all be done
remotely, with any process, as long as it can be accessed through a command prompt.
The destination computer will think that you are working on it directly, though it
may just be your NAnt script doing the work for you.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.sysinternals.com/"&gt;SysInternals&lt;/a&gt; publishes a tool called &lt;a href="http://www.sysinternals.com/Utilities/PsExec.html"&gt;PsExec&lt;/a&gt;.
It allows you to execute a program remotely on a remote machine. To the remote machine
the process is running locally. Because of this, you can use traditional command line
tools to run programs and utilities, such as GACUtil to install a new assembly to
the GAC on a remote box–a feature that most other options don’t support.
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;
&lt;code&gt;PSExec \MyServer "C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\GACUtil.exe"
"C:\bin\MyAssembly.dll"&lt;/code&gt;
&lt;/p&gt;
&lt;p&gt;
Note: the paths are all ‘local’ paths on \\MyServer, just as you would enter from
a command prompt in an RDP session to MyServer. You will also need to customize the
paths to include whatever location and framework version your remote machine uses.
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
As for me, because our web applications make thorough use of the GAC, our only deployment
method is a VS.Net Deployment project to create a MSI. We have NAnt scripts that upload
the MSI to remote machines then execute PsExec run the installation (MSIExec) in unattended
mode. It has brought our deployment time down from a manual 30-45 minutes to an automated
15 minutes, and allows code managers to spend those 30-45 minutes doing something
else. We save even more time when we deploy to production, which contains an 8-server
web farm.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cptloadtest.com/aggbug.ashx?id=06a099a6-6f14-4f25-a729-caacec5191bc" /&gt;</description>
      <comments>http://www.cptloadtest.com/CommentView,guid,06a099a6-6f14-4f25-a729-caacec5191bc.aspx</comments>
      <category>ASP.Net</category>
      <category>Tools</category>
    </item>
  </channel>
</rss>