code

You are currently browsing the archive for the code category.

I just setup browser testing framework utilizing Selenium from TeamCity project. The usual suspects are involved, Gallio, MBUnit, Nant and even C# Unittests.

The usual scenario when it comes to automating browser testing is that the QA / testers will create some scripts to run a browser against your website. Somehow those tests are usually not maintained very well and often are run by hand. There is not much value in browser testing scripts if you have to run them by hand.

As I needed browser testing on one of the projects I’m on I decided to look into using more of a automated setup to run the browser tests. There seem to be two big players Waitn and Selenium, Selenium lends itself to broader range of testing, naturally we will go with Selenium.

Here is the scenario I want, the tester installs a recorder on his computer, in this case a FireFox plugin. The tester records the tests and runs them in the browser using the plugin tool. Once the tester is happy with the tests the tester checks them into the repository. After check-in tester lets a developer know that there are new or changed tests. The developer takes the script and turns it into C# UnitTest, simply has Selenium convert it to UnitTest code. Then the developer takes and updates or adds the tests that resulted from the scripts and checks it into the repository. The conversion step could be automated in the future once Selenium supports that. The next step is to run it from TeamCity and after it runs you get email with the results.

So let’s take a closer look at what is needed. We need the UnitTest to be able to run against different servers using different browsers. We will pass values from TeamCity to the Nant script that is responsible for compiling and running the tests. This is how your test C# configuration file might look like.

<!– Selenium RC properties–>
    <add key=“SeleniumAddress” value=“localhost” />
    <add key=“SeleniumPort” value=“4444″ />
    <add key=“SeleniumSpeed” value=“0″ />
   
    <!– Browser targets –>
    <add key=“BrowserType” value=“*firefox” />
    <add key=“BrowserUrl” value=“http://10.9.169.198/” />
    <add key=“BaseUrlPath” value=“IPCA.Dev/” />

Then the base test class will look something like this.

[FixtureSetUp]
        public virtual void TestFixtureSetup()
        {
            // Read from config
            msBrowserType = getConfigSetting(“BrowserType”, msBrowserType );
            msBrowserUrl = getConfigSetting(“BrowserUrl”, msBrowserUrl);
            msBasePath = getConfigSetting(“BaseUrlPath”, msBasePath);
            //
            msSeleniumAddress = getConfigSetting( “SeleniumAddress”, msSeleniumAddress );
            miSeleniumPort = int.Parse(getConfigSetting(“SeleniumPort”, miSeleniumPort.ToString()) );
            msSeleniumSpeed = getConfigSetting( “SeleniumSpeed”, msSeleniumSpeed );
           
           
            // Start up the selenium session, using config values
            selenium = new DefaultSelenium(msSeleniumAddress, miSeleniumPort, msBrowserType, msBrowserUrl);
            selenium.Start();
            // Clean errors
            verificationErrors = new StringBuilder();

            // sets the speed of execution of GUI commands
            selenium.SetSpeed(msSeleniumSpeed);
        }

        [TearDown]
        public void TeardownTest()
        {
            try
            {
                selenium.Stop();
            }
            catch (Exception)
            {
                // Ignore errors if unable to close the browser
            }
            Assert.AreEqual(“”, verificationErrors.ToString());
        }

And a sample Selenium C# Unittest

//
using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
//
using Gallio.Framework.Assertions;
using MbUnit.Framework;
//
using Selenium;

namespace SeleniumTests
{
    [TestFixture]
    public class LoginPage : WebTestBase
    {

        [Test]
        public void TheLoginPageTest()
        {
            selenium.Open( this.msBasePath + “TestLogin.aspx”);
            selenium.Click(“lbAdmin”);
            selenium.WaitForPageToLoad(“50000″);
            selenium.Click(“loginLink”);
            selenium.WaitForPageToLoad(“50000″);
            try
            {
                Assert.IsTrue(selenium.IsTextPresent(“my responsibilities regarding permissible access”));
            }
            catch (AssertionException e)
            {
                verificationErrors.Append(e.Message);
            }
            selenium.Click(“ctl00_pageContent_btnSubmit”);
            selenium.WaitForPageToLoad(“50000″);
            try
            {
                Assert.IsTrue(selenium.IsTextPresent(“Total Unassigned Web”));
            }
            catch (AssertionException e)
            {
                verificationErrors.Append(e.Message);
            }
        }
    }
}

After the Nant script compiles the tests and is getting ready to run the UnitTests it needs to startup the Selenium engine. Make sure to spawn in order for the Selenium engine to exist on another thread than your tests.

<property name=“SeleniumExec” value=“java” />
  <property name=“SeleniumPath” value=“C:\apps\selenium\selenium-server-1.0.3\” />
  <property name=”SeleniumParams” value=”-jar ${SeleniumPath}selenium-server.jar” />

    <!– Start selenium –>
    <exec   program=”${SeleniumExec}
      commandline=”
${SeleniumParams}” workingdir=”${path.base}${WebTest}
      spawn=”
true” failonerror=”true” verbose=”true
       />

    <!– Give it a sec to load –>
    <sleep milliseconds=”3000” />

In order to run the tests using different browsers, change the configuration file of the tests before run.

<!– Run tests in Firefox browser –>
    <xmlpoke
        file=“${path.base.test}${assembly.test.config}”
        xpath=“/configuration/appSettings/add[@key='BrowserType']/@value”
        value=“*firefox”
        verbose=“true”/>

    <call target=“runTests” />

<target name=“runTests”
    description=“runs tests using Gallio.” >

   
    <echo message=“*** Start runTests: “/>

      <gallio
        result-property=“exitCode”
        failonerror=“false”
        report-types=“Html;Xml”
        report-directory=“${artifacts}”
        report-name-format=“gallioresults”
        show-reports=“false”
        application-base-directory=“${path.base.test}”
            >

          <!– Specify the tests assemblies  –>
          <files>
            <include name=“${path.base.test}${assembly.test}”/>
          </files>
        </gallio>

        <!–
            Set error for email injector to pick it up and GlobalFailBuildMessage for
            the end target to fail the build after cleanup
          –>

        <if test=“${int::parse(exitCode)!=0}”>
          <property name=“GlobalFailBuildMessage” value=“*** One or more tests failed. Please check the log for more details” dynamic=“true” />
          <echo message=“EmailInjectMsg=${GlobalFailBuildMessage}” />
        </if>

    <echo message=“*** End runTests: “/>
  </target>

And after the run of the Unittests Selenium needs to be shut down

<!– Stop Selenium server –>
      <get  src=“http://localhost:4444/selenium-server/driver/?cmd=shutDownSeleniumServer”
        dest=“shutdown.txt”  failonerror=“false”
      />

As I had a need to setup different configurations in TeamCity to run against different locations on the webserver I used a couple of Nant variables that are passed on the command line from TeamCity, like you normally would do when running Nant script -D:BaseUrlPath=/Test/ etc.

<echo message=“*** Location variables passed from TeamCity”/>
    <echo message=“*** BrowserUrl=${BrowserUrl} “/>
    <echo message=“*** BaseUrlPath=${BaseUrlPath} “/>

Of course you get the Gallio UnitTest report as well

gallio_report

With this setup once we deploy to a server we can run all the browser tests on it using different browsers with one click of a button from TeamCity.

Custom Nant Task

When using Nant there is not much you can say is lacking. Sometimes you find yourself wondering why you are cutting and pasting good amount of code between different scripts. There has to be a better way of reusing code and sure enough there is. Just write your own Nant extension and it’s pretty simple, let’s take a look.

First create a class that extends the nant Task then declare the name of the task and setup the properties you want available to the user. Lastly you will have ExecuteTask procedure that will be called by Nant when your Task executes. That’s all the magic !

[TaskName(“setVersionAssembly”)]
    public class CxSetVersionAssembly : NAnt.Core.Task
    {
        [TaskAttribute(“file”, Required = true)]
        [StringValidator(AllowEmpty = false)]
        public string file
        {
            get { return msAssemblyFile; }
            set { msAssemblyFile = value; }
        }

        [TaskAttribute(“buildNumber”, Required = true)]
        [StringValidator(AllowEmpty = false)]
        public string buildNumber
        {
            get { return msBuildNumber; }
            set { msBuildNumber = value; }
        }

        // Executes the nant task
        protected override void ExecuteTask()
        {
            // Don’t catch errors, it will display in the build log if any
            Project.Log(Level.Info, “start setVersionAssembly”);
            ChangeAssemblyVersionNumber(msBuildNumber, msAssemblyFile);
        }
}

When you use it in your Nant script you will have to load your assembly first. Once your assembly has been loaded you can start using your custom Task.

<loadtasks assembly=“bin\debug\DE.Nant.Extensions.dll”/>

    <setVersionAssembly
         file=“${tempFile}”
         buildNumber=“3.333.3.3000″
    />

This is a very brief and simple example, there are bunch of properties and other goodies you can use as you build out your custom Nant Tasks.

The Custom Nant Task I wrote is used to update the version of our .net assemblies during build. Attached is the complete code including Nant script and unittests. Get the code

I’m sure you had the need sometime to download the content of a web page to be able to analyze it or work with the content. Here is a code snippet just for you, we will use simple http GET for the specified URL.

public static string getWebPage(string psUrl)
{
    WebResponse result = null;
    string sRet = string.Empty;

    try
    {
        WebRequest req = WebRequest.Create(psUrl);
        req.Method = “GET”;
        req.Timeout = 3 * 1000// 3 secs
        // Explicit no caching, usually this is the default
        req.CachePolicy = new RequestCachePolicy(RequestCacheLevel.BypassCache);

        // Has to process the results if the responding service is spitting it out
        result = req.GetResponse();
        Stream ReceiveStream = result.GetResponseStream();
        Encoding encode = System.Text.Encoding.GetEncoding(“utf-8″);
        StreamReader sr = new StreamReader(ReceiveStream, encode);
        // in case the caller is interested
        sRet = sr.ReadToEnd();
    }
    finally
    {
        if (result != null) result.Close();
    }

    return sRet;
}

I went looking for a nant script to checkout changed files between two revisions from SVN. I found some Ant / Java based solutions. As we are using nant I figured I would give it a shot writing it myself. It is easy to get a list of files from SVN using diff. However that doesn’t do you any good if you need to get them from SVN by hand one by one. The trick is to use the list you get from SVN diff and then loop each file and bring it down to the local machine. The biggest gotcha was of course space in file or directory names. If you notice in the script that’s taken care of by inserting %20 in the URL location and local file names are quoted with double quote when doing the SVN export. List of deleted files are written to deletedfiles.txt in the checkout directory, Enjoy !

<?xml version=“1.0″?>
<!–
  Exports changes between revision from the given repository URL to checkout Directory
–>
<project name=“SVN_changes”
   default=“getChanges”
   basedir=“.”>

  <!–
   Register the sys.* properties; most specifically, sys.env.* for all environment vars
  –>
  <sysinfo/>

  <!– Properties / defaults –>
  <property name=“checkoutDir” value=“svnchanges”/>
  <property name=“changelog” value=“${checkoutDir}\changelog.txt”/>
  <property name=“delLog” value=“${checkoutDir}\deletedfiles.txt”/>
  <property name=“delFile” value=“”/>
  <property name=“deleteIndicator” value=“D      “/>

  <!– url to svn repository –>
  <property name=“repoURL” value=“http://10.10.10.10/svn/myproject/trunk”/>
  <property name=“repoUser” value=“testUser” dynamic=“true” />
  <property name=“repoPassword” value=“testPassword” dynamic=“true” />
  <property name=“startingRevision” value=“29455″ />
  <property name=“endingRevision” value=“30692″ />

  <target name=“getChanges” description=“Get changes from Subversion given two revisions “  >

    <echo message=“Exporting files between revisions ${startingRevision} and ${endingRevision}” />
    <echo message=“from ${repoURL}” />
    <echo message=“to ${checkoutDir}/” />
    <echo message=“——-” />
    <echo message=“stand by….. “ />
    <echo message=“——-” />

    <!– Start with a fresh local checkout directory –>
    <mkdir dir=“${checkoutDir}” />

    <!– creates log file comparison from start to end revision –>
    <exec program=“svn”
      commandline=“diff -r ${startingRevision}:${endingRevision} –summarize ${repoURL}”
      output=“${changelog}” />

    <!– Loop the files in the changelog and process –>
    <foreach item=“Line” in=“${changelog}” delim=“,” property=“svnfile”>

      <!– Extract the file name –>
      <property name=“startpos” value=“${string::index-of(svnfile, repoURL) +  string::get-length(repoURL) }” />
      <property name=“length” value=“${string::get-length(svnfile) - int::parse(startpos)}” />
      <property name=“tmpFile” value=“${string::substring( svnfile, startpos, length)}” />
      <!– Space in URL covered –>
      <property name=“repoFile” value=“${string::replace( tmpFile, ‘ ‘, ‘%20′)}” />
      <!– Extract the dir –>
      <property name=“endpos” value=“${string::last-index-of( tmpFile, ‘/’)}” />
      <property name=“localDir” value=“${string::substring( tmpFile, 0, int::parse(endpos))}” />

      <!– Sep –>
      <echo message=“—”/>
     
      <!– Advertise deleted files between revisions –>
      <if test=“${ string::contains(svnfile, deleteIndicator)}”>
          <echo message=“Deleted file=${tmpFile}”/>
          <property name=“delFile” value=“${tmpFile}”/>
          <call target=“WriteToTextFile” />
      </if>

      <!– Files to bring down from repository  –>
      <if test=“${ not string::contains(svnfile, deleteIndicator)}”>
          <!–
            Create the dir before checkout, this might happen multible times
            for files in the same dir, don‘t fail it.
          –>
          <mkdir dir="${checkoutDir}${localDir}" failonerror="false"/>
       
          <!– Check out the file –>
          <echo message="svn export ${repoURL}${repoFile} &quot;${checkoutDir}${tmpFile}&quot; -r ${endingRevision} –force " />
          <exec program="svn"
                commandline="export ${repoURL}${repoFile} &quot;${checkoutDir}${tmpFile}&quot; -r ${endingRevision} –force"
                            failonerror="true"
          />
      </if>
    </foreach>

    <!– Show user that it’s all done –>
    <echo message=“   ” />
    <echo message=“——-” />
    <echo message=“Changed and new files have been exported to the ${checkoutDir} directory” />
    <echo message=“List of deleted files can be found in the ${delLog} file” />
    <echo message=“——-” />
    <echo message=“Done !” />
  </target>

  <!– Appends deleted files to text file –>
  <target name=“WriteToTextFile” >
    <script language=“C#” mainclass=“writeToDelLog”>
      <references>
        <include name=“System.Management.dll” />
      </references>
      <div class=“codesnip-container” ><![CDATA[
            class writeToDelLog
            {       
                public static void ScriptMain(Project project)
                {       
                                      PropertyDictionary pd = project.Properties;       
                    string sDeletedFile = pd[“delLog”];
                    string sDeletedEntry = pd[“delFile”];
                   
                    FileStream stream = new FileStream(sDeletedFile, FileMode.Append );
                    StreamWriter writer = new StreamWriter(stream);

                    try
                    {
                      writer.WriteLine(sDeletedEntry);
                    }
                    catch( Exception ex )
                    {
                      Console.WriteLine( “NOT able to write to file, error=” + ex );
                    }
                    finally
                    {
                      if( writer != null ) writer.Close();
                      if( stream != null ) stream.Close();
                    }
                           
                }
            }
        ]]></div>
    </script>
  </target>

</project>

If you are like me and wonder how much coverage your unittests have you can add coverage to your Team Foundation Server builds and see for yourself.

Note, I have only tried this using VS2008

First right click /Solution items in your solution explorer Add new item, choose Test run Configuration, let’s name it CodeCoverage.testrunconfig

Choose Code coverage on the left and choose the dll’s you want covered, save and check it in.

In your build.proj file find the first PropertyGroup, at the end of it add the line about the config file. You will need this in order for MsBuild to find the configuration. Then it will look similar to the xml below. Note the path, in my case I had to add \MYPROJECT to the mix as that’s where my source gets checked out on the build machine. You can see where that is on the server or check the build log and look at what directory the file is checked out to.

<PropertyGroup>
    …. snip
 
    <RunConfigFile>
        $(SolutionRoot)\MYPROJECT\CodeCoverage.testrunconfig
    </RunConfigFile>
  </PropertyGroup>

The coverage numbers will show up in the Unittest section of the build report. It is of course important to remember a well covered code does NOT mean that your unittests are any good. Most likely they are but the coverage number just means how much of the code was touched during the unittest run.

C# Base32

I had the need to use Base32 at work some time ago to compress numbers. I had forgotten about it until today when I ran across some old code. As I was researching implementation for a developer on another system we interact with. The problem at the time was that we had numbers that are too big to fit in the field where we needed to write it. In order to do so we needed to compress it and we choose Base32 for the task.

Simply put, you take a number and you convert it to the 32 characters in the convert table, for example.

123456789 becomes VITXVD

Of course when you have the Base32 encoded number you can decode it back to the original number. If you couldn’t do that it wouldn’t be very useful.

VITXVD becomes 123456789

The RFC 4648 Base 32 alphabet
Value Symbol Value Symbol Value Symbol Value Symbol
0 A 9 J 18 S 27 3
1 B 10 K 19 T 28 4
2 C 11 L 20 U 29 5
3 D 12 M 21 V 30 6
4 E 13 N 22 W 31 7
5 F 14 O 23 X
6 G 15 P 24 Y
7 H 16 Q 25 Z
8 I 17 R 26 2



Note that one and zero are not used so there is no confusion between them O and I. When shuffling data between different systems, legacy etc they might not be interpreted correctly. You can create the Base32 encoding in different ways. Therefor if your interacting with another system exchanging data that system needs to use the same encoding / decoding as your system.

Below is a C# sample Base32 code.

class CxBase32
    {
        //
        private const string BASE_32_ALPHABET = “ABCDEFGHIJKLMNOPQRSTUVWXYZ234567″;
        private static int BASE_LENGTH = BASE_32_ALPHABET.Length;
 
        // Encode number to base 32 string
        public static string toBase32( int piNumToCode )
        {
            StringBuilder sRet = new StringBuilder();
 
            // loop until nothing left
            do
            {
                // Set the encoded character using mod
                sRet.Append(BASE_32_ALPHABET[piNumToCode % BASE_LENGTH]);
                // Adjust the reminder
                piNumToCode = piNumToCode / BASE_LENGTH;
            }
            while (piNumToCode != 0);
 
            return sRet.ToString();
        }
 
 
        // Decode base 32 string to a number
        public static int fromBase32(string psCodedString)
        {
            int iRet = 0;
 
            // Decode the alphabet
            for (int i = psCodedString.Length - 1; i > -1; i–)
                { iRet = (iRet * BASE_LENGTH) + BASE_32_ALPHABET.IndexOf(psCodedString[i]); }
 
            return iRet;
        }
 
    }  // EOC
 

And unittests

[Test]
        // Make sure encoded number can be decoded correctly
        public void randomBase32Test()
        {
            // Try some random number
            string encoded = CxBase32.toBase32(123456789);
            Assert.AreEqual(“VITXVD”, encoded);
            int decode = CxBase32.fromBase32( encoded );
            Assert.AreEqual(123456789, decode);
           
            // Another number just for fun
            encoded = CxBase32.toBase32(987654321);
            Assert.AreEqual(“RF24N5″, encoded);
            decode = CxBase32.fromBase32(encoded);
            Assert.AreEqual(987654321, decode);
        }
       
        [Test]
        // Make sure zero will return a value
        public void zeroBase32Test()
        {
            // Zero test, should return a value as well
            string encoded = CxBase32.toBase32(0);
            Assert.AreEqual(“A”, encoded);
            int decode = CxBase32.fromBase32(encoded);
            Assert.AreEqual(0, decode);
        }

« Older entries