Search This Blog

Showing posts with label EasyTest. Show all posts
Showing posts with label EasyTest. Show all posts

Wednesday, January 21, 2015

Beware of Windows update KB3025390 as it breaks EasyTest functionality in Internet Explorer 11

We were lucky enough to come across this issue when one day, almost all our internal functional tests (we use our in-house EasyTest engine) for XAF Web UI failed due to the following error:

    Type:       UnauthorizedAccessException
    Message:    Access is denied.

    Data:       0 entries
    Stack trace:

   at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
   at System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(Int32 errorCode)
   at System.Runtime.InteropServices.CustomMarshalers.ExpandoViewOfDispatchEx.DispExInvoke(String pstrMemberName, Int32 MemberDispID, Int32 Flags, Binder pBinder, Object[] aArgs, ParameterModifier[] aModifiers, CultureInfo pCultureInfo, String[] astrNamedParameters)
   at System.Runtime.InteropServices.CustomMarshalers.DispatchExMethodInfo.Invoke(Object pObj, BindingFlags invokeAttr, Binder pBinder, Object[] aParameters, CultureInfo pCulture)
   at System.Runtime.InteropServices.CustomMarshalers.DispatchExPropertyInfo.GetValue(Object pObj, BindingFlags invokeAttr, Binder binder, Object[] aIndex, CultureInfo culture)
   at System.Reflection.PropertyInfo.GetValue(Object obj, Object[] index)
   at DevExpress.ExpressApp.EasyTest.WebAdapter.WebCommandAdapter.<>c__DisplayClasse.<GetIReflectTestControlCore>b__9(Object obj)
   at DevExpress.ExpressApp.EasyTest.WebAdapter.WebCommandAdapter.ExecuteTimeoutFunction(Int32 timeoutMilliseconds, Int32 sleepTime, Predicate`1 predicate, Func`1 onTimeoutPredicate)
   at DevExpress.ExpressApp.EasyTest.WebAdapter.WebCommandAdapter.GetIReflectTestControlCore(String testControlsName, IHTMLDocument2 doc)
   at DevExpress.ExpressApp.EasyTest.WebAdapter.WebCommandAdapter.GetIReflectTestControl(String testControlsName, IHTMLDocument2 doc)
   at DevExpress.ExpressApp.EasyTest.WebAdapter.WebCommandAdapter.UpdateTestControls()
   at DevExpress.ExpressApp.EasyTest.WebAdapter.WebCommandAdapter.WaitForBrowserResponse(Boolean waitPostback, Boolean isSecondCall)
   at DevExpress.ExpressApp.EasyTest.WebAdapter.WebAdapter.CreateCommandAdapter()
   at DevExpress.EasyTest.Framework.TestExecutor.CreateCommandAdapterCore(IApplicationAdapter adapter)
   at DevExpress.EasyTest.Framework.TestExecutor.ExecuteCommands(IApplicationAdapter adapter, String& applicationName)
    InnerException is null

After several hours of researching and googling, we found out the Installation of KB3025390 breaks out-of-process JavaScript execution in IE11 ticket on MS Connect
as well as possible workarounds at https://code.google.com/p/selenium/issues/detail?id=8302

Thursday, August 22, 2013

How to prompt when the user is about to exit a WinForms application

Today I improved  the implementation one of my WinForms examples by changing the code and also by adding functional tests powered by our EasyTest engine.

This example is about displaying confirmation message when the main application window is being closed by a user to avoid accidental closure of the whole application and losing all opened screens:


You might remember this behavior from many browsers, which ask you under similar circumstances.
This is not rocket science (just a single WindowController for you to add), but probably your end-users will appreciate it.

www.devexpress.com/example=E527

The functional test is also quite straightforward and easy to understand for regular human beings:

Thursday, April 18, 2013

EasyTest: Referring to an UI element by its Id rather than by caption when writing a functional test

As you probably know, our functional testing framework - EasyTest, finds or identifies UI elements by their captions by default. This is natural and allows non-developers to easily create functional tests based on what they see on the screen.

However, sometimes there may be several elements with the same caption on the screen or their captions may be too long or inconvenient to use in the script. EasyTest also provides a solution for such scenarios and allows you to use the control's identifier instead of its caption right in the script! Let me demonstrate you how to use this hidden feature.

Step 1. Enable the Dianostic Action in the application configuration file:





Step 2. Navigate to the required UI screen and display the EasyTest Control diagnostic info:





Step 3. Find the required UI element identifier:





Step 4. Use the obtained identifier in the EasyTest script:




The demonstrated functionality is available for WinForms apps only.
Anyway, I hope you will find this small trick helpful!

Monday, November 19, 2012

Getting started with EasyTest (lazy man tutorial)

If you are not using our functional testing framework  - EasyTest yet (if you fall into this category, do not feel bad as you are not alone - our stats (example) show that you are still in the majority:-) ), then this is a good chance to start!

I would like to talk about an internal *AutoTest command that we use to test XAF Code Examples during the initial testing phase internally (before running example-specific tests). This command checks all the navigation items in your app and ensures that list and detail forms can be opened without errors. Not much, but at least it allows you ensure the minimal possible quality of your application before delivering it to the client. Of course, if you wish more, you can choose from dozens of other built-in EasyTest commands or even implement a custom EasyTest command with blackjack and ..., you know:-)

BTW, creating a custom EasyTest command is not that difficult at it appears, expecially taking into account the detailed tutorial and the availability of the full source code of the built-in EasyTest commands:
%ProgramFiles%\DXperience 12.1\Sources\DevExpress.ExpressApp.Modules\DevExpress.ExpressApp.EasyTest.WinAdapter\
%ProgramFiles%\DXperience 12.1\Sources\DevExpress.ExpressApp.Modules\DevExpress.ExpressApp.EasyTest.WebAdapter\
Well, returning to simple things, this is how to use the command I was talking about:
#Timeout 10
#DropDB SimpleProjectManager
#Application SimpleProjectManagerWin
;#Application SimpleProjectManagerWeb
*AutoTest
You can past this stuff (correct app names first, of course!) into the <YourSolutionName>.Module\FunctionalTests\Sample.ets file (it comes with the default XAF solution template) and then right click to choose the Run command in the menu (see this help article for more details).
And here is the result it produces:


View on screencast.com »
Seriously, it is time to start with EasyTest, no more excuses;-)

P.S.
As I mentioned in the beginning, this command is internal and unofficial. We also have not tested it under all scenarios supported by XAF. That said, we may not be able to fix issues with it in a reasonable time frame, so please use it at your own risk, and feel free to modify and test it further to better meet your business requirements.risk. Or better implement normal functional tests for each required screen in your app using the wonderful EasyTest Script Reference.

Thursday, October 25, 2012

"Ideal" development workflow for adding a custom functionality in XAF

In this "short" post I'd like to demonstrate the subject by example of implementing the following suggestion: SystemModules.Link - Exclude objects that are already linked to an object from the Link ListView. Good for our learning purposes, this feature request is representative and small enough at the same time. Technically, we will improve the standard LinkUnlinkController class behavior. Let's start doing real coding!

Implementation/Refactoring

If you look at the current 11.2 code of the controller, you will notice that it is quite difficult to provide your own link View for it:

private void linkAction_OnCustomizePopupWindow(Object sender, CustomizePopupWindowParamsEventArgs args) {
linkListView = (ListView)CreateLinkView();
args.View = linkListView;
args.DialogController = Application.CreateController<LinkDialogController>();
((LinkDialogController)args.DialogController).Initialize(lookUpEditorHelper,
lookUpEditorHelper.CanFilterDataSource(linkListView.CollectionSource, MasterObject));
}

Note that according to this code the link View must be always a ListView. Let's fix this by adding more flexibility as follows:

private void linkAction_OnCustomizePopupWindow(Object sender, CustomizePopupWindowParamsEventArgs args) {
View linkView = CreateLinkView();
args.View = linkView;
linkListView = linkView as ListView;
if (linkListView != null && lookUpEditorHelper != null) {
LinkDialogController dialogController = Application.CreateController<LinkDialogController>();
dialogController.Initialize(lookUpEditorHelper, lookUpEditorHelper.CanFilterDataSource(linkListView.CollectionSource, MasterObject));
args.DialogController = dialogController;
}
}

As you see, I removed the direct cast to ListView and also slightly refactored the rest code. Apparently, now the linkListView variable must be checked on null before using.

If you look at the current CreateLinkView method code, you will notice that it creates the link View of the ListView type only. Since we want to provide the capability to create the link View of an arbitrary View type (e.g., check out this ticket for a real business scenario), we can refactor the method by introducing the event and also moving the default ListView creation code into a separate method:

protected virtual View CreateLinkView() {
CustomCreateLinkViewEventArgs customArgs = new CustomCreateLinkViewEventArgs(View);
OnCustomCreateLinkView(customArgs);
if (!customArgs.Handled || customArgs.LinkView == null)
return CreateLinkViewCore();
return customArgs.LinkView;
}
protected virtual void OnCustomCreateLinkView(CustomCreateLinkViewEventArgs customArgs) {
if (CustomCreateLinkView != null)
CustomCreateLinkView(this, customArgs);
}

The new event and its arguments declarations will look as follows:

public event EventHandler<CustomCreateLinkViewEventArgs> CustomCreateLinkView;

public class CustomCreateLinkViewEventArgs : HandledEventArgs {
private ListView sourceViewCore;
public CustomCreateLinkViewEventArgs(ListView sourceView) {
sourceViewCore = sourceView;
}
public ListView SourceView { get { return sourceViewCore; } }
public View LinkView { get; set; }
}


To complete support of custom link Views, we need to slightly refactor the Link method code, because it currently takes selected objects from the default ListView only:

protected virtual void Link(PopupWindowShowActionExecuteEventArgs args) {
LinkObjects(args.PopupWindow.View.SelectedObjects);
}

My refactored code is shown below:

protected virtual void Link(PopupWindowShowActionExecuteEventArgs args) {
QueryLinkObjectsEventArgs customArgs = new QueryLinkObjectsEventArgs(args.PopupWindow);
OnQueryLinkObjects(customArgs);
IList linkObjects = customArgs.LinkObjects;
if (!customArgs.Handled && linkListView != null)
linkObjects = linkListView.SelectedObjects;
LinkObjects(linkObjects);
}
protected virtual void OnQueryLinkObjects(QueryLinkObjectsEventArgs customArgs) {
if (QueryLinkObjects != null)
QueryLinkObjects(this, customArgs);
}

Here the QueryLinkObjects event and its arguments look as follows:

public event EventHandler<QueryLinkObjectsEventArgs> QueryLinkObjects;
public class QueryLinkObjectsEventArgs : HandledEventArgs {
private Window linkWindowCore;
public QueryLinkObjectsEventArgs(Window linkWindow) {
linkWindowCore = linkWindow;
}
public Window LinkWindow {
get { return linkWindowCore; }
}
public IList LinkObjects { get; set; }
}

So, a guy who wants to implement a custom link View will have to handle these two events, provide their respective LinkView and LinkObjects parameters and do not forget to set the important Handled parameter to True.

We are now done with the first part and are ready to implement the main functionality - excluding already linked objects from the link View. Apparently, we need to modify the newly introduced CreateLinkViewCore method for that purpose. Since we are creating a ListView in this method, we need to add a criterion to its CollectionSource, as described in this help article from our docs:

if(MasterObject != null) {
CriteriaOperator associatedCollectionCriteria =
ObjectSpace.GetAssociatedCollectionCriteria(MasterObject, ((PropertyCollectionSource)View.CollectionSource).MemberInfo);
result.CollectionSource.Criteria[CriteriaKeyForLinkView] = new NotOperator(associatedCollectionCriteria);
}

As you see, I just took association criteria and then inverted it.

It seems that we are done with our main implementation and now it is time to check whether this code ever works. The easiest way to do this is to run our MainDemo application and test the improved Link functionality with Contact and its Tasks list:

Linkunlinktest

Thanks God, my code worked like a sharm in both Windows Forms and ASP.NET applications. Some of you may think that we are now fully done, but in fact we are only in the middle of our path... Why? The answer is simple - we must ensure that the code we just wrote will work fine in future versions of our product, preferably without any input from God.

Unit Testing

The best way to ensure this is to cover the implemented functionality with unit and functional tests. I strongly believe that it is simply damn wrong and plain stupid not to do this (no mercy) and as a result manually test this functionality each and every release in the future. Writing tests will also make you a better developer.

Fortunately for me (and for you too!), the developers of our Core team already had some unit tests for LinkUnlinkController in the LinkUnlinkControllerTests class and my task is to just add a few test methods to cover my code. Practically, that means that I do not need to create a required testing infrustructure from scratch and can just reuse existing test objects and probably grab some example code blocks from other tests. Another good thing is that I can make use of existing base test classes and mocks like BaseXafTest, TestApplication, etc. that provide useful methods and allow me to write platform-independent tests. Let's demonstrate this by an example.

First, I will extend the LinkUnlinkController descendant used only for tests with a couple of overridden methods to provide counters for my events - I want to ensure that they actually fire when needed and their arguments are taken into account:

public class LinkUnlinkControllerForTests : LinkUnlinkController {
public int CustomCreateLinkViewEventCounter = 0;
public int QueryLinkObjectsEventCounter = 0;
public LinkUnlinkControllerForTests() : base() { }
protected override void OnCustomCreateLinkView(CustomCreateLinkViewEventArgs customArgs) {
base.OnCustomCreateLinkView(customArgs);
CustomCreateLinkViewEventCounter++;
}
protected override void OnQueryLinkObjects(QueryLinkObjectsEventArgs customArgs) {
base.OnQueryLinkObjects(customArgs);
QueryLinkObjectsEventCounter++;
}
}

This is a very common practice, especially when we need to hook up into some protected members or disable/mock certain functionality for tests only. To give you one more example, the TestApplication class I mentioned earlier is a descendant of XafApplication that overrides its methods for tests, e.g. provides platform-agnostic TestListEditor and TestLayoutManager instead of real platform-dependent classes.

Now we are ready to write our first test method for the functionality implemented earlier:

[Test]
public void TestCustomCreateLinkViewEvent() {
RegisterTypesForModel(typeof(Incident), typeof(Message));
CollectionSourceBase linkedMessagesDS = CreateCollectionSource(incident, "Messages");
TestApplication application = new TestApplication(this, modelApplication);
LinkUnlinkControllerForTests controller = new LinkUnlinkControllerForTests();
controller.Application = application;
ListView sourceListView = application.CreateListView(GetListView<Message>(), linkedMessagesDS, false);
sourceListView.CreateControls();
controller.SetView(sourceListView);
Assert.AreEqual(controller.LinkAction.GetPopupWindowParams().View.GetType(), typeof(ListView));
Assert.AreEqual(1, controller.CustomCreateLinkViewEventCounter);
bool handled = false;
EventHandler<CustomCreateLinkViewEventArgs> customCreateLinkViewEventHandler = delegate(object sender, CustomCreateLinkViewEventArgs args) {
Assert.AreEqual(args.SourceView, sourceListView);
args.LinkView = new DashboardView(ObjectSpace, application, false);
args.Handled = handled;
};
controller.CustomCreateLinkView += customCreateLinkViewEventHandler;
Assert.AreEqual(controller.LinkAction.GetPopupWindowParams().View.GetType(), typeof(ListView));
Assert.AreEqual(2, controller.CustomCreateLinkViewEventCounter);
handled = true;
Assert.AreEqual(controller.LinkAction.GetPopupWindowParams().View.GetType(), typeof(DashboardView));
Assert.AreEqual(3, controller.CustomCreateLinkViewEventCounter);
controller.CustomCreateLinkView -= customCreateLinkViewEventHandler;
}

It's a bit too long, but I need to test all possible combinations.

The next two test methods will be a way more complex and longer:

[Test]
public void TestQueryLinkObjectsEventAndExcludeLinkedObjectsNoServerMode() {
TestQueryLinkObjectsEventAndExcludeLinkedObjectsCore(false);
}
[Test]
public void TestQueryLinkObjectsEventAndExcludeLinkedObjectsServerMode() {
TestQueryLinkObjectsEventAndExcludeLinkedObjectsCore(true);
}

private void TestQueryLinkObjectsEventAndExcludeLinkedObjectsCore(bool useServerMode) {
RegisterTypesForModel(typeof(Incident), typeof(Message));
CollectionSourceBase linkedMessagesDS = CreateCollectionSource(incident, "Messages");
TestApplication application = new TestApplication(this, modelApplication);
application.Model.Views.DefaultListEditor = typeof(TestListEditor);
application.Model.Options.UseServerMode = useServerMode;
LinkUnlinkControllerForTests controller = new LinkUnlinkControllerForTests();
controller.Application = application;
ListView sourceListView = application.CreateListView(GetListView<Message>(), linkedMessagesDS, false);
sourceListView.CreateControls();
controller.SetView(sourceListView);
CustomizePopupWindowParamsEventArgs windowParams = controller.LinkAction.GetPopupWindowParams();
Assert.AreEqual(1, linkedMessagesDS.GetCount());
Assert.AreEqual(windowParams.View.GetType(), typeof(ListView));
Assert.AreEqual(0, controller.QueryLinkObjectsEventCounter);
bool handled = false;
Window linkWindow = new Window(application, "", null, false, true);
EventHandler<QueryLinkObjectsEventArgs> queryLinkObjectsEventHandler = delegate(object sender, QueryLinkObjectsEventArgs args) {
args.LinkObjects = new object[0];
args.Handled = handled;
Assert.AreEqual(linkWindow, args.LinkWindow);
Assert.AreEqual(windowParams.View, args.LinkWindow.View);
};
controller.QueryLinkObjects += queryLinkObjectsEventHandler;
ListView linkListView = ((ListView)windowParams.View);
CollectionSourceBase messagesToLinkDS = linkListView.CollectionSource;
Assert.IsTrue(messagesToLinkDS.Criteria.ContainsKey(LinkUnlinkController.CriteriaKeyForLinkView));
Assert.AreEqual(0, messagesToLinkDS.GetCount());
Message messageToLink = new Message(ObjectSpace.Session);
ObjectSpace.CommitChanges();
messagesToLinkDS.Reload();
Assert.AreEqual(1, messagesToLinkDS.GetCount());
linkWindow.SetView(linkListView);
linkListView.CreateControls();
linkListView.Editor.FocusedObject = messageToLink;
controller.LinkAction.DoExecute(linkWindow);
Assert.AreEqual(1, controller.QueryLinkObjectsEventCounter);
ObjectSpace.CommitChanges();
incident.Reload();
Assert.AreEqual(2, incident.Messages.Count);
handled = true;
messageToLink = new Message(ObjectSpace.Session);
ObjectSpace.CommitChanges();
linkListView.Editor.FocusedObject = messageToLink;
controller.LinkAction.DoExecute(linkWindow);
Assert.AreEqual(2, controller.QueryLinkObjectsEventCounter);
ObjectSpace.CommitChanges();
incident.Reload();
Assert.AreEqual(2, incident.Messages.Count);
controller.QueryLinkObjects -= queryLinkObjectsEventHandler;
}

However, these methods fully test the entire link functionality from the beginning to end. It is also done under both server-side and client binding modes.

Did I mention that writing good unit tests once and for all will help you avoid problems and PITA in the future?

Functional Testing

Finally, to ensure that everything will operate as expected under real circumstances, I will add functional tests. As you probably know, these kind of tests is powered by our EasyTest functional testing framework. With EasyTest I can ensure the correctness of both Windows Forms and ASP.NET applications using a single test script:

#Aplication AppStudioTestWeb
#Application AppStudioTestWin

*Action Navigation(Incident)
*ProcessRecord
Описание = Test Incident

*Action Versions

*Action Versions.Link
*CheckTable
Columns = Name
Row = 1.0
Row = 2.0
*ProcessRecord
Name = 2.0

*CheckTable Versions
Columns = Name
Row = 2.0

*Action Versions.Link
*CheckTable
Columns = Name
Row = 1.0
*Action Cancel

*SelectRecords Versions
Columns = Name
Row = 2.0
*Action Versions.Unlink

*HandleDialog
Respond = Yes

!ProcessRecord Versions
Name = 2.0

That is it. Now I am sure that the code I added will not be broken one day. Or at least I will know if that happens from failed tests.

I hope you find this information interesting as the process I described above will help you ensure a better quality of your XAF applications. I also want to explicitly mention that this process is the same in our team when developing features. The only thing I did not mention is that we also do a manual testing of some scenarios before releasing a new product version.

Forgot to say, that the feature I described here will be available in XAF 12.1. I also hope you also liked this small addition to the framework.

See Also
Best practices of creating reusable XAF modules by example of a View Variants module extension
eXpressApp Framework > Task-Based Help > Testing