0

Due to circular-import issues which are common with Celery tasks in Django, I'm often importing Celery tasks inside of my methods, like so:

# some code omitted for brevity
# accounts/models.py
def refresh_library(self, queue_type="regular"):
    from core.tasks import refresh_user_library 

    refresh_user_library.apply_async(
        kwargs={"user_id": self.user.id}, queue=queue_type
    )
    return 0

In my pytest test for refresh_library, I'd only like to test that refresh_user_library (the Celery task) is called with the correct args and kwargs. But this isn't working:

# tests/test_accounts_models.py
@mock.patch("accounts.models.UserProfile.refresh_library.refresh_user_library")
def test_refresh_library():

Error is about refresh_library not having an attribute refresh_user_library.

I suspect this is due to the fact that the task(refresh_user_library) is imported inside the function itself, but I'm not too experienced with mocking so this might be completely wrong.

zerohedge
  • 3,185
  • 4
  • 28
  • 63
  • 2
    I think you need to mock core.tasks.rehresh_user_library instead of accounts.models.UserProfile.refresh_library.refresh_user_library – cagrias Aug 06 '19 at 10:47
  • @cagrias thank you, mocking that (actually, its apply_async) worked. I thought I should mock the object where it’s used not where it’s defined though..? – zerohedge Aug 06 '19 at 10:56
  • Mocking is by means saying that: "I have this external package function that I'm going to use, just ignore that and return this value when its called". So that external package function is `core..tasks.rehresh_user_library.apply_sync` in your case. – cagrias Aug 06 '19 at 11:00
  • @cagrias hmmm, yes but isn’t this function used inside of my model method? In any case you’ve answered my OP question, can you add an answer so I can mark as correct? – zerohedge Aug 06 '19 at 11:03

2 Answers2

1

Even though apply_async is your own-created function in your core.tasks, if you do not want to test it but only make sure you are giving correct arguments, you need to mock it. In your question you're mocking wrong package. You should do:

# tests/test_accounts_models.py
@mock.patch("core.tasks.rehresh_user_library.apply_sync")
def test_refresh_library():
cagrias
  • 1,847
  • 3
  • 13
  • 24
0

In your task function, refresh_user_library is a local name, not an attribute of the task. What you want is the real qualified name of the function you want to mock:

@mock.patch("core.tasks.refresh_user_library")
def test_refresh_library():
    # you test here
bruno desthuilliers
  • 75,974
  • 6
  • 88
  • 118