0
votes

I have been tasked with adding unit testing to an application and I find myself needing help with setting up the mocks for the database queries.

We have a model:

class Category(db.Model):
__tablename__ = "category"

id = db.Column(db.Integer, primary_key=True)
company_id = db.Column(db.Integer, db.ForeignKey("company.id"))
name = db.Column(db.String(150))
modified = db.Column(db.DateTime(), default=datetime.datetime.utcnow())
status = db.Column(db.Integer)
image = db.Column(db.String(120))
color = db.Column(db.String(20))

old_category_id = db.Column(db.Integer, default=-1)

And a class PBCategory with a bunch of methods, but we are starting with the first

class PBCategory:

@classmethod
def list_of_categories(cls, user, select_deleted=False):
    """
    List of categories for the users company
    :param user: User making the request
    :type user: modules.pb_auth.PBAuthUser
    :param select_deleted: Also return deleted categories
    :return: List of Category objects
    :rtype: list of collections.namedtuple
    """

    query = Category.query.filter(Category.company_id == user.company_id)
    if not select_deleted:
        query = query.filter(Category.status == constants.CATEGORY_ACTIVE)

    return query.order_by(Category.name.asc()).all()

In my conftest I have the following fixtures:

@pytest.fixture
def mock_client():
    #Setup mock application
    app_mock = Flask(__name__)
    db = SQLAlchemy(app_mock)
    db.init_app(app_mock)
    return app_mock

@pytest.fixture
def mock_get_sqlalchemy(mocker):
    mock = mocker.patch("flask_sqlalchemy._QueryProperty.__get__").return_value = mocker.MagicMock()
    return mock

@pytest.fixture(scope='module')
def list_of_categories():
    categories = []

    for x in range(5):
        new_category = Category(
            company_id=1,
            name='test category' + str(x),
            status=constants.CATEGORY_ACTIVE
        )
        categories.append(new_category)

    return categories

This is the first test we try to run:

def test_list_categories(
        mock_client,
        mock_get_sqlalchemy,
        list_of_categories,
        new_user
):
    with mock_client.app_context():
        mock_get_sqlalchemy().order_by = list_of_categories
        print(list_of_categories)
        results = PBCategory.list_of_categories(new_user, False)

    print(results)

    assert len(results) > 0

The issue is, no matter how I format the call signature (return_value.order_by, return_value.order_by.return_value.all, etc) I get the following error:

>       assert len(results) > 0
E       AssertionError: assert 0 > 0
E        +  where 0 = len(<MagicMock name='__get__().filter().filter().order_by().all()' id='140592881056736'>)

tests/unit_tests/modules/test_pb_category.py:27: AssertionError

I have looked at this question, but it didn't get me too far... How to mock <ModelClass>.query.filter_by() in Flask-SqlAlchemy

Any help would be hugely appreciated.