2017-08-08 113 views
1

我正在为GUI应用程序编写一个测试自动化框架,并且我想使用装饰器来捕获类中方法生成的弹出窗口(例如,登录)Python装饰类中的方法和继承

我有一个_BaseWindow类,用于跟踪每个窗口中GUI的元素(例如:菜单栏,弹出窗口),它由MainWindow类继承。 MainWindow类跟踪主菜单上的按钮,以及单击其中一个按钮时生成的对话框。例如,如果您单击主菜单上的登录按钮,则会加载登录对话框。

class _BaseWindow(object): 
    def __init__(self): 
     self.window = "windowName" 
     self.popup = None 

    def _catch_popups(self, method): 
     from functools import wraps 
     @wraps(method) 
     def wrapper(*args, **kwargs): 
      # get a list of the open windows before the method is run 
      before = getwindowlist() 

      retval = method(*args, **kwargs) 

      # get a list of the open windows after the method is run 
      after = getwindowlist() 

      for window in after: 
       if window not in before: 
        self.popup = window 
        break 

      return retval 
     return wrapper 

class MainWindow(_BaseWindow): 
    def __init__(self): 
     self.dialog = None 
     self.logged_in = False 

     # buttons 
     self.login_button = "btnLogin" 

     super(MainWindow, self).__init__() 

    def click_login(self): 
     if not self.dialog: 
      mouseclick(self.window, self.login_button) 
      self.dialog = LoginDialog() 

class LoginDialog(_BaseWindow): 
    def __init__(self): 
     # buttons 
     self.button_ok = "btnLoginOK" 
     self.button_cancel = "btnLoginCancel" 
     # text input 
     self.input_username = "txtLoginUsername" 
     self.input_password = "txtLoginPassword" 

     super(LoginDialog, self).__init__() 

    @MainWindow._catch_popups 
    def perform_login(self, username, password): 
     input_text(self.input_username, username) 
     input_text(self.input_password, password) 
     mouseclick(self.window, self.button_ok) 

当我尝试测试这个我得到:

Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "objects/gui.py", line 185, in <module> 
    class LoginDialog(_BaseWindow): 
    File "objects/gui.py", line 236, in LoginDialog 
    @MainWindow._catch_popups 
TypeError: unbound method _catch_popups() must be called with 
MainWindow instance as first argument (got function instance instead) 

当我试图指定MainWindow instance为:

@MainWindow._catch_popups(self) 

我得到:

Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "objects/gui.py", line 185, in <module> 
    class LoginDialog(_BaseWindow): 
    File "objects/gui.py", line 236, in LoginDialog 
    @MainWindow._catch_popups(self) 
NameError: name 'self' is not defined 

任何帮助理解这将是最重要的ppreciated。

+3

你需要做'_catch_popups'一个[静态方法](https://stackoverflow.com/questions/735975 /静态方法合蟒)。 –

回答

3

这里有你的结构错误。在类体中定义的实例方法与类同时创建,因此是未绑定的方法。因此,在创作时,没有self可供参考。您的_catch_popups方法需要一个实例。

自然的解决办法是将_catch_popups更改为staticmethod,它返回一个实例方法。

@staticmethod 
def _catch_popups(method): 
    from functools import wraps 
    @wraps(method) 
    def wrapper(self, *args, **kwargs): 
     before = getwindowlist() 
     retval = method(self, *args, **kwargs) # notice that self is passed 
     after = getwindowlist() 
     try: self.popup = next(w for w in after if w not in before) 
     return retval 
    return wrapper 

这里,self明确地传递给method,因为它仍然是一个未绑定的实例方法时,被传递给装饰它。


正如您的评论中所建议的,您希望将弹出窗口添加到窗口实例。要做到这一点,你可以更新以下方法:

def click_login(self): 
    if not self.dialog: 
     mouseclick(self.window, self.login_button) 
     self.dialog = LoginDialog(self) # pass window to dialog __init__ 

class LoginDialog(_BaseWindow): 
    def __init__(self, parent_window): 
     # original code 
     self.parent = parent_window 

@staticmethod 
def _catch_popups(method): 
    def wrapper(self, *args, **kwargs): 
     # original code 
     try: self.parent.popup = ... # add to parent rather than self 
     return retval 
    return wrapper 
+0

谢谢,这工作。原来的问题是固定的,但是当我尝试访问self.popup的值与初始化(无)相同,但是当我访问self.dialog.popup时,弹出窗口被捕获。 – AllenMoh

+1

@AllenMoh这是预期的。您的'perform_login'方法在您的对话框类中,因此对话框实例将被传递给'_catch_popups'创建的实例方法。如果要捕获窗口本身的弹出窗口,则必须为窗口提供对窗口的引用,然后将该属性分配给窗口。 –

+1

@AllenMoh我已经添加了一些更新的方法,将这个属性分配给主窗口。 –