Passing objects from test case to test case

Best practices, code snippets for common functionality, examples, and guidelines.
robert.altman
Posts: 8
Joined: Thu Feb 23, 2017 10:54 pm

Passing objects from test case to test case

Post by robert.altman » Thu Feb 23, 2017 11:03 pm

So I'm trying to pass an object (Container, Text, ComboBox, etc.) from one test case to another.

I have, lets say 10 test cases, that need to be separate, but are similar. Let's say they all have a button in common. I don't want to add the button to my repository.

I create the button in user code such as: Button startButton = RxPath

How can I pass this Button object to the next test case?

I've tried everything from global parameters to module variables, however, they only seem to work if they are strings.

I've tried creating a User Code class (Variables.cs), where I assign the Button, but once the actual test case executes, the value of the Button returns to null;

Is there any way to do this or am I wasting my time?

User avatar
odklizec
Ranorex Guru
Ranorex Guru
Posts: 7470
Joined: Mon Aug 13, 2012 9:54 am
Location: Zilina, Slovakia

Re: Passing objects from test case to test case

Post by odklizec » Fri Feb 24, 2017 12:51 pm

Hi,

Is there a reason why you can't use repository? Not using repository and creating your own system of storing and processing GUI elements is, in my opinion, huge step back. Not to mention storing xpaths somewhere in code is a certain way to mess. It's much better to keep all elements stored and managed in repository.

To pass elements to code you have to use RepoItemInfo or Adapter class. If you insist on using xpath strings, then you will have to find the elements via 'Find' (or equivalent) method, which accepts xpath (string).
Pavel Kudrys
Ranorex explorer at Descartes Systems

Please add these details to your questions:
  • Ranorex Snapshot. Learn how to create one >here<
  • Ranorex xPath of problematic element(s)
  • Ranorex version
  • OS version
  • HW configuration

robert.altman
Posts: 8
Joined: Thu Feb 23, 2017 10:54 pm

Re: Passing objects from test case to test case

Post by robert.altman » Fri Feb 24, 2017 3:06 pm

Odklizec,

Thanks for your reply.
I am using the repository, however only to store "views" of our application. It's a WPF application, which leads to there being lots of layers. Think of a "view" as a layer in the application that contains a text box for example.
We do not want to add every button and text box, etc to the repo due to the quantity. The app is very in depth and we already have many repo items using only these "views". They are comprised of Element and Container objects.

We are not actually storing RxPaths in code. It was just an example.

This is what I am using to find the objects of interest, contained in a certain view.

cuObject = view.FindSingle(".//text[@automationid='" + autoID + "']");

cuUobject in this case is a text object (Text cuObject)
view represents an element of the view where I want to search

Now, the problem is that most of these views are buried deep in the application so it takes a while to create them. Since we have 100's of test cases that use the same views, it would be ideal if we could create the views once (in a Variables.cs for example), and then access them from each test case, rather than having each test case re-create the view.

I've tried the global parameter/module variable binding method, however it only works with strings in my experience. If I change the variable's code from 'string variable = ' to 'Container variable = ' , and then try to assign a container object to the variable, I get this error: Failed to set value '' to variable 'metaData'.
String was not recognized as a valid Container.


So instead of:
string _variable = "";
[TestVariable("8a1bc350-e036-4d98-9599-bfbfd469a539")]
public string variable
{
get { return _variable; }
set { _variable = value; }
}

I change to:
Container _variable = null;
[TestVariable("8a1bc350-e036-4d98-9599-bfbfd469a539")]
public Container variable
{
get { return _variable; }
set { _variable = value; }
}

And assign using:
void ITestModule.Run()
{
variable = repo.ConfigurationUtility.ProjectManagement.Grids.ProjectMetaData;
// doesn't have to be assigned repo item, but this is the easiest way to show example
}

This fails with the above mentioned error.

krstcs
Posts: 2683
Joined: Tue Feb 07, 2012 4:14 pm
Location: Austin, Texas, USA

Re: Passing objects from test case to test case

Post by krstcs » Fri Feb 24, 2017 7:04 pm

Robert,

I think you may be trying to reinvent the wheel here. Ranorex's repo handles variables as well, so you can make child elements that are variablized.

For example:
Upload.png
Here, "$listitem" is replaced at runtime with the value that is bound to it, and the xpath is using regex to find the value inside a listitem's text attribute.

This is the appropriate way to handle variablized elements in your code. You do not need to re-write the functionality that is already there.
You do not have the required permissions to view the files attached to this post.
Shortcuts usually aren't...

robert.altman
Posts: 8
Joined: Thu Feb 23, 2017 10:54 pm

Re: Passing objects from test case to test case

Post by robert.altman » Fri Feb 24, 2017 7:34 pm

I guess I'm not stating my intention correctly.

I have a repo with various containers and elements.

When I do this:
Container target = repo.Application.target;
Mouse.MoveTo(target);

Ranorex gets the repo item, and using it's path, finds said item in the application and moves the mouse to it.
This can take some time depending on how deep this container is buried in the WPF application. For argument's sake, let's say it's 10 seconds.

Now, if later on in the test script I want to move the mouse back to that same container, I can just do this:

Mouse.MoveTo(target);

This time it only takes one second, because 'target' has already been found in the application once.

The problem is that when I move on to the next test case (new test module) I have to re-create the 'target' again, spending another 10 seconds finding it again in the application.

If I could pass that 'target' to the next test case, I wouldn't have to re-create anything because it's already found and stored in the variable.

I know I can pass it to another module, as long as it's in the same test case.
Fore instance, TestModule1.cs can make a call to a method in TestModule2.cs that has required arguments like this:

TestModule1.cs
--------------------------

public void DoStuff()
{
Container target = repo.Application.target;
TestModule2 module2 = new TestModule2();
module2.DoMoreStuff(target);
}

TestModule2.cs
---------------------------
public void DoMoreStuff(Container target)
{
Mouse.MoveTo(target);
}


This relies on the fact that the variable was created in TestModule1, which is waiting, while TestModule2 does it's thing, and they are both in the same test case.

I want to be able to pass the variable from TestModule1 to TestModule2, when they are in separate test cases. Much like you can create a string variable and bind it from test case to test case using global parameters.

Like mentioned earlier, creating a string variable and crudely changing 'string' to 'Container' doesn't work. It will only accept 'string' as a variable type.

I hope that this clears up my intention.

krstcs
Posts: 2683
Joined: Tue Feb 07, 2012 4:14 pm
Location: Austin, Texas, USA

Re: Passing objects from test case to test case

Post by krstcs » Fri Feb 24, 2017 9:26 pm

OK. A couple of things:

1. The first time Ranorex tries to find something, it will search based on the given XPath. If the XPath is very generic, or contains a lot of wild-cards (?, *, //) then it will take longer. Also, if you have an XPath prefaced with //, Ranorex will search all paths under the parent until it finds the element. This can take time. The more specific your path is, the faster it will be.

2. After Ranorex finds an item, it caches the on-screen location, which makes finding the item later much faster.

3. Using Unique Ids ("text[#'myText']") in your path will negate number 1 above and will be VERY fast. You should use these whenever possible.


In your case, you most likely have paths that are not unique enough and require Ranorex to search for the final element for much longer.

It would help us if you could post a Ranorex Snapshot (not a screenshot!) of your AUT and some of the XPaths you are using. We might be able to help you find a way to make the paths better.


In my opinion, though, it is better to make the repository more complicated than to make your tests more complicated. Make the paths as unique as possible, even making them very long if needed. It will save you a lot of time and hassle.
Shortcuts usually aren't...

robert.altman
Posts: 8
Joined: Thu Feb 23, 2017 10:54 pm

Re: Passing objects from test case to test case

Post by robert.altman » Fri Feb 24, 2017 10:35 pm

krstcs,

Thanks for your answer.

I'll have to find out about the snapshot, but the xPaths are very long, to say the least.

The application is still under development, so the repo items xPaths can change with each release, which would cause a lot of maintenance of/in the repo.

However,
Even if I have every button, text, etc, in the repo, those items still have to get initialized once per test case. This is what I'm trying to avoid.

How can I initialize the repo item in test case 1, and push it to test case 2, and so on, without having to re-find and re-cache it with each test case...?

krstcs
Posts: 2683
Joined: Tue Feb 07, 2012 4:14 pm
Location: Austin, Texas, USA

Re: Passing objects from test case to test case

Post by krstcs » Fri Feb 24, 2017 10:57 pm

I would suggest heavy use of "Rooted Folders" in your repo. Ranorex would cache the element represented by the folder, so all child repo elements would have to be child UI elements. This would mean that Ranorex would find the parent once, then the children would be calculated from that parent's cached location instead of from the root form.


I know that some applications are very cumbersome, especially for repository maintenance, but for me, that is the easiest place to make changes. And in my experience it really isn't that bad if you have it set up well.


As far as getting it faster with the way you are doing it, the only thing I can suggest is to make sure that the path you are passing in to the Find method is as specific as possible. For example, assuming myform is the top-level repo object:

/form[@title='myform']
....//button[@text='OK']

This may take a long time to find the OK button the first time, while:

....//container[@accessiblename='mycontainer']/button[@text='OK']

will be faster, although maybe not by much.

But,
....//container[#'mycontainer']/button[@text='OK']
will be almost instant, every time.

I hope this helps. With Ranorex it's all about the XPath...
Shortcuts usually aren't...

robert.altman
Posts: 8
Joined: Thu Feb 23, 2017 10:54 pm

Re: Passing objects from test case to test case

Post by robert.altman » Mon Feb 27, 2017 3:10 pm

Thanks again for the reply.

The rooted folder may be something for me to try out. We originally had rooted folders, but they presented a problem do to how dynamic the program is and also the fact it's still under dev.
The xPaths are changing in a lot of areas with each release of the application. I guess that's the price to pay when you try to automate software that's not finished. Lot's of redoing and using the spy tool to get new xPaths for already existing repo items.

If the rooted folder doesn't help, I'll just have to deal with it. It seems there isn't any way to pass run-time created objects as variables from test case to test case.

tvu
Posts: 195
Joined: Tue Apr 07, 2015 10:47 pm

Re: Passing objects from test case to test case

Post by tvu » Tue Feb 28, 2017 6:13 am

I use public static variables to pass objects between recordings and I imagine you can do the same between test cases. You just have to declare the static variables on a more global scope then the test cases.

I create a Ranorex code module that defines the variables and then references them from my recording. Here's an example:

Code: Select all

    public class ParameterPassingStaticVariables : ITestModule
    {
    	public static List<string> listOfStrings = null;
        
        /// <summary>
        /// Constructs a new instance.
        /// </summary>
        public ParameterPassingStaticVariables()
        {
            // Do not delete - a parameterless constructor is required!
        }

        /// <summary>
        /// Performs the playback of actions in this module.
        /// </summary>
        /// <remarks>You should not call this method directly, instead pass the module
        /// instance to the <see cref="TestModuleRunner.Run(ITestModule)"/> method
        /// that will in turn invoke this method.</remarks>
        void ITestModule.Run()
        {
            Mouse.DefaultMoveTime = 300;
            Keyboard.DefaultKeyPressTime = 100;
            Delay.SpeedFactor = 1.0;
        }
    }    
I run this Ranorex code module before any of my recordings. I usually put it in the Setup phase of my test case. Then in my recording, I just reference them.

Recording 1

Code: Select all

ParameterPassingStaticVariables.listOfStrings = *** Some list of string object ***
Recording 2

Code: Select all

foreach (string str in ParameterPassingStaticVariables.listOfString)
{
    *** DO SOMETHING ***
}
Remember these are static variables and you can only have one instance of each variable in the entire solution. Ranorex Support provided me with this method awhile back and it works great for me.

Hope that helps.

User avatar
Stub
Posts: 515
Joined: Fri Jul 15, 2016 1:35 pm

Re: Passing objects from test case to test case

Post by Stub » Tue Feb 28, 2017 9:36 am

krstcs wrote:But,
....//container[#'mycontainer']/button[@text='OK']
will be almost instant, every time.
krstcs, I have not see these "Unique IDs" before (#mycontainer, #myText). I had a quick search in the User Guide for them but can't see anything more from a quick skim. Any suggestions where I can find out more? I did come across a mention related to Web Elements here.

krstcs
Posts: 2683
Joined: Tue Feb 07, 2012 4:14 pm
Location: Austin, Texas, USA

Re: Passing objects from test case to test case

Post by krstcs » Tue Feb 28, 2017 5:10 pm

Ranorex will create them automatically if your AUT has element id's that are unique, or you can create them if you know for sure that they are there. Note that they still have a timeout and if they aren't found, Ranorex will still wait for the whole timeout.

It expects that there is one and only one element with that ID on the whole page/form at that time.

The format is:

[#'<Id value>']

You can't have any other properties in the same set of brackets, but you can add them in a different set.

Button[#'MyButton'][@visible='true' and @enabled='true']

Ranorex indexes and caches the element so it is found almost immediately.

Again, your AUT must implement one of the following properties, and it must be unique:
Id
AccesibilityId

(There may be others that work as well...)
Shortcuts usually aren't...

robert.altman
Posts: 8
Joined: Thu Feb 23, 2017 10:54 pm

Re: Passing objects from test case to test case

Post by robert.altman » Tue Feb 28, 2017 5:50 pm

I use public static variables to pass objects between recordings and I imagine you can do the same between test cases. You just have to declare the static variables on a more global scope then the test cases.

I create a Ranorex code module that defines the variables and then references them from my recording.
From my previous understanding I thought this was not possible, since when the variable defining module finishes it's execution, you can't reference the variables any longer as they will return null.

Then again, if it's working for you, maybe that will be the simplest solution for me. I'll play around with that and let you know if it works for me. If it does it will be bitter sweet... :x :)

krstcs
Posts: 2683
Joined: Tue Feb 07, 2012 4:14 pm
Location: Austin, Texas, USA

Re: Passing objects from test case to test case

Post by krstcs » Tue Feb 28, 2017 5:57 pm

There are several issues with using global static variables for element identification, the primary one being that you are re-inventing what Ranorex already does with the repo. You are doing work that has already been done. The second is that you now also have to maintain the static variables in your code instead of being able to just manage the repo. This also means that anyone coming up behind you has to figure out what you did instead of just using Ranorex, and they will not appreciate it.

Use the tools the way they were intended, they work and they work well. Sometimes it just takes changing your mindset to look at it from what Ranorex gives you. It will do everything you need, and most of it from out-of-the-box.
Shortcuts usually aren't...

tvu
Posts: 195
Joined: Tue Apr 07, 2015 10:47 pm

Re: Passing objects from test case to test case

Post by tvu » Thu Mar 02, 2017 8:05 pm

Sorry, I should have explicitly said that I was using global static variables to pass complex objects like Lists or Class objects. I am not using it for any element identifications related to the Repo.