Tuesday, September 15, 2009

Selenium RC timing issues

Even the best Selenium test will fall victim to timing issues which will cause tests to fail some what randomly.

This class attempts to isolate the test from timing issues by performing an automatic retry.

public static class SeleniumRetry
 {
  public static void Invoke<TArg>(Action<TArg> action, TArg arg)
  {
   Invoke(() => action.Invoke(arg));
  }
  
  public static void Invoke<TArg1, TArg2>(Action<TArg1, TArg2> action2, TArg1 arg1, TArg2 arg2)
  {
   Invoke(() => action2.Invoke(arg1, arg2));    
  }
  
  public static void Invoke(Action action)
  {
   var attempt = 0;
   const int maxAttempts = 5;
   while (true)
   {
    try
    {
     action.Invoke();
     break;
    }
    catch (Exception e)
    {
     Console.WriteLine(e.Message);

     if (++attempt > maxAttempts)
      throw;

     Thread.Sleep(500);
    }
   }
  }
 }


Using the class is simple:
This scenario shows how to automate a dynamically loaded login form that is created when the PopupLogon link is clicked.

SeleniumRetry.Invoke(Browser.Click, "PopupLogon");

SeleniumRetry.Invoke(Browser.Type, "input_email", "fake@email.com");
SeleniumRetry.Invoke(Browser.Type, "password", "12345");

//First click selects the button, second performs action.
SeleniumRetry.Invoke(Browser.Click, "submitBtn");
SeleniumRetry.Invoke(Browser.Click, "submitBtn");

Thursday, September 10, 2009

Automatically start and stop SeleniumRC with NUnit

You can use NUnit and SeleniumRC to run automated functional tests of your website. This is a simple class that starts selenium at the beginning of a unit test suite and shuts it down when done.


using System.Diagnostics;
using System.Net;
using NUnit.Framework;

[SetUpFixture]
public class SeleniumRcSetup
{
private readonly Process SeleniumRC = new Process();
[SetUp]
public void StartSelniumRc()
{
const string pathRelativeToProjBinDebug = @"path to your selenium installation";
SeleniumRC.StartInfo.FileName = "java";
SeleniumRC.StartInfo.Arguments = string.Format("-jar {0}selenium-server.jar", pathRelativeToProjBinDebug);
SeleniumRC.Start();
}
[TearDown]
public void StopSeleniumRc()
{
var r = WebRequest.Create("http://localhost:4444/selenium-server/driver/?cmd=shutDown");
r.GetResponse();
SeleniumRC.WaitForExit(5000);
SeleniumRC.Close();
}
}

Wednesday, September 9, 2009

Using XmlSerializer without rendering document declaration or namespace

Using xmlSerializer to serialize an object will by default add the xml namespace and document declaration. <strong>Example</strong>:

<?xml version="1.0" encoding="Windows-1252"?>
<node xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" uID="12345">
...
</node>

But if all you want is to write out the xml fragment like:
<node uid="12345">
...
</node>

You need to configure the serializer before you use it. The following code will not render the document declaration or namespace.

public void SerializeWithNoDeclarationNoNamespace<T>(TextWriter writer, T theObject)
{
var settings = new XmlWriterSettings
{
Indent = true,
IndentChars = " ",
NewLineHandling = NewLineHandling.Replace,
NewLineChars = Environment.NewLine,
OmitXmlDeclaration = true
};

using (var xmlWriter = XmlWriter.Create(writer, settings))
{
var xmlnsEmpty = new XmlSerializerNamespaces();
xmlnsEmpty.Add("", "");

new XmlSerializer(typeof(T)).Serialize(xmlWriter, theObject, xmlnsEmpty);
}

writer.WriteLine("");
}

Friday, July 31, 2009

iTunesConnect crash reports

One nice feature of iTunesConnect is that you get crash reports from real users. You can use the symbolicatecrash script to map the crash report to line numbers in your code.

symbolicatecrash attempts to be very clever at finding the symbol files based on the applicaton GUID found in the crash report. Unfortunately even if you use a revision control system, get the exact revision of the code you released to the iTunes store and re-build, symbolicatecrash wont find the debug symbols because the applications GUIDs don't match.

In a pinch you can break open the symbolicatecrash script file, brush up on your Perl skills and force it to use the symbol file created by the re-build.

But for all future releases you can just have Hudson archive the debug symbol files for you and life will be much easier.

zip -r -T -y "myApp_ProdSymbols.zip" "myApp.app.dSYM"

Friday, July 17, 2009

iPhone app distribution made easy - Part 4

Introducing Subversion
One of the most important items for any kind of software development is a version/revision control system. There are many flavors of version control systems and many arguments for and against each one. Ultimately they all provide the ability to track changes in code over time and provide the ability to manage development paths. For the purpose of this post I'll be referencing SubVersion (http://subversion.tigris.org/).

Introducing Hudson
Hudson is a continuous integration build system that enables easy tracking and running of builds. Hudson can be downloaded from https://hudson.dev.java.net/ and is very easy to get started and can be run on the Mac with the following command "java -jar hudson.war".

Hudson is integrated with subversion so builds can be triggered by subversion code commits. Builds can also be launched manually. One of the great strengths of Hudson is that it manages all the build numbers and build artifacts for you so you don't have to think about it.

Basic steps
The steps to get Hudson building your iPhone applications are quite simple and follows the format:


  1. Create a new hudson job

  2. Point Hudson to your subversion repository

  3. Create a build step to run the build scripts developed earlier in Part 2 and Part 3.

  4. Instruct Hudson to save the build output.


Example Build step
The following build step starts by creating some variables for build folders etc using some of Hudson's built in environment variables. It then builds the AppStore and AdHoc distributions.

PROJDIR=${WORKSPACE}/myApp
ADHOC_BUILDDIR="${PROJDIR}/build/myAppAdHoc/DistributionAdHoc-iphoneos"
APPSTORE_BUILDDIR="${PROJDIR}/build/myAppAppStore/DistributionAppStore-iphoneos"
BASEFILENAME="${JOB_NAME}_${BUILD_NUMBER}(rev-${SVN_REVISION})"

echo Building AppStore release
cd "${PROJDIR}"
xcodebuild -target "myAppAppStore" -configuration "DistributionAppStore" -sdk iphoneos2.1
cd "${APPSTORE_BUILDDIR}"
zip -r -T -y "${BASEFILENAME}_AppStoreApp.zip" "myApp.app"

echo Building AdHoc release
cd "${PROJDIR}"
xcodebuild -target "myAppAdHoc" -configuration "DistributionAdHoc" -sdk iphoneos2.1
cd "${ADHOC_BUILDDIR}"
zip -r -T -y "${BASEFILENAME}_AdHocApp.zip" "myApp.app"


The output zip file name will include the build number & subversion revision number for easy reference.

Example: myApp_13(rev-99619)_ProdApp.zip

Example artifacts archive
Hudson has the ability to perform wild card searches when looking for build artifacts. The following will search both the AdHoc and AppStore build folders for their output files.

myApp/build/**/*.zip

Conclusion
So hopefully you are now inspired or atleast aware of how you can make your own iPhone development easier.

iPhone app distribution made easy - Part 3

Now that we've built the distributions with xcodebuild it seems a shame to use Finder to compress the app bundle for submission to the App Store.

So lets use the "zip" command line utility to compress the app bundle:

zip -r -T -y "myApp_AppStoreDistribution.zip" "myApp.app"

The important option to note here is the "-y" option that stores symbolic links as the link. This is important because the app bundle contains symbolic links to the code signature folder.

If the symbolic links don't exist the application will not be accepted and iTunesConnect will complain with an error like:

The binary you uploaded was invalid. The signature was invalid, or it was not signed with an Apple submission certificate...

Now all that is left for us to do is formalize the build process and we're good to go. Next time I'll introduce the continuous integration engine called Hudson.

iPhone app distribution made easy - Part 2

Being able to build various distributions in the XCode IDE is great but you have to think about what you're doing very carefully. Thankfully the 3.0 version of the SDK comes with an improved command line build utility called "xcodebuild".

Here's an example of how to build the AppStore distribution:

xcodebuild -target "myAppAppStore" -configuration "DistributionAppStore" -sdk iphoneos2.1

As you'll notice the target, configuration and the sdk to use are being specified. Note: The sdk option is new for the 3.0 sdk and can take either the name or path of the sdk to use.

You can view all of the installed sdks by running the following command:

xcodebuild -showsdks

So now we have the ability to build the distributions without thinking about it. We could put this in a script and call it a day but lets not stop there. Next time we'll zip up the app bundle for submission to the AppStore or AdHoc users.