Friday, December 18, 2009

Design of Selenium tests for ASP.NET: DSL (Domain Specific Language) for Acceptance Web Tests

A large amount of people (testers, managers and even customers) can contribute Test Cases in acceptance test suite for your project, but not all do have Visual Studio to write and compile pure unit tests like this:

     [Test]
public void LoginSuccessWithCorrectPassword()
{
Start
.GoToLoginPage()
.EnterCredentials("admin", "god")
.Login();
}

To allow them to create tests it is needed to invent some kind of DSL in the simple to edit format – TXT for example. But also it is needed to be able run these test as regular nunit tests. TestCaseSource attribute is exactly what is needed – it will dynamically create test case for each TXT file in folder.

   [TestFixture]
public class ScriptTest : TestBase
{
[Test, TestCaseSource("TestCases")]
public void DivideTest(CommandSet commandSet)
{
object currentFlow = Start;

foreach (var command in commandSet.Commands)
{

var method = currentFlow.GetType().GetMethod(command.Name);

try
{
var parameters = command.Parameters.ToArray();

if(parameters.Length == 0)
{
parameters = null;
}

currentFlow = method.Invoke(currentFlow, parameters);
}
catch (Exception ex)
{

throw new Exception(string.Format("Error while executing command {0}", command.Name), ex);
}

}
}

public IEnumerable TestCases
{
get
{
return (from fileName in Directory.GetFiles(Configuration.ScriptsPath)
let contents = File.ReadAllText(fileName)
select new object[] {GetCommand(fileName, contents)})
.Cast<object>()
.ToList();
}
}

private static CommandSet GetCommand(string fileName, string commands)
{
var set = new CommandSet { Name = fileName };

var lines = commands.Split('\n');

lines = lines.Select(l => l.Replace("\r", "")).ToArray();

foreach (var line in lines)
{
var commandStrings = line.Split(' ');

var name = commandStrings[0];
var parameters = commandStrings.Skip(1);

var command = new Command() { Name = name };
command.Parameters.AddRange(parameters.Cast<object>());

set.Commands.Add(command);
}

return set;
}
}

Now just it is only needed to place TXT files in Scripts folder. Format of scripts is simple:

CheckNameOnLoginPage.txt

LoginAndGoToHomePage

AssertUserName admin

or

LoginSuccessWithCorrectPassword.txt

GoToLoginPage

EnterCredentials admin god

Login

The result in nunit runner will be like this:

NUnit result with test case marked with TestCaseSource

Of course all Flows are needed to be implemented before usage of them in DSL files, but the advantage of such approach is that the people who will write tests do not have to know about aspects of interacting with web page – ids of controls, waiting for ajax requests, URLs of pages etc.

It would be very handful to create "help" system, which will describe all Flows with its parameters. It is easy to generate with help of Reflection.

All sources are available in design-of-selenium-tests-for-asp-net sample solution.

0 comments: