Python-mock: mocking pymongo's Cursor and Collection in the same test case
<p>I want to make a mock test for some mongo queries, but I had a problem when I tried to mock two diferent mongo objects (Cursor and Collection) in the same scope.
I can't put the original code here, but I made a generic with the same problem.</p>

<p>This is the function I want to test (using find and distinct):</p>

<pre><code>def get_some_info(date1, date2):
    data = collection.find({"timestamp": {"$lt": date1, "$gt": date2})
    id_list = data.distinct("id")

    for id in id_list :
       collection.find({"id" : id})
</code></pre>

<p>This is the test code:</p>

<pre><code>@mock.patch.object(Collection, "find")
@mock.patch.object(Cursor, "distinct")
def test_get_some_info(self, mock_distinct, mock_find):
    date1 = datetime.datetime()
    date2 = datetime.datetime()
    mock_distinct.return_value = ["id1", "id2"]
    find_parameters1 = {"timestamp": {"$lt": date1, "$gt": date2}
    find_parameters2 = {"id" : "id1"}
    self.my_class.get_some_info(date1, date2)
    mock_find.assert_called_with(find_parameters1)
    mock_find.assert_any_call(find_parameters2)
</code></pre>

<p>When I run the test, I have this error message:</p>

<blockquote>
  <p>'%s call not found' % expected_string AssertionError: find({"id" :
  "id1"}) call not found</p>
</blockquote>

<p>So I printed the value of id_list:</p>

<pre><code>def get_some_info(date1, date2):
    data = collection.find({"timestamp": {"$lt": date1, "$gt": date2})
    id_list = data.distinct("id")
    print id_list

    for id in id_list :
        collection.find({"id" : id})
</code></pre>

<p>This is the value of id_list:</p>

<blockquote>
  <p>MagicMock name='find().distinct()' id='139719585597776'</p>
</blockquote>

<p>But the expected is: ["id1", "id2"]</p>

<p>When I comment the Cursor's mock, the value of id_list is the same as before:</p>

<pre><code>#@mock.patch.object(collection, "distinct")
@mock.patch.object(Cursor, "find")
def test_get_some_info(self, mock_find):
    date1 = datetime.datetime()
    date2 = datetime.datetime()
    mock_distinct.return_value = ["id1", "id2"]
    find_parameters1 = {"timestamp": {"$lt": date1, "$gt": date2}
    find_parameters2 = {"id" : "id1"}
    self.my_class.get_some_info(date1, date2)
    mock_find.assert_called_with(find_parameters1)
    mock_find.assert_any_call(find_parameters2)

&lt;MagicMock name='find().distinct()' id='140089689306448'&gt;
</code></pre>

<p>I think the code is always catching the "distinct" value from Collection, not from Cursor.
Does anybody had the same problem?</p>