2017-07-24 548 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 

为了澄清添加到该解决方案,我不需要变量是在一个特定的格式。如果你希望进一步精确地指定你的变量是什么,但没有必要,可以这样做。我宁愿在这种计划中留下更多的选择。