2017-07-24 71 views
3

我在Robot Framework中看到了很多「nestable」For循環,主要是在For循環裏面創建一個關鍵字,然後在另一個For循環中調用該關鍵字。我使用Python 2.7.13創建了一個可嵌套的For循環,但因爲它主要使用運行關鍵字語法,所以我無法使用Robot Framework樣式語法(例如${variable_name}= My Keyword)創建變量。根據記錄,這是內建的機器人框架庫,它使用以下語法下運行關鍵詞:如何在此可嵌套For循環中實現Robot Framework樣式的變量?

Run Keywords Keyword1 arg11 arg12 AND  Keyword2 arg21 arg22 

同樣地,它可以這樣寫:

Run Keywords Keyword1 arg11 arg12 
...  AND  Keyword2 arg21 arg22 

它通常不支持在其中創建變量。但是,我將運行關鍵字用作可嵌套For循環的一部分。這是關鍵字的Python代碼。您可以看到,我的解決方法是創建一個名爲Assign Internal Variable的新關鍵字及其夥伴Assign Internal Variable to Keyword。但是,這會改變Robot Framework循環的語法,這個循環有點過分,而且我的喜好有限,因爲內部變量與外部變量完全分離。這個關鍵字在行動的機器人框架的測試情況的​​一個例子如下:

*** Variables *** 
${gold_squadron} = Gold 
${red_squadron} = Red 

*** Test Cases *** 
Test For Loop 
    For Loop IN RANGE 0 1 INDEX0 
    ...  \\ For Loop IN RANGE 1 6 INDEX1 
    ...  \\ \\ Assign Internal Variable {{standing_by}}  Standing By Red Leader 
    ...  \\ \\ Run Keyword If  INDEX1 == 1  Log to Console ${red_squadron} Leader Standing By 
    ...  \\ \\ Run Keyword Unless INDEX1 == 1  Log to Console ${red_squadron} INDEX1 {{standing_by}} 
    ...  \\ For Loop IN RANGE 1 6 INDEX2 
    ...  \\ \\ Assign Internal Variable {{standing_by_2}} Standing By Gold Leader 
    ...  \\ \\ Run Keyword If  INDEX2 == 1  Log to Console ${gold_squadron} Leader Standing By 
    ...  \\ \\ Run Keyword Unless INDEX2 == 1  Log to Console ${gold_squadron} INDEX2 {{standing_by_2}} 

該循環按預期工作,假設你已經正確導入Loops.py蟒蛇文件作爲庫。然而,我在尋找,語法是沿着以下線的東西:

*** Variables *** 
${gold_squadron} = Gold 
${red_squadron} = Red 

*** Test Cases *** 
Test For Loop 
    For Loop IN RANGE 0 1 INDEX0 
    ...  \\ For Loop IN RANGE 1 6 INDEX1 
    ...  \\ \\ {standing_by}=  Standing By Red Leader 
    ...  \\ \\ Run Keyword If  INDEX1 == 1  Log to Console ${red_squadron} Leader Standing By 
    ...  \\ \\ Run Keyword Unless INDEX1 == 1  Log to Console ${red_squadron} INDEX1 {{standing_by}} 
    ...  \\ For Loop IN RANGE 1 6 INDEX2 
    ...  \\ \\ {standing_by_2}= Standing By Gold Leader 
    ...  \\ \\ Run Keyword If  INDEX2 == 1  Log to Console ${gold_squadron} Leader Standing By 
    ...  \\ \\ Run Keyword Unless INDEX2 == 1  Log to Console ${gold_squadron} INDEX2 {{standing_by_2}} 

對於誰不覺得像撕裂成機器人框架的基礎代碼(不推薦,這是痛苦的), Loops通常不能嵌套在Robot Framework中的原因是因爲在基本級別上,關鍵字和For循環是兩個完全不同的對象。一些關鍵字被編碼,以便他們可以使用其他關鍵字(如「運行關鍵字」),但對於循環不是這樣編碼的。如果有人能找到一種方法來改變我For循環的語法,那麼最終的結果會更直觀地用於來自Robot Framework的人。只需要清楚,如果從示例中不清楚,我可以使用來自測試用例和For循環外部的Robot Framework變量。我問的是在For循環中創建它們。

+0

謝謝,修復。 –

回答

1

我終於明白了。這是更正後的代碼。

from robot.libraries.BuiltIn import BuiltIn 


class Loops(object): 

    def __init__(self): 
     self.selenium_lib = BuiltIn().get_library_instance('ExtendedSelenium2Library') 
     self.internal_variables = {} 

    def for_loop(self, loop_type, start, end, index_var, *keywords): 
     # Format the keywords 
    keywords = self._format_loop(*keywords) 

     # Clean out the internal variables from previous iterations 
     self.internal_variables = {} 

     # This is the actual looping part 
     for loop_iteration in range(int(start), int(end)): 
      keyword_set = self._index_var_swap(loop_iteration, index_var, *keywords) 
      # If it's a one-keyword list with no arguments, then I can use the fastest possible keyword to run it 
      if len(keyword_set) == 1: 
       BuiltIn().run_keyword(keyword_set) 
      # If it's a one-keyword list with arguments, then I can use a faster keyword to run it 
      elif 'AND' not in keyword_set: 
       BuiltIn().run_keyword(*keyword_set) 
      # If it's a multiple-keyword list, then I have to use Run Keywords 
      else: 
       BuiltIn().run_keywords(*keyword_set) 

    def _format_loop(self, *keywords): 
     keywords = list(keywords) # I need to format the keywords as a list. 
     changed = False    # Whether or not I changed anything in the previous iteration. 
     index = 0     # The item index I'm at in the list of keywords 
     del_list = []    # The list of items I need to delete 
     swap_list = []    # The list of items i need to swap to AND for the use of Run Keywords 

     def _new_variable(): 
      # Default to a variable declaration of 'name=' 
      t = 1 
      # If my variable declaration is 'name =' 
      if x[-2:] == ' =': 
       # Reflect that in the value of t 
       t = 2 

      # Count the number of cells until the end of the line 
      length = self._deliminator_search(index, x, *keywords) 

      if length == 3 and not BuiltIn().run_keyword_and_return_status("Keyword Should Exist", keywords[index + 1]): 
       # If I'm assigning a value to my variable 
       self._assign_internal_variable(x[:-t], str(keywords[index + 1])) 

      elif length == 3: 
       # If I'm assigning the result of a keyword without any arguments 
       self._assign_internal_variable_to_keyword(keywords[index][:-t], str(keywords[index + 1])) 
      else: 
       # If I'm assigning the result of a keyword with arguments 
       self._assign_internal_variable_to_keyword(keywords[index][:-t], keywords[index + 1], 
                  keywords[index + 2:index + (length - 1)]) 

      # Add the variable declaration code to the delete list. 
      del_list.extend(range(index - 1, index + length)) 

     # For each argument 
     for x in keywords: 
      # Format it to a string 
      x = str(x) 
      # Assign new variables 
      if x[-1:] == '=': 
       _new_variable() 

      # If the previous element was not changed... 
      if not changed: 
       # If the current item is not the last one on the list... 
       if x != len(keywords) - 1: 
        # If the current item is a deliminator... 
        if x == '\\': 
         # If the next item is a deliminator, delete this item and set changed to True 
         if keywords[int(index) + 1] == '\\': 
          del_list.append(index) 
          changed = True 
         # If the next item is not a deliminator... 
         else: 
          # If this isn't the first deliminator on the list, swap it to an 'AND' 
          if index != 0: 
           swap_list.append(index) 
           changed = True 
          # If this deliminator is in position index=0, just delete it 
          else: 
           del_list.append(index) 
           changed = True 
        # If the current element is not a deliminator, then I don't need to touch anything. 
       # If the current element is the last one, then I don't need to touch anything 
      # If the previous element was changed, then I don't need to "change" this one... 
      elif changed: 
       changed = False 
       # ...but if it's a deliminator then I do need to set it up for the inner for loop it means. 
       if keywords[index] == '\\': 
        keywords[index] = keywords[index]*2 
      index = index + 1 # Advance the index 

     # These actually do the swapping and deleting 
     for thing in swap_list: 
      keywords[thing] = 'AND' 
     del_list.reverse() 
     for item in del_list: 
      del keywords[item] 

     # I also need to activate my variables for this set of keywords to run. 
     keywords = self._activate_variables(*keywords) 

     return keywords 

    @staticmethod 
    def _index_var_swap(loop_iteration, index_var, *keywords): 
     # Format the keywords as a list for iteration 
     keywords = list(keywords) 
     index = 0 
     # For every line in keywords 
     for line in keywords: 
      # Replace all instances of the index_var in the string with the loop iteration as a string 
      keywords[index] = str(line).replace(str(index_var), str(loop_iteration)) 
      index = index + 1 
     return keywords 

    def _assign_internal_variable(self, variable_name, assignment): 
     # This keyword works like any other keyword so that it can be activated by BuiltIn.run_keywords 
     self.internal_variables[variable_name] = assignment 

    def _assign_internal_variable_to_keyword(self, variable_name, keyword, *arguments): 
     # Uses assign_internal_variable to simplify code. 
     # BuiltIn().log_to_console(BuiltIn().run_keyword(keyword, *arguments)) 
     self._assign_internal_variable(variable_name, BuiltIn().run_keyword(keyword, *arguments)) 
     # BuiltIn().log_to_console(self.internal_variables[variable_name]) 

    def _activate_variables(self, *keywords): 
     # Initialize variables 
     keywords = list(keywords) # Cast keywords as a List 
     index = 0     # The index of the keyword I'm looking at 

     # For each keyword 
     for keyword in keywords: 
      keyword = str(keyword) # Cast keyword as a String 
      assignment = False  # Whether or not the found variable name is in a variable assignment 
      for key in self.internal_variables.keys(): 
       key = str(key)  # Cast key as a String 
       # If I can find the key in the keyword and it's not an assignment... 
       if keyword.find(key) > -1 and not assignment: 
        # ...replace the text of the key in the keyword. 
        keywords[index] = keyword.replace(str(key), str(self.internal_variables[key])) 
       # If the keyword I'm looking at is an assignment... 
       if keyword.lower() == 'assign internal variable'\ 
         and keyword.lower() != 'assign internal variable to keyword': 
        # ...then my next keyword is going to definitely be a known variable, so I don't want to touch it. 
        assignment = True 
       # If the keyword I'm looking at is not an assignment... 
       else: 
        # ...set assignment to False just in case the previous one happened to be an assignment. 
        assignment = False 
      index = index + 1 # Advance the index 
      # NOTE: Replaces the EXACT text, even if it's in another keyword or variable, so be very careful 
     return keywords  # Return the list of keywords to be used in the format loop 

    @staticmethod 
    def _deliminator_search(start, keyword, *keywords): 
     index = 0 
     while keyword != '\\' and keyword != '\\\\': 
      keyword = keywords[int(start) + index] 
      index = index + 1 
     return index 

這裏是測試它的代碼:

*** Variables *** 
${blue_squadron} =  Blue 
${gold_squadron} =  Gold 
${green_squadron} =  Green 
${red_squadron} =  Red 

*** Test Cases *** 
Test For Loop 
    For Loop IN RANGE 0 1 INDEX0 
    ...  \\ For Loop IN RANGE 1 6 INDEX1 
    ...  \\ \\ {standing_by}=  standing by 
    ...  \\ \\ Run Keyword If  INDEX1 == 1  Log to Console This is ${red_squadron} Leader standing by 
    ...  \\ \\ Run Keyword Unless INDEX1 == 1  Log to Console ${red_squadron} INDEX1 {standing_by} 
    ...  \\ For Loop IN RANGE 1 6 INDEX2 
    ...  \\ \\ standing_by_2 =  standing by 
    ...  \\ \\ Run Keyword If  INDEX2 == 1  Log to Console This is ${gold_squadron} Leader standing by 
    ...  \\ \\ Run Keyword Unless INDEX2 == 1  Log to Console ${gold_squadron} INDEX2 standing_by_2 
    ...  \\ For Loop IN RANGE 1 6 INDEX3 
    ...  \\ \\ standing_by_3=  Get Blue Squadron 
    ...  \\ \\ Run Keyword If  INDEX3 == 1  Log to Console This is ${blue_squadron} Leader standing by 
    ...  \\ \\ Run Keyword Unless INDEX3 == 1  Log to Console ${blue_squadron} INDEX3 standing_by_3 
    ...  \\ For Loop IN RANGE 1 6 INDEX4 
    ...  \\ \\ standing_by_4 =  Get Green Squadron null input 
    ...  \\ \\ Run Keyword If  INDEX4 == 1  Log to Console This is ${green_squadron} Leader standing by 
    ...  \\ \\ Run Keyword Unless INDEX4 == 1  Log to Console ${green_squadron} INDEX4 standing_by_4 

*** Keywords *** 
Get Blue Squadron 
    [Return] standing by 

Get Green Squadron 
    [Arguments]  ${null_input} 
    [Return]  standing by 

爲了澄清添加到該解決方案,我不需要變量是在一個特定的格式。如果你希望進一步精確地指定你的變量是什麼,但沒有必要,可以這樣做。我寧願在這種計劃中留下更多的選擇。