Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using Django Q filters with mocked instances, doesn't work as expected! #90

Open
mehdi-essebbar opened this issue Sep 3, 2018 · 1 comment

Comments

@mehdi-essebbar
Copy link

THE METHOD BEING TESTED:



from repo.models import Expert
from django.db.models import Q

def method_to_test():
experts = Expert.objects.filter(Q(firstname__iregex='^a.*'))
return experts



THE TEST IMPLEMENTATION:



def test_q_expr(experts):
@mocked_relations(Expert)
def mocking_instances(qs):

    for exp in experts:
        m = MockModel(firstname='a' + exp.firstname, user=exp.user)
        Expert.objects.add(m)

    vals = method_to_test()
    print(len(vals))
    return vals

results = mocking_instances()
print(len(results))
assert False


THE ERROR OUTPUT:



==================================== FAILURES ====================================
__________________________________ test_q_expr ___________________________________

experts = [<Expert: Zmzhn 70214>, <Expert: Tt2vj JBL94>, <Expert: F4vm7 JU0H6>]

def test_q_expr(experts):
    @mocked_relations(Expert)
    def mocking_instances(qs):

        for exp in experts:
            m = MockModel(firstname='a' + exp.firstname, user=exp.user)
            Expert.objects.add(m)

        vals = method_to_test()
        print(len(vals))
        return vals



  results = mocking_instances()

tests/test_immodvisor.py:48:


../../.venv/local/lib/python2.7/site-packages/mock/mock.py:1305: in patched
return func(args, **keywargs)
../../.venv/local/lib/python2.7/site-packages/django_mock_queries/mocks.py:299: in absorb_mocks
return target(test_case)
tests/test_immodvisor.py:42: in mocking_instances
vals = method_to_test()
tests/test_immodvisor.py:30: in method_to_test
experts = Expert.objects.filter(Q(firstname__iregex='^a.
'))
../../.venv/local/lib/python2.7/site-packages/django_mock_queries/query.py:108: in filter
results = self._filter_q(results, x)
../../.venv/local/lib/python2.7/site-packages/django_mock_queries/query.py:96: in _filter_q
results = merge(results, filtered)
../../.venv/local/lib/python2.7/site-packages/django_mock_queries/utils.py:13: in merge
return first + list(set(second) - set(first))
../../.venv/local/lib/python2.7/site-packages/django_mock_queries/query.py:415: in hash
return hash_dict(self)
../../.venv/local/lib/python2.7/site-packages/django_mock_queries/utils.py:282: in hash_dict
return hash(tuple(sorted((k, v) for k, v in obj_values.items() if not fields or k in fields)))


self = <User: testquqwlb>

def __hash__(self):
    if self._get_pk_val() is None:
       raise TypeError("Model instances without primary key value are unhashable")

E TypeError: Model instances without primary key value are unhashable

../../.venv/local/lib/python2.7/site-packages/django/db/models/base.py:615: TypeError
1 failed in 0.65 seconds

@stphivos
Copy link
Owner

stphivos commented Sep 6, 2018

From m = MockModel(firstname='a' + exp.firstname, user=exp.user) does exp.user have a pk/id? It should work if that is populated or if the user=... part is omitted.

The library determines the hash value of a MockModel by hashing a tuple consisting of all attribute key/value pairs. If one of those values such as user happens to be a Django model, it ends up calling Django's Model.__hash__ which expects the model to have a pk.

So I think the best way is to change the library's code to determine a Model's hash depending on:

  • if it's a Django model i.e. Expert to use Django's built-in way.
  • if it's a MockModel, since no pk is mandatory, to keep doing the current approach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants