Forum Discussion

automTest's avatar
automTest
Occasional Contributor
6 years ago

Placing NameMapping data into vars

Hey smartBear community!

 

I was wondering if it's possible to place a specific object's Alias inside a variable once and re-use that variable throughout several scripts.

 

For example, if I'm referencing the same object in three different scripts which run back to back, would it be possible to place it in a variable before running that "set" of scripts and simply do something like the following:

 

Place this somewhere initially,

header = Aliases...---------------------...label.

 

Then reference that variable in the scripts without redeclaring that same variable again in each script,

Script1: header.Click();

Script2: header.HoverMouse();

Script3 header.VisibleOnScreen();

 

In other words, I'm trying to create a bank of variables which I can freely choose upon within several scripts without having to type in the "Aliases..........." part over and over again, being that it becomes repetitive.

 

Thanks for the help!

  • Hi automTest 

     

    I have used a similar approach previously and can say that I won't recommend it.  For example, I was storing a combobox in a variable because I was applying lots of operations on the same object.  Inevitably though, somewhere through the test run, the handle to the object would be destroyed and you would get an error about not being able to find the object despite it obviously being on the page.  You don't even need a page load for the mapping to change in some cases.  This means that each time you want to work with the object - before Click(), HoverMouse() and VisibleOnScreen() - in your example, you first have to check that it exists AND remap it if it doesn't.  If you keep it local to your script,  you may still need to do the same, but you will find you don't need to refresh the mapping info as often, which means less of a performance hit, which will slow down your tests.  Taking longer to type your code is better than taking longer to run your scripts.  You will make up the difference after a few test runs.

     

    What I could suggest to make the typing easier.  You can assign the aliases object to a variable inside your script.  You don't need to store it in a global variable, but you don't need to type as much either:

     

    var myLabel = Aliases.MyApp.Panel1.Panel0.Panel2.Table.Cell1.Label;
    myLabel.Click();
    myLabel.HoverMouse();
    myLabel.VisibleOnScreen();

    You only had to use that long Aliases... syntax once in the entire script.  Slightly more typing than a global variable, lots less failed tests because of object recognition issues totally unrelated to what you are actually trying to test

  • Hi automTest 

     

    I have used a similar approach previously and can say that I won't recommend it.  For example, I was storing a combobox in a variable because I was applying lots of operations on the same object.  Inevitably though, somewhere through the test run, the handle to the object would be destroyed and you would get an error about not being able to find the object despite it obviously being on the page.  You don't even need a page load for the mapping to change in some cases.  This means that each time you want to work with the object - before Click(), HoverMouse() and VisibleOnScreen() - in your example, you first have to check that it exists AND remap it if it doesn't.  If you keep it local to your script,  you may still need to do the same, but you will find you don't need to refresh the mapping info as often, which means less of a performance hit, which will slow down your tests.  Taking longer to type your code is better than taking longer to run your scripts.  You will make up the difference after a few test runs.

     

    What I could suggest to make the typing easier.  You can assign the aliases object to a variable inside your script.  You don't need to store it in a global variable, but you don't need to type as much either:

     

    var myLabel = Aliases.MyApp.Panel1.Panel0.Panel2.Table.Cell1.Label;
    myLabel.Click();
    myLabel.HoverMouse();
    myLabel.VisibleOnScreen();

    You only had to use that long Aliases... syntax once in the entire script.  Slightly more typing than a global variable, lots less failed tests because of object recognition issues totally unrelated to what you are actually trying to test

  • tristaanogre's avatar
    tristaanogre
    Esteemed Contributor

    NameMapping references an object. So, if you create a variable that stores an object, you can assign an object to that variable.  HOWEVER....  the state of the object at the time of storage is important.  You can assign the object but if it is not present in the application at the time you assign it, then what you'll get is a stub object or null object.

    The Aliases reference triggers an internal engine of TestComplete that searches for and identifies the object.  So, you can't quite just assign the object.  Each time you reference an Alias object, you need to make sure that it exists.  And assigning it once when it could subsequently be destroyed and recreated will lose the "handle" on the object.

    Now... I'm reading between the lines a bit.  It sounds like your Aliases..... is a very long string of objects.  It COULD be that there is some means by which that string can be shortened.

    For example, let's say you have an object that looks like this.

    Aliases.MyApp.Panel1.Panel0.Panel2.Table.Cell1.Label.

     

    That may reflect EXACTLY the hierarchy of the object in your application.  In fact, you my see, in the Mapped Object section

     

    NameMapping.Sys.MyApp.Panel1.Panel0.Panel2.Table.Cell1.Label.

     

    Well, the "beauty" of Aliases is that you can exclude unnecessary members of the tree.  The NameMapping.Sys doesn't change but, by right clicking on an Aliased object and selecting "Exclude", you can shorten your string to only the desired segments.

    Aliases.MyApp.Panel1.Label COULD be all you need.  To do this, all I'd do is exclude everything between Panel1 and Label... then you wouldn't have as much to type.

    • shankar_r's avatar
      shankar_r
      Community Hero

      tristaanogre wrote:

      NameMapping references an object. So, if you create a variable that stores an object, you can assign an object to that variable.  HOWEVER....  the state of the object at the time of storage is important.  You can assign the object but if it is not present in the application at the time you assign it, then what you'll get is a stub object or null object.

      This sounds interesting, I tried to have my aliases as a global variable and used that variable in one of my function. I believe global will get set at the start of execution.

      At the start, my object was not available after some actions object is getting displayed and I'm able to do the action, where I used the global variable in a function and everything works fine.  I'm curious about your reply :smileyhappy:

      • AlexKaras's avatar
        AlexKaras
        Champion Level 3

        shankar_r :

         

        Hi,

         

        Robert is correct with his explanation.

        The only missed detail is that objects referenced via Aliases use late binding and are evaluated when the target object is first interacted with.

        This fact makes it possible to declare global variable that references some Alias object and use this variable later inside some function. But as soon as the reference to the Alias is resolved, the obtained object will be cached. So if the target object is recreated (for example, as a result of the page reload), then its cached reference will be invalidated (obj.Exists will become False) and it will be required to refersh it with the help of the .RefereshMappingInfo() method. (See its documentation for more details.)

        This is the reason why personally I don't consider the idea of storing references to aliased objects in global variables to be a really good one. (Not mentioning the fact that global variable is risky in the meaning that its value can be unexpectedly altered at any time.)

         

  • The issue is that of scope. I suppose you could make them project variables, and populate them at test start or something.

  • shankar_r's avatar
    shankar_r
    Community Hero

    EDIT: This is not a recommended method

     

    If you really don't want to type Aliases (which is short name of the object) then there is one possibility.

    You can create a separate unit where you can declare all the objects globally like below then refer that in all other script units.

     

    Objs unit

    var txtUserName = Aliases.MainPage.LoginForm.txtUserName;
    var txtPassword = Aliases.MainPage.LoginForm.txtPassword;
    

    In other units just use like below and make you did USEUNIT for Objs unit

    //USEUNIT Objs
    function login(){
          Objs.txtUserName.Keys("Username");
          Objs.txtPassword.Keys("password");
    }

    You don't need to put Objs. but for the safer side, it is good to have.