Working surgery for Watin.Net. All examples were created within Visual Studio 2008 set up for C# language. My aim is to show simple complete examples of working code mainly focused around google's website. By doing this will allow you the user to apply these examples to an actual website for themselves. If you are new to WatiN I suggest you follow the posts in order.

Thursday 9 April 2009

Post Six - On Error grab a screenshot

I read sometime ago of a rival test automation product that boasted that you could configure your auto-generated script to grab a screenshot and save this image to file if an error occurred within your test. This sounded a useful utility to have so I set about writing my own methods to achieve this within watiN. The direction I've taken to manage this task is to use the clipboard to store the screenshot and then write the contents of the clipboard to an image file. In total there are 3 methods to handle this so lets look at the main method first dealing with writing the contents of the clipboard to file.

private static void SaveClipBoardImagetoFile()
{
//Line 1
if (Clipboard.GetDataObject() != null)
{
//Line 2
IDataObject data = Clipboard.GetDataObject();
//Line 3
if (data == null)new ArgumentNullException("data");
//Line 4
if (data.GetDataPresent(DataFormats.Bitmap))
{
//Line 5
using (Bitmap image = (Bitmap)data.GetData(DataFormats.Bitmap, true))
{
//Line 6
string FilePath = DateFormatFileNameUpdate("C:\\temp\\");
try
{
//Line 7
image.Save(FilePath, System.Drawing.Imaging.ImageFormat.Jpeg);
}
catch
{
//Line 8
Directory.CreateDirectory("C:\\Temp");
//Line 9
image.Save(FilePath, System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
}
else
{
MessageBox.Show("The Data In Clipboard is not as image format");
}
}
else
{
MessageBox.Show("The Clipboard was empty");
}
}

So lets look at this method in more detail. The first thing we do 'Line 1' is to check wether the clipboard has any data stored in it, if not we simply show a messagebox to that effect. If we do have data then 'Line 2' creates the clipboard object 'data' and passes into this the clipboard data. 'Line 3' then checks that we have valid data, if not we throw an 'null' exception error. 'Line 4' checks that the data retrieved is in fact of bitmap format, if not then we display a message box to highlight this fact. 'Line 5' we create a bitmap object to hold the image data. We use a 'using' statement here as this is handy for us as it cleans up the bitmap object automatically when exiting the 'using' section. 'Line 6' calls a further method named 'DateFormatFileNameUpdate' passing in the parameter 'C\temp\' whose main job is to append to the file path a date\time stamp followed by the file name of 'ErrorImage.jpg'. This method is detailed more in the next section. Line 7 now attempts to write the image to file as part of a 'try\catch' statement, if the temp directory does not exist an error is returned, we catch this in 'Line 8' and create a directory and then write the image out to file in 'Line 9'.

Now lets look in more detail at the method 'DateFormatFileNameUpdate'.
private static string DateFormatFileNameUpdate(string filepath)
{
//Line 1
string d = DateTime.Now.ToString();
//Line 2
d.Trim();
//Line 3
string v = d.Replace("/", "_");
//Line 4
string v1 = v.Replace(":", "_");
//Line 5
string v2 = v1.Replace(" ", "_");
//Line 6
return filepath + v2 + "_ErrorImage.jpg";
}

This method takes the filepath string, 'C:\temp\' as it's parameter. Line 1 then stores the current system date and time in a string variable 'd'. Line 2 removes any possible spaces from the start or end of variable 'd'. Line 3 then replaces any occurance of the character '/' (forward slash) which is auto generated by the date\time function (which are illegal in a file path) with underscore characters, Line 4 repeats the same process for any ':' (colon character) and Line 5 replaces any spaces with underscores. Line 6 then returns the new file path string, for an example would look like this:
'C:\temp\04_10_2009_15_34_21_ErrorImage.jpg'.

You need to place the following 'using' statements at the head of the 'WorkingExamples' class i.e. just below the watiN using statements to facilitate this new code:
using System;
using System.IO;
using System.Window.Forms;
using System.Drawing;
using System.Threading;

The third method (shown below) shows us how we implement the above 2 methods, 'SaveClipBoardImagetoFile' & 'DateFormatFileNameUpdate', you'll notice that these two methods are both private methods and the 'GrabScreenOnError' is of type public because this is the method we call to implement the screen capture. The 'GrabScreenOnError' method simply loads the google page and takes a screen shot by implementing 'SendKeys' method. Although these methods are designed to work when an error is thrown you don't have to use them simply for this purpose. I show where to place the screen grab call within a try/catch block for error catching purposes.

public static void GrabScreenOnError()
{
//Line 1
IBrowser browser = BrowserFactory.Create(BrowserType.InternetExplorer);
//Line 2
browser.GoTo(Element_ID.GOOGLE_URL);
//Line 3
Thread.Sleep(500);
try
{
//Line 4
SendKeys.SendWait(Element_ID.CTRL + Element_ID.PRINT_SCREEN);
//Line 5
SaveClipBoardImagetoFile();
}
catch (Exception)
{
//Line 6
//SendKeys.SendWait(Element_ID.CTRL + Element_ID.PRINT_SCREEN);
//Thread.Sleep(500);
//SaveClipBoardImagetoFile();
}
finally
{
browser.Dispose();
}
}

So let's expain this method in more detail. Lines 1 & 2 we've used before and should now be familiar with. The first thing thats new is Line 3. Hear we use a built in .Net method called 'Sleep' which needs the using statement we put at the head of the class, 'System.Threading'. This Sleep call allows us to pause the program execution for a number of ms (milliseconds - 1000 milliseconds = 1 second), so Line 3 is pausing for half a second just to ensure we have the google page loaded before we use Line 4 to simulate the key press of 'Alt' & 'PrtSc' buttons on the keyboard. Using the 'Alt' keypress allows us grab the active dialog on screen (hopefully the error message dialog) and not all dialogs displayed, in this example we grab the whole google page. SendKeys again is a built in .Net method to simultate key presses. The 'SendWait' attribute waits until the message is processed i.e. the screen capture is actived. Line 5 calls the 'SaveClipBoardImagetoFile' method discussed earlier. The lines under 'Line 6' (all commented out) is to show where we would normally put the code relating to capturing the screen when an error is thrown.

So how do we get all this to work. Firstly all three methods 'SaveClipBoardImagetoFile', 'DateFormatFileNameUpdate', & 'GrabScreenOnError' should be placed into the 'WorkingExamples' class. Then within the 'main' method of the 'Program' class place the following call to 'WorkingExamples.GrabScreenOnError()' .

One further thing to note is that within the 'GrabScreenOnError' method we use references to the Element_ID class when using the SendKeys call, below is the code you need to place into the Elememt_ID class so we can reference the key press id's. I've supplied you with most of the special keypress codes so you can experiment with other combinations.

//KeyPress
public const string ALT = "%";
public const string CTRL = "^";
public const string SHIFT = "+";
public const string BACKSPACE = "{BACKSPACE}";
public const string BREAK = "{BREAK}";
public const string CAPS_LOCK = "{CAPSLOCK}";
public const string DELETE = "{DELETE}";
public const string DOWN_ARROW = "{DOWN}";
public const string END = "{END}";
public const string ENTER = "{ENTER}";
public const string ESC = "{ESC}";
public const string F1 = "{F1}";
public const string F10 = "{F10}";
public const string F11 = "{F11}";
public const string F12 = "{F12}";
public const string F13 = "{F13}";
public const string F14 = "{F14}";
public const string F15 = "{F15}";
public const string F16 = "{F16}";
public const string F2 = "{F2}";
public const string F3 = "{F3}";
public const string F4 = "{F4}";
public const string F5 = "{F5}";
public const string F6 = "{F6}";
public const string F7 = "{F7}";
public const string F8 = "{F8}";
public const string F9 = "{F9}";
public const string HELP = "{HELP}";
public const string HOME = "{HOME}";
public const string INSERT = "{INSERT}";
public const string LEFT_ARROW = "{LEFT}";
public const string NUM_LOCK = "{NUMLOCK}";
public const string PAGE_DOWN = "{PGDN}";
public const string PAGE_UP = "{PGUP}";
public const string PRINT_SCREEN = "{PRTSC}";
public const string RIGHT_ARROW = "{RIGHT}";
public const string SCROLL_LOCK = "{SCROLLLOCK}";
public const string TAB = "{TAB}";
public const string UP_ARROW = "{UP}";

No comments:

Post a Comment