Forum Discussion

escap89's avatar
escap89
Contributor
9 years ago

How to configure test run conditions

Hi,

 

Lets say that i have 4 tests:

TEST A: Add user number 1

TEST B: Open user number 1 and change data

TEST C: Add user number 2

TEST D: Open user number 2 and change data

 

How can I in Test Complete simply configure tests like:

Run test A  always

Run test B if test A success

Run test C always

Run test D if test C success

 

For this moment i have no idea how simple i can do that in TC. Was wondering if in project "Test items" tab i can define conditions.

 

In advance thanks for the tips

 

//Sebastian

 

  • Your right, i just forgot to remove that sentence.

    I mean that code (your first version):

     

    def yourTest():
        while not listen():
            step1()
            step2()
            step3()

    other_steps()

     Code above will do the whole "step1/step2/step3" even if inside that already was 10000 errors.

  • tristaanogre's avatar
    tristaanogre
    Esteemed Contributor

    I tried this in a quick project with some basic logic to simulate errors.  The functions I created are:

     

    function TestA(isError) {
        if (isError) {
            Log.Error('Got an error in Test A');
        } 
        else {
            Log.Message('No error in Test A');  
        }
    }
    
    function TestB() {
        Log.Message('Ran test B');
    }
    
    function TestC(isError) {
        if (isError) {
            Log.Error('Got an error in Test C');
        } 
        else {
            Log.Message('No error in Test C');  
        }
    }
    
    function TestD() {
        Log.Message('Ran test D');
    }

    I then did the following:


    Make Test B a child test item of Test A and make Test D a child test item of Test C. Set the "Stop on Error" setting on all tests to Test Item. 


     

    If TestA runs with the isError set to false, TestA does not raise an error and testB then runs. If TestC is run with the isError set to true, TestC runs but generates an error and stops and TestD does not run.  Playing around with the isError parameters verifies that this works for any of the combinations.

     

    Hope this helps.

    • tristaanogre's avatar
      tristaanogre
      Esteemed Contributor

      Obviously, there is another solution to your problem if you want to write it as code.  Taking the same four functions I mentioned before, I did a bit of rework. This, effectively, does the same thing.  Likewise, if you are using Keyword tests, you could build similar logic.  You don't even need to use the "try catch" logic at all... just embed tests within tests with if/then/else logic wrapped around them to properly detect whether the sub-test should be run. This is the beauty of a tool like TestComplete... you can, potentially, organize your tests using any combination of the three techniques and end up with a REALLY cool suite of tests.

       

      function TestA(isError) {
          try {
              if (isError) {
                  throw 'Got an error in Test A';
              } 
              else {
                  Log.Message('No error in Test A');
                  TestB();  
              }
          }
          catch (e) {
              Log.Error('rasied an error: ' + e);
          }
      }
      
      function TestB() {
          Log.Message('Ran test B');
      }
      
      function TestC(isError) {
          try {
              if (isError) {
                  throw 'Got an error in Test C';
              } 
              else {
                  Log.Message('No error in Test C'); 
                  TestD(); 
              }
          }
          catch (e) {
              Log.Error('rasied an error: ' + e);
          }
      }
      
      function TestD() {
          Log.Message('Ran test D');
      }
      
      function RunAll() {
          TestA(true);
          TestC(false);
      }
      • Colin_McCrae's avatar
        Colin_McCrae
        Community Hero

        My framework allows this.

         

        It allows the user to put a marker against a test step on their input sheet.

         

        Subsequent test steps can then refer back to this and will only run if the referral(s) to previous steps meet the conditions. (It can check multiple markers, and can be triggered by passes or fails)

         

        My main use for it is to put remedial test steps in in areas where we have known bugs. That way, the failing test will fail, and be marked as such. The option steps afterwards check, see it's still failing, this triggers the remedial steps and the test can keep running.

         

        When the bug is fixed, the previously failing test passes, the remedial steps no longer meet the trigger condition, and are not run.

         

        Shazam!

         

        Self-fixing automated tests. :smileyvery-happy:

  • Thanks for these examples :) it gave me alot of new ideas.

     

    I just want to know one more thing, cause for this moment can't imagine how to do that:

     

    Lets say that i have 3 tests that doing the same thing, diffrence is one parametr - because i dont want to make 3 diffrent .py files i decided to create a one with a loop like:

     

     

    def RUNALL():
    param= ['P','Np','Pm']
    number=1
    year=16
    for p in param:
         SprAddModify.SprAddModify(p,number,year)

     

    If inside "SprAddModify" ill get an error but only for param "Np" i want my loop jump to param "Pm" and stop executing "SprAddModify" for param "Np" on first cached error

     

    Actually if i use OnErrorEvent and inside that ill put  Close and run app it will be like:

    Test for param "P" success

    Test for param "Np":

    looking for window A

    close/run app

    looking for window B

    close/run app

     etc...

     

    No clue how can i impose stop running the whole method SprAddModify if inside it you encountered any error.

    What i want achive (if my test fail for param "Np"):

    Test for param P finished with success

    Test for param "Np" failed

    Test for param "Pm" finished with success

     

     

    I will be rlly glad for any help.

     

     

     

    • Colin_McCrae's avatar
      Colin_McCrae
      Community Hero

      Kind of depends what you mean by passed or failed.

       

      If your test catches that it has failed and logs something accordingly, then your code above should be fine.

       

      But if the second one fails and causes the code to throw an error, then is that what you want to handle?

       

      I've done some Python, but not within TestComplete. The way I did it before, where a main loop was handing off to various smaller functions was simply to wrap the function calls in the loop within a try/except.

       

      So in your case, something along the lines of:

       

      def RUNALL():
      param= ['P','Np','Pm']
      number=1
      year=16
      for p in param:
           try:
               SprAddModify.SprAddModify(p,number,year)
           except:
               >> Log some sort of bug/failure here <<
      >> Maybe also do some sort of application state tidy up? <<

       

       

      ... should be the bare minimum required to keep it moving I would think?

      • baxatob's avatar
        baxatob
        Community Hero

        Hi guys!

         

        A little comment - when you are using try/except statement within TestComplete, it will handle only Python exceptions. All native TC errors will be passed.

         

         

  • My test:

    def RUNALL():
    param= ['P','Np','Pm']
    number=1
    year=16
    for p in param:
         try:
             SprAddModify.SprAddModify(p,number,year)
         except:
             Log.Error("Error for param: "+str(p))
    pass

     

    SprAddModify:

    def SprAddModify(rep,number,year):
    date_w='01012016'
            SprReg.SprReg(rep,number,year)
            SprAdd(date_w)
            SprOpen(rep,number,year)
            SprCheck(date_w)

    To simulate situation i want to handle i added code below  to method "SprReg()":

    if (rep != 'Np'):
            object.click()
    objectA.click()

    All code above will effect like  my attached Log.

     

     

    As we see "except" do not work same as "onerror event".

    I need change my loop  to skip the current loop on first logederror.

     

    • Colin_McCrae's avatar
      Colin_McCrae
      Community Hero

      Ah right. We're into the realm of how TC errors are handled (or not) in Python.

       

      Which I know nothing about I'm afraid. So I'll leave this one to others.

    • Colin_McCrae's avatar
      Colin_McCrae
      Community Hero

      I tend to write in all my own error handling anyway. I don't want automated scripts coming to a stop due to an error, because I know they can, and will, happen.

       

      So in your case, I'd put in a check against the top level item you'll be using - the MDIWindow("Sprawa") by the look of it - and if it doesn't exist, drop out of the routine after logging an error.

       

      So inside SprAddModify ...

       

      def SprAddModify(rep,number,year):
      
      if (<top level object is present>) then:
              date_w='01012016'
              SprReg.SprReg(rep,number,year)
              SprAdd(date_w)
              SprOpen(rep,number,year)
              SprCheck(date_w)
      else:
              Log an error
              Return

       

       

      (Syntax and formatting are not correct .... it's just example logic)

       

      Like I say, I tend to have all the automatic error stopping switched off and rely on my own error handlers. My scripts have always had loads of error handling and validation built in anyway as they are keyword + data driven by other users. Which means there is tons of scope for the user to introduce bad calls and/or data so it has to be able to cope with pretty much anything.

       

      It's more work, but it's also more robust once that work is done.

    • baxatob's avatar
      baxatob
      Community Hero

      1. You can catch an error while it recorded to the log >> 

      It is useful, if you don't know where exactly expect the error.

       

      2. If you know the weak points of your application, you can expect the error using the last operation result.

      E.g you have some checkpoint - aqObject.CheckProperty(...) It will return True if passed and False otherwise.

      So you can wrap your steps like:

       

      result = aqObject.CheckProperty( ... )
      if result:
          do_something_1()
      else:
          do_something_2()

       

      3. Write your own error handler like Colin_McCrae said.

       

       

      Also take a look at the Handling Events >>

  • Well I am reading and still do not see an good solution for that problem.

     

    My idea was use

    try

    ....

    except

    ...

    but  i wanted force "try" to try while error event sleeps insinde, if it log an error inside go go to "except" (wanted to skip current loop, restart app and go to next loop (another param)).

    So i needed try - except force to work like error event.

     

    I cant use just error event cus i need step to next loop with another param after logged error.

     

    Well if the only way is to control test inside every method then i prefer to duplicate my tests as i wanted at start but i though that there is better way:

    RunP.py (file):

    RunP():
    SprAddModify.SprAddModify('P',number,year)

    RunNp.py(file):

    RunNp():
    SprAddModify.SprAddModify('Np',number,year)

    RunPm.py(file):

    RunPm():
    SprAddModify.SprAddModify('Pm',number,year)

     

    with my tests written like that i can do whatever i want because from a project test item configuration i can specify

    Stop on Error: Test item - ( analogue to what i wanted achieve with my loop insinde script)

    • baxatob's avatar
      baxatob
      Community Hero

      If you need to break a loop, you can use a kind of "flag" variable, which will change its value if some error occurs. 

       

      def listen():
          if Project.Variables.flag:
              Project.Variables.flag = False # <-- reset variable to initial state
              return True
          else:
              return False
      
      
      def GeneralEvents_OnLogError(Sender, LogParams):
          Project.Variables.flag = True
      
      
      def yourTest():
          while not listen():
              step1()
              step2()
              step3()

      other_steps()

      The idea: if some error will happen during yourTest() , OnLogError event will assign flag variable as True and you will exit from the loop.

       

       

      • Colin_McCrae's avatar
        Colin_McCrae
        Community Hero

        Just have the called function return some sort of flag that indicates an error occurred and it did not complete successfully.

         

        If you really want to, you could use this flag to force an exception on return which, I think, should cause it drop into the "Except" block. Or you could just use it as an exit condition from the loop. Various ways to do it.

         

        http://stackoverflow.com/questions/2052390/manually-raising-throwing-an-exception-in-python

         

        Setting up multiple copies of the same function, with only different input data, definitely does not feel like the way to go!