2016-11-03 1 views
0

** kwargsを受け入れる関数を嘲笑するのに問題があります。このシナリオでは、私はClassAを持っています(特定のケースでは私が書いたことはありません)。そして、それは** kwargsの関数を持っています。 ClassBのインスタンスを持ち、** kwargs関数を呼び出すClassB。クラスAの関数呼び出しを嘲笑してClassBをテストしたい。** kwargsを受け付ける関数を嘲笑する

これまで私が試したのはこれまでのことで、両方の試みで、私はTypeErrorで終わった。これを行う方法はありますか?私はこれの別の側面を考え直すべきですか?

import unittest 


#a class i have no control over. Has a function accepting **kwargs 
class ClassA(object): 

    def classFunctionAcceptingKwargs(self, **kwargs): 
     return kwargs["a"] + kwargs["b"] 

# a mock of the above class 
class Mock_ClassA(object): 

    def __init__(self): 
     self.mockclassFunctionAcceptingKwargs = lambda **kwargs: None 

    def classFunctionAcceptingKwargs(self, **kwargs): 
     #FAILS: TypeError: mockFunctionAcceptingKwargs() takes exactly 0 arguments (1 given) 
     return self.mockclassFunctionAcceptingKwargs(kwargs) 
     #ALSO FAILS: TypeError: mockFunctionAcceptingKwargs() argument after ** must be a mapping, not set 
     #return self.mockclassFunctionAcceptingKwargs(**{kwargs["a"] + kwargs["b"]}) 

#class B calls the class A kwargs but exposes a function with a dict 
class ClassB(object): 
    def __init__(self, classA): 
     self.classA = classA 

    def doSomething(self, dict): 
     return self.classA.classFunctionAcceptingKwargs(**dict) 

class TestClassA(unittest.TestCase): 

    def runTest(self): 
     a = ClassA() 
     result = a.classFunctionAcceptingKwargs(**{"a":1, "b": 2}) 
     self.assertEqual(result, 3) 

class TestClassB(unittest.TestCase): 

    def runTest(self): 

     mock = Mock_ClassA() 
     def mockFunctionAcceptingKwargs(**kwargs): 
      self.assertEqual(kwargs["a"], 1) 
      self.assertEqual(kwargs["b"], 2) 

     mock.mockclassFunctionAcceptingKwargs = mockFunctionAcceptingKwargs 
     b = ClassB(mock) 
     b.doSomething({"a": 1, "b": 2}) 

スタックトレース:

Test Name: TestClassB 
Test Outcome: Failed 
Result StandardError: 
====================================================================== 
ERROR: runTest (module1.TestClassB) 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "C:\test\module1.py", line 49, in runTest 
    b.doSomething({"a": 1, "b": 2}) 
    File "C:\test\module1.py", line 28, in doSomething 
    return self.classA.classFunctionAcceptingKwargs(**dict) 
    File "C:\test\module1.py", line 18, in classFunctionAcceptingKwargs 
    return self.mockclassFunctionAcceptingKwargs(kwargs) 
TypeError: mockFunctionAcceptingKwargs() takes exactly 0 arguments (1 given) 
---------------------------------------------------------------------- 
Ran 1 test in 12.873s 
FAILED (errors=1) 

答えて

2

私はあなたが別の関数を呼び出している理由はわかりません。あなたインスタンスを持っている必要がありますが​​機能を属性場合しかし、その後、ちょうど**kwargskwargs辞書を渡す:

class Mock_ClassA(object): 
    # ... 
    def classFunctionAcceptingKwargs(self, **kwargs): 
     return self.mockclassFunctionAcceptingKwargs(**kwargs) 

classFunctionAcceptingKwargsが存在するためにあなたが必要とするすべてがある場合は、すべてのことラムダを呼び出す必要はありません:

class Mock_ClassA(object): 
    def __init__(self, mock_result): 
     self.mock_result = mock_result 
    def classFunctionAcceptingKwargs(self, **kwargs): 
     self.called_with = kwargs 
     return self.mock_result 

その後、ちょうどあなたがテストのためにClassBに戻って渡される必要があるものは何でも嘲笑戻り値を渡し、その後あなたが右の値が大きすぎに渡されたことを確認することができます。

mock = Mock_ClassA(3) # to return 3 back to the caller 
b = ClassB(mock) 
b.doSomething({"a": 1, "b": 2}) 
self.assertEqual(mock.called_with, {'a': 1, 'b': 2}) 
あなたが渡すためにモックオブジェクトを構築するために unittest.mock libraryを使用したい場合があり

(Pythonの3で利用可能にし、Pythonの2のためのbackportをインストールすることができます)。それはあなたが嘲笑ClassAを作成でき、その後、モックが予想される方法で使用されたかどうかをテストするためにAPIを使用します:モック層としてunittest.mock

try: 
    # Python 3 
    from unittest import mock 
except ImportError: 
    # Python 2, backport 
    import mock 

class TestClassB(unittest.TestCase): 
    def runTest(self): 
     mockA = mock.Mock(spec=ClassA) # only accept attributes ClassA also has 
     mockA.classFunctionAcceptingKwargs.return_value = 3 # or whatever else you want it to return 
     b = ClassB(mockA) 
     b.doSomething({"a": 1, "b": 2}) 
     mockA.classFunctionAcceptingKwargs.assert_called_once_with(a=1, b=2) 

デモ:

>>> from unittest import mock 
>>> class ClassA(object): 
...  def classFunctionAcceptingKwargs(self, **kwargs): 
...   return kwargs["a"] + kwargs["b"] 
... 
>>> class ClassB(object): 
...  def __init__(self, classA): 
...   self.classA = classA 
...  def doSomething(self, dict): 
...   return self.classA.classFunctionAcceptingKwargs(**dict) 
... 
>>> mockA = mock.Mock(spec=ClassA) 
>>> mockA.classFunctionAcceptingKwargs.return_value = 3 
>>> b = ClassB(mockA) 
>>> b.doSomething({"a": 1, "b": 2}) 
3 
>>> mockA.classFunctionAcceptingKwargs.assert_called_once_with(a=1, b=2) # passes, no exception raised 
>>> mockA.mock_calls 
[call.classFunctionAcceptingKwargs(a=1, b=2)] 
関連する問題