Forum Discussion

Nikolayev's avatar
Nikolayev
Contributor
5 years ago

How to manage Errors as not or Warnings with Testcomplete

Hi everyone in SmartBear Community,

 

Sorry for my aproximate poor, or roughly English. I hope you will understand me !

 

I have a simple Test Result question  with an "WPF" application called "PI.UI.exe" made by my compagny.

I made some tests with this APP "PI.UI.exe".

This app depends on system environment and, sometimes, takes time to open or close.

So today I want to improve my tests to get more informations about application launching and closing.

 

I made these 2 python scripts which are detecting some expected objects :

 

START

import time

if Aliases.PI_UI.FrmPIMenu.Exists:

  Aliases.PI_UI.FrmPIMenu.Focus()

else:

  Log.Message("Slowddown detected with application launch, waiting 5 seconds")

   time.sleep(5)

 

CLOSE

if not Sys.Process("PI.UI").Exists:

  Log.Message("Application closed correctly")

else :

  Log.Message("Application is still open. Waiting 5 seconds before Kill process")

  time.sleep(5)

  Sys.Process("PI.UI").Terminate()

 

It works well, but in normal case it return a Red Error in the log because Process PI.UI is not found.

I would like to manage and bypass this Error.

What I want is that TestComplete ignore this control and make the test Results GREEN instead of RED.

 

Do you me know if it's possible ?

 

This will make my robots happy

:robothappy:

 

Regards !   

Niko...

 

 

 

 

 

 

  • You can control by different ways:

    - use the event, General events -> onLogError and when the error message is the wanted to ignore then you can lock the log system

    - use the Log.Enabled property to switch off/on the logging system

    - use a try/catch/finally to intercepet already known errors

     

    Each one has advantages and disadvantages, try them to learn them and choose the best suited to you :)

     

     

    Below on on my complete event management, look the part about skip

     

    /* ---------------------------------------------------------------------------
     Gestionnaire des évènements d'erreur
     - Prend en charge les répétitions de messages identiques
     - Prend en charge les conditions d'ignorance de la remontée d'erreur
     - Prend en charge la transformation d'erreur d'object inexistant en simple avertissement
     - Transmet une capture écran au log
     - Applique une mise en forme spécifique
    --------------------------------------------------------------------------- */
    function GeneralEvents_OnLogError(Sender, LogParams) {
      // Message d'erreur identique alors on met de coté
      if (LogParams.MessageText == Globals.LASTERRORLOG)  {
        Globals.SAMEERRORCOUNT++;
        LogParams.Locked = true;
      }
      else {
        // Gérer les erreurs que l'on souhaite ignorer
        let skip = false;
        for (let i = 0; i < Globals.MESSAGETOSKIP.length; i++) {
          skip = skip == false ? aqObject.CompareProperty(LogParams.MessageText, cmpContains, Globals.MESSAGETOSKIP[i], false, lmNone) : true;
        }
        // Condition pour ignorer remplie
        if (skip) {
          Log.Message(LogParams.MessageText);
          LogParams.Locked = true;
        }
        else {
          // Transformer les erreurs d'objet inexistants en warning
          if ((Globals.IGNORENOTFOUND) && ((aqObject.CompareProperty(LogParams.MessageText, cmpContains, "Unable to find the object", false, lmNone)) || (aqObject.CompareProperty(LogParams.MessageText, cmpContains, "The object does not exist.", false, lmNone)))) {
            Log.Message(LogParams.MessageText, LogParams.AdditionalText, pmHigher, qa.system.logWarning, screen);
            LogParams.Locked = true;
          }
          else {
            // Gérer les répétitions
            if (Globals.SAMEERRORCOUNT > 1) {
              Log.Message("Erreur '" + Globals.LASTERRORLOG + "' répétée " + Globals.SAMEERRORCOUNT.toString() + " fois !", "", pmNormal, qa.system.logInfo);
            }
            Globals.LASTERRORLOG     = LogParams.MessageText;
            // Dérouter le gestionnaire d'évènement avant de faire un log d'erreur
            let f                    = GeneralEvents_OnLogError;
            GeneralEvents_OnLogError = null;
             // Récupérer la capture d'écran existante ou en générer une
            let screen               = qa.system.lastExceptionScreen != null ? qa.system.lastExceptionScreen : Sys.Desktop;
            let addInfo              = ((LogParams.AdditionalText == null) || (LogParams.AdditionalText == "")) ? qa.system.lastExceptionStack : (LogParams.AdditionalText != qa.system.lastExceptionStack) ? LogParams.AdditionalText + '\n' + qa.system.lastExceptionStack : LogParams.AdditionalText;
            Log.Error(Globals.LASTERRORLOG, addInfo, pmHighest, qa.system.logError, screen);
            Globals.TESTRESULT       = false;
            GeneralEvents_OnLogError = f;
            Globals.SAMEERRORCOUNT   = 0;
            LogParams.Locked         = true;
          }
          // Réinitilaliser la capture d'écran et la stack
          qa.system.lastExceptionScreen = null;
          qa.system.lastExceptionStack  = "";
        }
      }
    }
  • In both sections of code, you should be using a "Wait" method before testing for "Exists".

     

    So, replace 

     

    if Aliases.PI_UI.FrmPIMenu.Exists

     

    with

     

    if Aliases.PI_UI.WaitAliasChild("FrmPIMenu", 20000).Exists

     

    and replace

     

    If Sys.Process("PI.UI.exe").Exists

     

    with

     

    Sys.WaitProcess("PI.UI", 20000).Exists

     

    Doing an "Exists" check the way you were doing it won't work... you can't check the "Exists" property of an object that does not exist...  So, the "Wait" processes return a "stub" object if the object is not found with the "Exists" property set to False.

  • BenoitB's avatar
    BenoitB
    Community Hero

    You can control by different ways:

    - use the event, General events -> onLogError and when the error message is the wanted to ignore then you can lock the log system

    - use the Log.Enabled property to switch off/on the logging system

    - use a try/catch/finally to intercepet already known errors

     

    Each one has advantages and disadvantages, try them to learn them and choose the best suited to you :)

     

     

    Below on on my complete event management, look the part about skip

     

    /* ---------------------------------------------------------------------------
     Gestionnaire des évènements d'erreur
     - Prend en charge les répétitions de messages identiques
     - Prend en charge les conditions d'ignorance de la remontée d'erreur
     - Prend en charge la transformation d'erreur d'object inexistant en simple avertissement
     - Transmet une capture écran au log
     - Applique une mise en forme spécifique
    --------------------------------------------------------------------------- */
    function GeneralEvents_OnLogError(Sender, LogParams) {
      // Message d'erreur identique alors on met de coté
      if (LogParams.MessageText == Globals.LASTERRORLOG)  {
        Globals.SAMEERRORCOUNT++;
        LogParams.Locked = true;
      }
      else {
        // Gérer les erreurs que l'on souhaite ignorer
        let skip = false;
        for (let i = 0; i < Globals.MESSAGETOSKIP.length; i++) {
          skip = skip == false ? aqObject.CompareProperty(LogParams.MessageText, cmpContains, Globals.MESSAGETOSKIP[i], false, lmNone) : true;
        }
        // Condition pour ignorer remplie
        if (skip) {
          Log.Message(LogParams.MessageText);
          LogParams.Locked = true;
        }
        else {
          // Transformer les erreurs d'objet inexistants en warning
          if ((Globals.IGNORENOTFOUND) && ((aqObject.CompareProperty(LogParams.MessageText, cmpContains, "Unable to find the object", false, lmNone)) || (aqObject.CompareProperty(LogParams.MessageText, cmpContains, "The object does not exist.", false, lmNone)))) {
            Log.Message(LogParams.MessageText, LogParams.AdditionalText, pmHigher, qa.system.logWarning, screen);
            LogParams.Locked = true;
          }
          else {
            // Gérer les répétitions
            if (Globals.SAMEERRORCOUNT > 1) {
              Log.Message("Erreur '" + Globals.LASTERRORLOG + "' répétée " + Globals.SAMEERRORCOUNT.toString() + " fois !", "", pmNormal, qa.system.logInfo);
            }
            Globals.LASTERRORLOG     = LogParams.MessageText;
            // Dérouter le gestionnaire d'évènement avant de faire un log d'erreur
            let f                    = GeneralEvents_OnLogError;
            GeneralEvents_OnLogError = null;
             // Récupérer la capture d'écran existante ou en générer une
            let screen               = qa.system.lastExceptionScreen != null ? qa.system.lastExceptionScreen : Sys.Desktop;
            let addInfo              = ((LogParams.AdditionalText == null) || (LogParams.AdditionalText == "")) ? qa.system.lastExceptionStack : (LogParams.AdditionalText != qa.system.lastExceptionStack) ? LogParams.AdditionalText + '\n' + qa.system.lastExceptionStack : LogParams.AdditionalText;
            Log.Error(Globals.LASTERRORLOG, addInfo, pmHighest, qa.system.logError, screen);
            Globals.TESTRESULT       = false;
            GeneralEvents_OnLogError = f;
            Globals.SAMEERRORCOUNT   = 0;
            LogParams.Locked         = true;
          }
          // Réinitilaliser la capture d'écran et la stack
          qa.system.lastExceptionScreen = null;
          qa.system.lastExceptionStack  = "";
        }
      }
    }
    • Nikolayev's avatar
      Nikolayev
      Contributor

      Thank you Benoit ,

      I simply discard it with  Log.Enabled = False    before the control and   Log.Enabled = True    after.

      Logs is clear now ...   even if there's a lot to discover with TC for me like General events  with it looks very usefull.

       

      Merci beaucoup Benoit,

      Et oui, je suis un français ... confiné en France  :smileyhappy:.

      Encore beaucoup de chose à découvrir avec TC pour moi, depuis plus d'un an je m'auto-forme sur l'outil, la doc est vraiment bien faite.

      Je n'ai pas encore utilisé les General Events, ça à l'air complet et pratique !

       

       

       

  • tristaanogre's avatar
    tristaanogre
    Esteemed Contributor

    In both sections of code, you should be using a "Wait" method before testing for "Exists".

     

    So, replace 

     

    if Aliases.PI_UI.FrmPIMenu.Exists

     

    with

     

    if Aliases.PI_UI.WaitAliasChild("FrmPIMenu", 20000).Exists

     

    and replace

     

    If Sys.Process("PI.UI.exe").Exists

     

    with

     

    Sys.WaitProcess("PI.UI", 20000).Exists

     

    Doing an "Exists" check the way you were doing it won't work... you can't check the "Exists" property of an object that does not exist...  So, the "Wait" processes return a "stub" object if the object is not found with the "Exists" property set to False.

    • Nikolayev's avatar
      Nikolayev
      Contributor

      Thanks a lot    Tristaanogre                   

      done ... I replace code with the Wait method and also found a solution to have the expected tests results .

      It's a good green now ! ;-)

       

      Have a nice day...

       

      • BenoitB's avatar
        BenoitB
        Community Hero

        Ca fait 8 ans que je suis sur TC .. et je découvre encore plein de choses ...

        Les events c'est très importent, tu vois bien que ca me permet de faire une gestion étendue d'erreur.

        Pareil pour les warnings.

         

        J'utilise TC pour du test, du dev pur, de la RPA...

         

        Finalement, le plus gros problème, et qui est un vrai frein lorsqu'on propose cette solutionà nos clients, c'est l'augmentation continue des tarifs qui deviennent vraiment exagérés. C'est vraiment une problématique que Smartbear ne prend pas du tout en compte.