Dustin Gibson

Automate Project (C#, Python, JavaScript)


This project is essentially an automation framework built on top of selenium Python bindings and uses a GUI interface written in C# to write and manage test cases. There are two major parts: creating test cases (C#) and processing test cases (Python).

The implementation of elements are separated from building the cases. As a result, there is only one point of maintenance. Users can add steps implemented in the interface section. These can range from clicking a button on the web page to verifying a piece of text.

After the test case is put together, the user can run the test case. After the test case is completed, users can view the results, which is compiled together in HTML format.

Code samples are located at the bottom of this page

UI Source Code, Selenium Toolkit Source, Sample Project



To Do:
  • Connect to Database and Run SQL Queries
  • Categorize Test Cases with Tags
  • Combine Reports
  • Version Control for Multiple Users
  • Backup Utility


Motivation:
I worked professionally QA automation and we used selenium with Python bindings. But we’re required to use a framework servilely lacking in support and regular updates. I wanted to create my own framework.

Code Details
  • XML and FTP – Input for test cases uses XML. FTP protocol allows managing and running test cases across networks.
  • Code Conversion – The Python part of the code converts test case XML into runnable Python code. This code uses selenium to do all of the automation and generates the reports.
  • Procedural Design – Due to the scope of the code conversion part of the application, I stuck with the procedural design paradigm. The requirements does not lend itself to the object-oriented paradigm as well.
  • Object Oriented Design – There are some elements of object oriented design in the C# part. Because of my lack of experience at the time, I didn’t use very many design patterns. There are a few examples of Factory and Adapter pattern for loading up test cases and interfaces.


Challenges and Lessons Learned
  • By far, the biggest lesson I learned is to favor databases over raw XML. I went with XML since it was easy to manage and carry around. Thanks to technologies like SQL Lite, that is not true anymore. I should have went with SQL Lite.
  • Another huge lesson I learned is to use TCP or HTTP protocols over FTP. FTP is good at transferring files, but abysmally bad when sending short messages. I should have used TCP over FTP.
  • Designing this application made me appreciate design patterns more. Upon reviewing the code, there were definitely areas that could have used more design. For an example: I had to completely redesign the way the application inserts and updates test cases in the XML from scratch at one point. I could have used the strategy pattern to save days of work.


Code Samples

Interface Drag and Drop (C#)

			
				

private void interfaceTreeItemDrop(object sender, DragEventArgs e)
{
	Point targetPoint = interfaceTree.PointToClient(new Point(e.X,e.Y));
	TreeNode targetNode = interfaceTree.GetNodeAt(targetPoint);
	TreeNode draggedNode = (TreeNode)e.Data.GetData(typeof(TreeNode));
	String xpath = "/project";
	String draggedXpath = "/project";
	String[] targetPaths = targetNode.FullPath.Split('\\');
	String[] draggedPaths = draggedNode.FullPath.Split('\\');
	String targetName = targetNode.Text;
	String draggedName = draggedNode.Text;
	for (int i = 1; i < targetPaths.Count(); i++)
		xpath += "/element[@name='" + targetPaths[i] + "']";
	for (int j = 1; j < targetPaths.Count(); j++)
		draggedXpath += "/element[@name='" + draggedPaths[j] + "']";
	if (!draggedNode.Equals(targetNode) && !isParent(draggedNode,targetNode))
	{
		if (e.Effect == DragDropEffects.Move && dragType == "parent")
		{
			if(targetNode.ImageKey == "container")
			{
				String[] prevPath = targetNode.FullPath.Split('\\');
				swapXmlNodes(draggedNode.FullPath.Split('\\'), targetNode.FullPath.Split('\\'));
				clearTree();
				dragType = "none";
				reselectNode(prevPath);
			}
			//RULE #5
		}
		else if (e.Effect == DragDropEffects.Move && dragType == "sibling")
		{
			String[] prevPath = draggedNode.FullPath.Split('\\');
			swapXmlSibling(draggedNode.FullPath.Split('\\'), targetNode.FullPath.Split('\\'));
			String closestEle;
			TreeNode parentDragged = draggedNode.Parent;
			for (int i = 0; i < parentDragged.Nodes.Count; i++)
			{
				if (parentDragged.Nodes[i].ImageKey == "element")
				{
					closestEle = parentDragged.Nodes[i].FullPath;
					if (parentDragged.Nodes[i].Text.Equals(draggedNode.Text))
						break;
				}
				else
				{
					//if (parentDragged.Nodes[i].
				}
			}
			//if(draggedNode.ImageKey == "element")
			reselectNode(draggedNode.FullPath.Split('\\'));
			List newNodeList = new List();
			clearTree();
			dragType = "none";
			reselectNode(prevPath);
			//RULE #7
		}
		targetNode.Expand();
	}
}