How to implement a custom EasyTest command

Related Posts:
Thinking of Testing… Enter EasyTest
How to run EasyTest scripts from code
EasyTest and test data

EasyTest has a set of predefined commands that cover most of the use cases. To support the remaining cases there is a very easy way to write custom commands. Our Code Central already has a sample demonstrating that and today I am going to step through it.

Lets assume we have a Product with PublishDate and Status properties. The Status property can take the following values: Valid, Invalid. We want to test the following logic: If PublishDate is less than the system date + 10 days then the Status must have a value of “Invalid”. If we write the code we will end up with something like (using the new

*FillForm
 Department = Sales Department

The test will pass if we run it today. However if we try to run it after a few days it will fail (because the Published date is fixed the Status will become Valid).

To overcome the problem we can create a custom command. All commands have to derive from DevExpress.EasyTest.Framework.Command class and implement the InternalExecute method. You probably find it easier to write the script in pseudo code before implementing the InternalExecute method .

#DropDB AdditionalCommandsEasyTest 
#Application AdditionalCommandsWin
*Action Navigation(Product) 
*Action New 
;---Custom Command 
*FillDateTimeValue Publish 
 Culture = en-US 
 Days = -1 
 Hours = 1 
;---End Custom Command 
*Action Save And Close 
*CheckTable Product 
 Columns = Status 
 Row = Invalid

As you see we have replaced the FillForm command with our custom FillDateTimeValue command and we have used 4 parameters. The main parameter is the name of the property, which is followed by Culture parameter along with Days and Hours to overcome any localization problems.

Now we are ready to implement our custom command.

    public class FillDateTimeValueCommand : Command{

        private int GetIntegerParameterValue(string parameterName) {

            int result = 0;

            Parameter parameter = Parameters[parameterName];

            if (parameter != null){

                if(!Int32.TryParse(parameter.Value, out result)) {

                    throw new CommandException(string.Format("'{0}' value is incorrect", parameterName), StartPosition);

                }

            }

            return result;

        }

        protected override void InternalExecute(ICommandAdapter adapter){

            //Get the parameters

            int deltaDays = GetIntegerParameterValue("Days");

            int deltaHours = GetIntegerParameterValue("Hours");

            int deltaMinutes = GetIntegerParameterValue("Minutes");

            CultureInfo currentCulture = GetCurrentCulture();

            string fieldName = Parameters.MainParameter.Value;

            //Create the DataTime values

            string dateTimeValue = GetDateTimeValue(deltaDays, deltaHours, deltaMinutes, currentCulture);

            //Get The control

            ITestControl testControl = adapter.CreateTestControl(TestControlType.Field, fieldName);

            //Apply the datetime value

            testControl.GetInterface<IControlText>().Text = dateTimeValue;

        }

 

        CultureInfo GetCurrentCulture() {

            string cultureName = Parameters["Culture"] != null ? Parameters["Culture"].Value : null;

            return cultureName != null ? CultureInfo.GetCultureInfo(cultureName) : null;

        }

 

        string GetDateTimeValue(int deltaDays, int deltaHours, int deltaMinutes, CultureInfo currentCulture) {

            DateTime dateTime = DateTime.Now.Add(new TimeSpan(deltaDays, deltaHours, deltaMinutes, 0));

            return currentCulture != null ? dateTime.ToString(currentCulture) : dateTime.ToString();

        }

    }

 

The InternalExecute method  implementation is very simple. First we get the parameters out of ParametersList collection and calculate the DateTime value according to our logic. The CreateTestControl method finds the original control by its caption and wraps it around an ITestControl interface. To communicate with the control the ITestControl provides the generic GetInterface<T> method.

 

The supported interfaces for the method live inside EasyTest namespace.

 

image

 

It is very rare but it is possible to extend an ITestControl with more interfaces. But that is another blog subject.

 

Register the command

In order EasyTest to recognize the FillDateTimeValueCommand we need to register it. The WinAdapter, WebAdapter classes are responsible for running the application under test. They are also handling the initialization of the CommandAdapter hence its the right place to register our custom commands. What we need is to to replace the default WinAdapter, WebAdapter classes. This can be accomplished by creating a new Class Library project and adding a class like this:

 

    public class ExtendedWinAdapter : WinAdapter{

        public override void RegisterCommands(DevExpress.EasyTest.Framework.IRegisterCommand registrator){

            base.RegisterCommands(registrator);

            registrator.RegisterCommand("FillDateTimeValue", typeof(FillDateTimeValueCommand));

        }

    }

 

In the same project open AssemblyInfo.cs and register the adapter there as well.

 

[assembly: Adapter(typeof(ExtendedAdapters.ExtendedWinAdapter))]

 

Finally modify your scripts Config.xml to point to the new adapter.

 

image

 

Debugging the command

a) Set as StartUp project the one that contains the command

image
b) Set the breakpoints in the code 

image


c) Open project properties and modify the (Start external program/Command line arguments) under debug tab. The first should point to your TestExecutor executable the latter to the path of the script that uses the command.

 

 

 

That’s it for the custom commands! What do you think? Should we go through couple of more examples?

2 comment(s)
Kim_Schmidt

Hi Tolis,

great post!

The only thing I stumbled over, was your last comment, about how to debug. Am I right, that you've written "YOUR TestExecuter" because I have to build my own TestExecutor? Within screenshot you posted the "Start external program" property points to a compiled debug version of the TestExecutor.

Because if I use the shipped "DevExpress XXXX.X\eXpressApp Framework\Tools\EasyTest\TestExecutor.vXX.X.exe" it doesn't work. We had to build our own TestExecutor, because the sources aren't included in DevExpress setup.

If its right, this isn't quite clear reading your blog.

Best regards,

Kim

2 August, 2011
Apostolis Bekiaris (DevExpress)

Hi Kim,

You got me! I am using a recompiled version, however there is no need to recompile the TestExecutor. I will correct the screenshot ASAP.

2 August, 2011

Please login or register to post comments.