5

I am currently trying (and failing) to perform unit tests on my simple app which posts data to a MySQL database. Below is the unit test I am trying to run, not sure if this will eve test my code successfully, but is coming up with a TypeError: 'Mock' object is not iterable

Unit_Test.py

from unittest import mock
from unittest.mock import patch, MagicMock
from unittest.mock import Mock


from source.src.scores import *


@mock.patch('source.src.scores.request')
def test_add_scores(self):
    columns = ["Match_ID", "Home_Score", "Away_Score"]
    values = [1, 1, 1]

    expected_score = {columns[i]: values[i] for i in range(len(columns))}

    with patch('source.src.scores.mysql.connector') as patch_connector:

        cursor = Mock()
        cursor.fetchone.return_value = values
        cursor.column_names = columns
        connect = Mock()
        connect.cursor.return_value = cursor

        patch_connector.connect.return_value = connect

        with patch('source.src.scores.jsonify') as json:
            json.return_value = expected_score

            json_return, http_code = add_score()

        assert patch_connector.connect.called
        assert connect.cursor.called
        assert connect.commit.called
        assert cursor.fetchone.called
        self.assertEqual(cursor.execute.call_count, 2)
        self.assertDictEqual(expected_score, json_return)


if __name__ == '__main__':
test_add_scores()

scores.py

 def execute_query(cursor, qry):
print("Executing query...")
cursor.execute(qry)


def execute_query_json(cursor, qry, cnx):
print("Executing JSON query...")
cursor.execute(qry, (request.json['Match_ID'],
                     request.json['Home_Score'],
                     request.json['Away_Score'],
                     )
               )
cnx.commit()


def add_score():
cnx = conn_db()
cursor = cnx.cursor()
print("Updating score")

execute_query_json(cursor, "INSERT INTO scores (Match_ID, Home_Score, Away_Score) VALUES (%s,%s,%s)", cnx)
execute_query(cursor, "SELECT * FROM scores WHERE Score_ID=" + str(cursor.lastrowid))
recs = extract_records(cursor)

return jsonify({'discipline':recs}), 201

Any helps is greatly appreciated

L Thompson
  • 151
  • 1
  • 2
  • 12
  • Try to specify which line the error occurs at. In the case of the "not iterable" error usually its just because we used [] where we should use () or something. – KuboMD Dec 13 '18 at 19:40
  • can you post the stack trace, please. – e.s. Dec 13 '18 at 20:00
  • 1
    Unrelated, but prefer `{k:v for k, v in zip(columns, values)}` (or even `dict(zip(columns, vertices))` to iterating over indices. – chepner Dec 13 '18 at 20:46

4 Answers4

8

When you create a mock, you sometimes have to let it know how to respond to some of the calls that will be expected of it. Take, for example:

class A(object):
  def __init__(self):
    self.items = []

If you were to create a Mock to use in place of an instance of A, the mock wouldn't automagically know how to respond if you attempt to request .items. You can overcome this by telling the Mock what to return for a particular property by passing that as a keyword to the constructor, like so:

mocked_a = Mock(items = [])

Now, when you call mock_a.items you'll get an empty list, so iteration won't fault.

g.d.d.c
  • 46,865
  • 9
  • 101
  • 111
4

To make mock iterable you need to mock its __iter__ method. For example:

cursor = Mock()
cursor.__iter__.return_value = []
Vladimir Prudnikov
  • 6,974
  • 4
  • 48
  • 57
2

The error message TypeError: 'Mock' object is not iterable is telling you one of your mocked object is not iterable: you are trying but cannot iterate through it (for elem in ...) or call list() on it. For an object to be iterable it needs to implement the __iter__ 'magic' method (see https://stackoverflow.com/a/5262255/12519542)

The MagicMock object (which you import in your test) implements __iter__ along with other double-underscore magic methods. You could try making your cursor and connect object MagicMock instances instead.

bricoletc
  • 420
  • 3
  • 12
1

It took me a while, trying different things. The MagicMock() never works for me, but the Magic() does. Thanks!

This works:

mocked_a = Mock(items = [])

Then, mocked_a.items will return []

This with Mock() doesn't work, neither with MagicMock(). I can't assign [] to cursor, regardless of how I tried!

cursor = Mock()

cursor.__iter__.return_value = []

or:

cursor = MagicMock()

cursor.__iter__.return_value = []

pdn2020
  • 91
  • 1
  • 8