2017-02-22 2 views
1

私はクラス「ラッパー」を持っています。ラッパーはオブジェクトから継承しますが、主な責任はテスト中にメソッド呼び出しをセレンに呼び出すことです。それはそれの関数スコープは、呼び出された自己へのアクセス権を与えますか?

__init__(self, object_to_wrap, actions={}, **kwargs) 

一部が機能__init__メソッドのシグネチャですされたのinitメソッドに引数として辞書を取るために、そして__getattr__魔法の方法 (シグネチャを定義することによって、object_to_wrapオブジェクトの属性としてのキーを公開することです: __getattr__(self, item):) とitemself.actionsのキーを確認してください。見つかった場合、メソッドが呼び出されます。テストコードで

、初期化はのようになります。

def navigate(scoped_self, to=''): 
    self.driver.switch_to_default_content() 
    self.driver.switch_to.frame(to) 
    scoped_self.navigations.append(to) 
    # the navigate method is scoped in an 
    # instance method of the test class, so it has access to self 

だから、私の質問は、私はスコープを作ることができるか、である、または上記の方法ではself、私Wrapperクラスのスコープも、テストクラスではない?私はこの質問に探しています解決策が見つかった場合に明確にするために

、ナビゲート実装があることを変更します

def navigate(scoped_self, to=''): 
    self.object_to_wrap.switch_to_default_content() 
    self.object_to_wrap.switch_to.frame(to) 

また明確にするため、私は私が探しているものをかなり確信していますまさにJavascripts Function.prototype.bindが達成するものです。

UPDATE:ラッパークラスの内部、例えば移動などの方法を定義ラッパークラステスト固有のロジックを持つことができないように、オプションではありません。テストスイートは、n> 1 DOMで実行されますが、完全に無関係です。たとえば、テストの1つでは、メソッドalert_handlers(window.alert関数を上書きし、文字列として表示されたアラートを返す)、別のメソッドがnavigateメソッドを必要とし、3番目のメソッドで両方が必要な場合があります。

UPDATE#2:c17rから以下の回答のおかげで、私はのgetAttributeなしコードは、私たちはすでに達成していた何かを求めていたかのように見えるだろうと、私の例に含まれていることに気づきました。私が探しているのは、上記のnavigateメソッドの能力で、scoped_selfがWrapperのインスタンスであることです。あなたはJavaScriptを使用して慣れていない場合は、;また、私は特に「動的」(機能にFunction.prototype.bindは、「動的」thisはmyEventListener.bind(ウィンドウ)であるthisを設定する方法をscoped_selfを渡す方法を探しています

体にイベントリスナーを作成し、結合なしthisをCONSOLE.LOG、その後、結合して、違いを見るために)

さらに、私はそれが私が探しています解決せずに実装例を与えるために役立つかもしれない考え出しの場合。これは、現在正常に機能している:

class Wrapper(object): 
    def __init__(self, wrapped, actions={}): 
     self.wrapped = wrapped 
     self.actions = actions 
     self.navigations = [] # EXAMPLE, SEE THE TEST CLASS CODE 

    def __getattr__(self, item): 
     if item in self.actions: 
      return self.actions[item] 
     # do other fancy stuff here 
     # UPDATE #2: added for clarity. this is the current implementation 
     orig_attr = self.wrapped.__getattribute__(item) 
     if callable(orig_attr): 
      def hooked(*args, **kwargs): 
       self.pre(item, *args, **kwargs) 
       self.err = False 
       try: 
        result = orig_attr(*args, **kwargs) 
       except Exception as e: 
        #logs 
        self.post(*args, **kwargs) 
        raise 
      if type(self.wrapped) == type(result): 
       return self 
      return result 
     return hooked 
    else: 
     return orig_attr 

class SomeTest(): 
    #blah blah init stuff, set self.driver = selenium.webdriver.Phantomjs 
    def spawn_actions(self): 
     def navigate(scoped_self, to=''): 
      self.driver.switch_to_default_content() 
      self.driver.switch_to.frame(to) 
      scoped_self.navigations.append(to) # <--- appended to wrapper.navigations  
     return {'navigate': navigate} 

    def run(self): 
     driver = Wrapper(self.driver, self.spawn_actions()) 
     driver.get(url) 
     driver.navigate('New Request') 
     # fun tests! 

答えて

0

私が正しくあなたを理解していれば、3つの事:

  1. Wrapperはそうdriver.get()が正しく動作しません、包まれた項目までの任意の未知の関数を渡す必要があります。
  2. 、それが実際に辞書ベース関数にselfを渡す必要WrapperWrapper
  3. で定義されたかどうようnavigate関数は、最初のパラメータとしてselfを必要とします。 __getattr__は実際に関数を呼び出さないので、デコレータの仕組みと同様に、基礎となる関数を適切に呼び出す関数を返さなければなりません。このよう

class Driver(object): 
    def get(self, url): 
     print('get') 
     print(repr(self)) 
     print(repr(url)) 
     print('--') 


class Wrapper(object): 
    def __init__(self, wrapped, actions={}): 
     self.wrapped = wrapped 
     self.actions = actions 

    def __getattr__(self, item):    
     if item in self.actions: 
      def unwrap(*args, **kwargs): 
       return self.actions[item](self, *args, **kwargs) 
      return unwrap 
     else: 
      return getattr(self.wrapped, item) 


class Test(object): 
    def __init__(self): 
     self.driver = Driver(); 

    def spawn_actions(self): 
     def navigate(self, to=''): 
      print('navigate') 
      print(repr(self)) 
      print(repr(to)) 
      print(repr(self.wrapped)) 
      print('--') 

     return { 
      'navigate': navigate 
     } 

    def run(self): 
     driver = Wrapper(self.driver, self.spawn_actions()) 
     driver.get('url') 
     driver.navigate('thing') 

今呼び出す:

t = Test() 
t.run() 

出力:

get 
<__main__.Driver object at 0x104008630> 
'url' 
-- 
navigate 
<__main__.Wrapper object at 0x104008ba8> 
'thing' 
<__main__.Driver object at 0x104008630> 
-- 

EDIT

また、動的にunwrap機能を返す代わりに__getattr__のインスタンスにメソッドをバインドすることができます。

import types 
class Wrapper(object): 
    def __init__(self, wrapped, actions={}): 
     self.wrapped = wrapped 

     for name, func in actions.items(): 
      setattr(self, name, types.MethodType(func, self)) 

    def __getattr__(self, item): 
     return getattr(self.wrapped, item) 
+0

あなたは正しく私を理解しなかった、と私は(簡潔にするため)__getattr__のすべてを除外をお詫び申し上げます。実際の実装がどのように見えるかについての私の更新を見てください。コードには含まれないというインスタンスメソッドが複数あることに注意してください(また、製品のプロダクションコードに近すぎるため) – h3xc0ntr0l

+0

コードを徹底的に読み直した後、私の質問に答えました:)実装があるマシンに着くとすぐにテストします。 – h3xc0ntr0l

関連する問題