Forum Discussion

alansvieceli's avatar
alansvieceli
New Contributor
10 years ago

ODT disappeared in version "10.40"

TestComplet upgraded to the lasted version, but the ODT is not present...



I need help, someone could help me how to solve this?



alread seen in the Extensions folder, the archives "tcODT.pls" and "tcODTEditor.pls" folder are not in it

10 Replies

  • mburr's avatar
    mburr
    Occasional Contributor
    Wished there was a checkbox option for ODT in the 10.40 install but I did not see it. The oldest project I have is written in VBScript and since I like OO I used ODT. I have since moved to JScript for later projects as it is easier but have not yet converted the one old project. I would definately vote to keep ODT. It will be awhile before I convert 27,000 lines of VBScript into JScript. I will need the interim ODT plugin until then.
  • Manfred_F's avatar
    Manfred_F
    Regular Contributor
    We, too, want to KEEP ON USING ODT.



    Maybe, it's "rarely used", because, maybe, it is not the simplest Approach. But, if You know how to apply it, it is much better than spaghetti Scripting.



    Here is, how I use it:

    Normal procedural test scripts tend to have a poor, spaghetti-like structure. There are long routines, and at a given code location it is not clear, which test step and/or test case is implemented there. Test data and reference data are often defined in the code as magic numbers and strings.

     

    Using ODT, I can do it better: the “script” is clearly divided into sections (Abschnitte), sequences and steps (Testschritte), see the attached screenshot of ODT data with the structure highlighted in green.

    Please notice the green rectangle: item0 and item1 hold test case references to the test step. This is a perfect way to integrate metadata. I could easily add a script to evaluate them, e.g. to generate a table or list containing each step and its implemented test cases. In a standard test script, I’d have to use code patterns to integrate metadata and I’d have to do code analysis to evaluate, which is far less comfortable and maintainable.

    The test steps could have names, but I’ve left that out, so they are only identified via their sequence and hierarchical position – like it was in my original test script for manual testing. However, each test step calls an ODT test function, which I gave a name to like Test_2_1_2(), containing the original test step ID.

    So, for each ODT test script code location, it is clear a) which test step it serves for (from the routine name) and b) which test cases are implemented.

    In addition, It is perfectly easy to add setup and shutdown functionality on each level of the test object hierarchy, and it leads to transparent results.

     

    To separate test and reference data form the scripts, I use the StdDatum data elements (highlighted in blue) integrated in the Daten_Test and Daten_Ref arrays of test elements on every level of hierarchy. The upper example shows a dialog that is to be opened by menu “Einrichten|BDE-Recorder”. In the lower example, a date value is to be set for field “Auflösung”.

    Accessing the ODT data tree originally is not so very comfortable, You have to deal with all these .owner, .properties and .value elements. So, to facilitate using my data definitions, I use a function defined in a script extension to get hold of the test data. Calling “Td = PVA_0.ODT.TestDatenArr(This, 0)” in an ODT test routine gives me an array with a wrapper object for each StdDatum in the Daten_Test property of This object. Calling “TdP = PVA_0.ODT.TestDatenArr(This, 1)” does the same for the superordinate test data object, and so on.

    The wrapper for StdDatum is a vbs object. It contains mostly getters/setters for the properties and also some very convenient procedures to use in ODT test procedure.

    If I call “TdP(mcBdeTblDlgIx).DialogOpenByMenu” from the ODT test routine of step item1 , I access the dialog in the upper example. TdP(mcBdeTblDlgIx) gives me access to the test data element with the given index on parent-level. During initialisation, TC took the alias string from field ObjektDefinition and created an alias object from it and stored it into field “object”. Now, the DialogOpenByMenu routine opens the dialog per menu and waits until the alias object is ready (exists and visible) and creates and stores a wrapper object for the dialog into the Objekt field – ready to use.

    Calling “Td(mcSchrAufloesungIx).SetText(myFrm)” sets in the lower example the text from the StdDatum property “Wert” to the field with caption “Auflösung”. The parameter myFrm holds a wrapper object for the frame carrying the target field, I get it from the wrapper object of the dialog.

     

    So as a result – opening a dialog or setting a value can easily be defined in the data tree and executed in a ODT test function by a simple line of code. The test and reference data are located in the data tree, separated from the test script code. There they can be moved to the appropriate level in the test element hierarchy with little effort (copy & paste), the adaptions in the ODT code can easily be handled, if constants are used as index in the test data array (Td).

    Furthermore, ODT is very useful to hold and evaluate metadata and for disposition of setup/shutdown functionality.

     



    Regards,



    Manfre

  • mburr's avatar
    mburr
    Occasional Contributor
    I discovered once I migrated from ODT, (Object Driven Testing), to VB script classes, that the test code actually ran faster. The conversion ended up to be easier than I originally thought. This may be due in part to the fact that I mostly used ODT to create classes and arrays. Unfortunately, I also used the Owner.Owner stuff but that ended up to be easy to get rid of.  I also used classes to drive UserForms and Network testing, but that ended up to be no problem either.



    The tests we run are completely data driven using DDT with an excel spreadsheet. (Hope they don't get rid of that ;-) The test server that needed to be converted was completely written in VB but fortunately the test clients were written using jscript. The test server had over 40 ODT classes. Several classes were fairly large with 30+ properties and 20+ methods. A good number of methods would also use ODT.Classes.NewArray(). 



    So, in order, here is a high level view of what I did. Of course I would continually test the test code after each change.



    1. Got rid of all uses "Owner.Owner."  Used module level variables and/or functions to pass data from a parent class to a child class.



    2. Made sure the organization of routines was such that all routines for a class were co-located. This does not include UserForm event modules that need to be kept outside any class.



    3. Defined a custom array class that for the most part would replace ODT.Classes.NewArray() directly. See below.



    4. Converted and tested each class one at a time. To save some time I simply used the Public keyword for public variables instead of defining the full Let/Get definitions. (Let/Get are done under the hood anyway.) When you test each class you will most likely discover something you forgot to convert. Each class most likely will need an accessor function outside the class so other "units" can instantiate an object based on that class.



    Once you have completed the conversion for all ODT classes and arrays, and your test code still run OK, you can remove ODT from your project.




    Class CustomArray



      ' --- Private properties



      Private m_Array()



      Private m_Count



      Private m_IsObject ' basic type of 1st item - object or non object





      ' --- Public Properties



      Public Property Let Count(value)



        m_Count = value



      End Property



      



      Public Property Get Count()



        Count = m_Count



      End Property

     



      ' Read only



      Public Property Get IsObject()



        IsObject = m_IsObject



      End Property



      



      ' --- Private Methods



      Private Function UseSet(ArrayItemToCheck)



        Dim strTemp



        Dim blnUnexpectType



        blnUnexpectType = False



        UseSet = False



        Select Case VarType(ArrayItemToCheck)   



          Case



            strTemp = "vbEmpty"



            blnUnexpectType = True



          Case



            strTemp = "vbNull"



            blnUnexpectType = True



          Case



            strTemp = "vbInteger"



          Case



            strTemp = "vbLong"



          Case



            strTemp = "vbSingle"



          Case



            strTemp = "vbDouble"



          Case



            strTemp = "vbCurrency"



          Case



            strTemp = "vbDate"



          Case



            strTemp = "vbString"



          Case



            strTemp = "vbObject"



            UseSet = True



          Case 10 



            strTemp = "vbError"



            blnUnexpectType = True



          Case 11 



            strTemp = "vbBoolean"



          Case 12 



            strTemp = "vbVariant"



          Case 13 



            strTemp = "vbDataObject"



            UseSet = True



          Case 14 



            strTemp = "vbDecimal"



          Case 17 



            strTemp = "vbByte"



          Case 8192



            strTemp = "vbArray"



            UseSet = True



          Case Else



            strTemp = "undetected: " & VarType(ArrayItemToCheck)



            blnUnexpectType = True



        End Select



        If blnUnexpectType Then



          Log.Error("Unexpected array item type: " & strTemp)



        End If



      End Function



      



      Private Sub Class_Initialize()



        m_Count = 0



        m_IsObject = False



        ReDim m_Array(-1) 



        'Log.Message("UBound=" & UBound(m_Array))



      End Sub



      



      ' --- Public Methods  



      Public Function GetArray()



        GetArray = m_Array



      End Function



      



      ' Returns a specific array item



      Public Default Function Items(index)



        If index < m_Count And index > -1 Then



          If m_IsObject Then



            Set Items = m_Array(index) 



          Else        



            Items = m_Array(index)



          End If



        Else



          Log.Error("index out of range")



        End If



      End Function



      



      ' Used to change value of an existing item



      Public Function SetItem(index, value)



        if m_IsObject Then



          Set m_Array(index) = value



          Set SetItem = m_Array(index) 



        Else



          m_Array(index) = value



          SetItem = m_Array(index)



        End If



      End Function



      



      Public Function AddItem(value)



        If m_Count = 0 Then



          If UseSet(value) Then



            m_IsObject = True



          Else



            m_IsObject = false



          End If



        Else



          If UseSet(value) <> m_IsObject Then



            Log.Error("Attempted to mix objects and non objects into the array. Item NOT added!")



            Exit Function



          End If



        End If



        ReDim Preserve m_Array(m_Count)



        'Log.Message("UBound=" & UBound(m_Array))



        if m_IsObject Then



          Set m_Array(m_Count) = value



          Set AddItem = m_Array(m_Count) 



        Else



          m_Array(m_Count) = value



          AddItem = m_Array(m_Count)



        End If



        m_Count = m_Count + 1



      End Function



      



      Public Sub DeleteItem(index) 



        Dim index2



        If index < m_Count and index > -1 Then



          If m_IsObject Then



            Set m_Array(index) = Nothing



          Else



            m_Array(index) = vbNull



          End If



          if m_Count > 1 And index < (m_Count - 1) Then



            ' Collapse array at the element that is being removed



            index2 = index + 1



            While index2 < m_Count



              If m_IsObject Then



                Set m_Array(index2 -1) = m_Array(index2)



              Else



                m_Array(index2 -1) = m_Array(index2)



              End IF



              index2 = index2 + 1



            Wend



          'ElseIf index = 0 And m_Count = 1 Then ' We must be removing the 1st and only element



            ' Do nothing as the adjustment of m_Count and the ReDim will suffice



          'Else ' We must be removing the last element 



            ' Do nothing as the adjustment of m_Count and the ReDim will suffice



          End If



          m_Count = m_Count - 1



          Redim Preserve m_Array(m_Count - 1)



          'Log.Message("UBound=" & UBound(m_Array))



        Else



          Log.Error("index out of range")



        End If



      End Sub



    End Class



    Function NewArray()



      Set NewArray = New CustomArray



    End Function




  • karkadil's avatar
    karkadil
    Valued Contributor
    Just a quick guess.

    Is it possible that you didn't tick corresponding checkbox during the installation?
  • No, alas, support for ODT was removed in 10.40.



    From the installed documentation:




    • The ODT plug-in is obsolete. We would recommend finding other ways to perform the tasks that you do with it. For instance, ODT is often used for creating custom classes (objects). You can define and create classes (objects) in JScript code by using JScript’s built-in functionality (see the JScript reference on the MSDN web site).



      To keep your tests functioning during the transaction, you can request the ODT plug-in from our Support Team.




    A support case has been opened and we're working on it there.

  • mburr's avatar
    mburr
    Occasional Contributor
    I see that now I can define VBScript classes in similar fashion as I had been use to in VBScript for office. I do not think I could do this back in TextComplete 5 and so I used ODT. Still a good size conversion task but more doable than converting to JScript as I would prefer. 
  • mdh's avatar
    mdh
    Contributor
    How about  ODT support for 10.50, is that re-introduced  ?



    and can I use the ODT Plug in I used for 10.40 or do I need to ask Smartbear again for a new one for 10.50 ? 
  • TanyaYatskovska's avatar
    TanyaYatskovska
    SmartBear Alumni (Retired)

    Hi Morten,


     


    The ODT feature wasn't reinstated in TestComplete 10.5. Our Product Management is aware of the fact that many of our customers are requesting to return this feature back. So, they consider this in future. However, right now, you will need to contact our Support team to get the ODT modules for TestComplete 10.5.


     

    • rrivest's avatar
      rrivest
      Contributor

      Where I'm currently working, we managed to replicate OO design without using ODT in C#.

       

      Here's a sample "Browser" class that allowes to instantiate either a standard browser or a virtual device for mobile web.

      We simply expose the methods and properties as needed

       

       

      function Fureteur()

      {

      // Initialisation des FIELDS

      this.Component = Object(); // L'object TestComplete.Browser

      this.BrowserType = varInteger; // Le type de Browser (int, -1=IE, -2=FF, -3=Chrome)

      this.currentPage = Object(); // Object de type Page, Page courante du Browser

      this.URL = varString; // URL de la page de type String

      this.isVirtual = Boolean();

      this.Description = varString;

      this.Open = function(BrowserType,isVirtual) // Instancie un fureteur selon le type

      {

       

      if (isVirtual) { // Si on utilise un Browser Virtuel

      this.isVirtual = true;

      var supported = VirtualBrowsers.Count;

       

      if (BrowserType<supported) // Est-ce que celui demandé est supporté (Voir dans les Projets-Properties-Open App-Web Test-Virtual

      {

      var mybrowser = VirtualBrowsers.Item(BrowserType);

      Log.Message(mybrowser.UserAgent);

      }

      this.Description = mybrowser.UserAgent;

      } else {

      this.isVirtual = false;

      switch (BrowserType) {

      case "-1" : Log["Message"]("Fureteur demandé : " + "Microsoft Internet Explorer");

      var mybrowser = Browsers["Item"](btIExplorer);

      break;

      case "-2" : Log["Message"]("Fureteur demandé : " + "Mozilla Firefox");

      var mybrowser = Browsers["Item"](btFirefox);

      break;

      case "-3" : Log["Message"]("Fureteur demandé : " + "Google Chrome");

      var mybrowser = Browsers["Item"](btChrome);

      break;

      default : Log["Message"]("Fureteur demandé : " + "Microsoft Internet Explorer");

      var mybrowser = Browsers["Item"](btIExplorer);

      }

      Log.Message("Fureteur : "+ mybrowser.Description);

      Log.Message("Family " + mybrowser.Family);

      this.Description = mybrowser.Description;

      }

      mybrowser.Run(Project["Variables"]["StartupURL"]); // La variable StartupURL se retrouve dans tous les projets.

      this.Component = Sys.Browser("*",0); // Pour obtenir le processus du Browser

      this.BrowserType = BrowserType;

      Log["PopLogFolder"]();

      return this.Component; // On retourne l'objet Browser

      }

      this.Navigate = function(url) // Navigue vers l'URL jusqu'à chargement complet

      {

      Log["AppendFolder"]("Navigation vers l'URL : "+url);

      var myClock = HISUtils["StopWatch"];

      myClock["Start"]();

      var myPage = this.Component["ToUrl"](url);

      while (myPage["contentDocument"] == null)

      Delay(200);

      while (myPage["contentDocument"]["readyState"] != "complete")

      myPage["Wait"]();

      Project["Variables"]["CurrentPage"]=myPage;

      myClock["Stop"]();

      //var myName = MakeLogName(Project["Variables"]["MyProject"]);

      //PushToLog(myName,"Page ; " + url + " ; "+myClock["ToString"]());

      Log["Message"](url + " ; "+myClock["ToString"]());

      this.currentPage = myPage;

      this.URL = myPage["URL"];

      Log["PopLogFolder"]();

      return this.currentPage; // On retourne l'objet Page de la navigation

      }

      this.Close = function() // Ferme le fureteur

      {

      this.Component["Close"]();

      return null;

      }

      }

       

       

       

      To instantiate the Browser

       

      myBrowser = new Fureteur

      myBrowser["Open"](-1,false) for a standard browser

      myBrowser["Open"](3,true) for one of the listed Virtual Devices in Project Properties