2017-04-11 8 views
1

私はPythonを初めて使用しているので、重複しているか、あまりにも簡単な質問であれば謝ります。私はKafka-pythonライブラリを使ってKafkaからデータを送信/読み込む2つのクラスを呼び出すコーディネータークラスを作成しました。私はコーディネータークラスの単体テストを書こうと思っていますが、これについて最善を尽くすにはどうすればいいか分かりません。私は虚偽のオブジェクトを渡すことができる代替のコンストラクタを作ることができることを期待していましたが、test_mycoordinatorを解決できないというエラーが発生したため、これは動作していないようです。このクラスを間違った方法でテストするつもりですか?私はそれをテストする必要がありますpythonic方法はありますか?ここでテストのためだけにPythonコンストラクタの一部を模擬しますか?

は私のテストクラスは、これまでのように見えるものです:

import unittest 
from mock import Mock 
from mypackage import mycoordinator 

class MyTest(unittest.TestCase): 

    def setUpModule(self): 
     # Create a mock producer 
     producer_attributes = ['__init__', 'run', 'stop'] 
     mock_producer = Mock(name='Producer', spec=producer_attributes) 

     # Create a mock consumer 
     consumer_attributes = ['__init__', 'run', 'stop'] 
     data_out = [{u'dataObjectID': u'test1'}, 
        {u'dataObjectID': u'test2'}, 
        {u'dataObjectID': u'test3'}] 
     mock_consumer = Mock(
      name='Consumer', spec=consumer_attributes, return_value=data_out) 

     self.coor = mycoordinator.test_mycoordinator(mock_producer, mock_consumer) 

    def test_send_data(self): 
     # Create some data and send it to the producer 
     count = 0 
     while count < 3: 
      count += 1 
      testName = 'test' + str(count) 
      self.coor.sendData(testName , None) 

そして、ここでは、私がテストしようとしているクラスです。

class MyCoordinator(): 
    def __init__(self): 
     # Process Command Line Arguments using argparse 
     ... 

     # Initialize the producer and the consumer 
     self.myproducer = producer.Producer(self.servers, 
              self.producer_topic_name) 

     self.myconsumer = consumer.Consumer(self.servers, 
              self.consumer_topic_name) 

    # Constructor used for testing -- DOES NOT WORK 
    @classmethod 
    def test_mycoordinator(cls, mock_producer, mock_consumer): 
     cls.myproducer = mock_producer 
     cls.myconsumer = mock_consumer 

    # Send the data to the producer 
    def sendData(self, data, key): 
     self.myproducer.run(data, key) 

    # Receive data from the consumer 
    def getData(self): 
     data = self.myconsumer.run() 
     return data 
+0

wher edoes 'mycordinator'はあなたの' setUpModule'から来ますか? – dm03514

+0

@ dm03514申し訳ありませんが、私はインポートステートメントを修正するために質問を編集した名前を変更していたときにタイプミスがありました – jencoston

答えて

3

別のコンストラクタを提供する必要はありません。 Mocking はあなたのコードにパッチを貼り、オブジェクトをモックで置き換えます。テスト方法にはmock.patch() decoratorを使用してください。生成されたモックオブジェクトへの参照を渡します。

両方producer.Producer()consumer.Consumer()は、その後、あなたがインスタンスを作成前を嘲笑されています

import mock 

class MyTest(unittest.TestCase): 
    @mock.patch('producer.Producer', autospec=True) 
    @mock.patch('consumer.Consumer', autospec=True) 
    def test_send_data(self, mock_consumer, mock_producer): 
     # configure the consumer instance run method 
     consumer_instance = mock_consumer.return_value 
     consumer_instance.run.return_value = [ 
      {u'dataObjectID': u'test1'}, 
      {u'dataObjectID': u'test2'}, 
      {u'dataObjectID': u'test3'}] 

     coor = MyCoordinator() 
     # Create some data and send it to the producer 
     for count in range(3): 
      coor.sendData('test{}'.format(count) , None) 

     # Now verify that the mocks have been called correctly 
     mock_producer.assert_has_calls([ 
      mock.Call('test1', None), 
      mock.Call('test2', None), 
      mock.Call('test3', None)]) 

だから、一瞬test_send_dataが呼び出され、mock.patch()コードがモックオブジェクトとproducer.Producerの参照を置き換えます。あなたのMyCoordinatorクラスは、実際のコードではなくそれらのモックオブジェクトを使用します。

は、私がproducerconsumerはトップレベルのモジュール名であることを前提に作られてきたなど、新しいモックオブジェクト(同じオブジェクトmock_producer.return_valueが参照する)producer.Producer()リターンを呼び出します。そうでない場合は、完全なインポートパスを指定します。 mock.patch()文書から:

target should be a string in the form 'package.module.ClassName' . The target is imported and the specified object replaced with the new object, so the target must be importable from the environment you are calling patch() from. The target is imported when the decorated function is executed, not at decoration time.

+0

@ mock.patch( 'consumer.Consumer'、autospec = True) ?より具体的には、私は嘲笑したいものをどのように知っていますか?テストを実行しようとするとエラーが表示されます(ImportError:No moduleという名前のコンシューマー)。私のクラスConsumerは、mypackageにあるconsumer.pyにあります。だから私はパッチのConsumerクラスへの完全なパスを何とか指定する必要がありますか? – jencoston

+0

@jencoston:あなたはあなたのコードで 'consumer'がどこから来たのかを含めませんでした。私はそれがモジュールの名前であると仮定しました。 'consumer'がパッケージの中にある場合は、インポートのフルネームを提供します:' mock.patch( 'package.consumer.Consumer') '。 'mock.patch'はモジュールをインポートして名前にパッチを当てます(パスの最後の部分)。 –

関連する問題