djangounit-testingexceptiondelete-rowassertraises

Django - Unit test an object has been deleted - how to use assertRaise / DoesNotExist exception


I would lioke some help to unit test a function that deletes an object in a Django app

The problem
I display a list of values, it includes a bin icon to delete one value, and my view seems to work fine (at least according to the test I made).
How can I unit test it? I'm not able to find out the right way to do yet.
I searched the web and found the DoesNotExist exception, but I'm afraid I'm not able to use it, as I got a matching query does not exist error.
Could you please advise me on how to proceed?

What I tried
Here is my current whole code for the test:

class TestAdmUsers(TestCase):
    def setUp(self):
        self.company = create_dummy_company("Société de test")
        self.usr11 = create_dummy_user(self.company, "user11")
        self.usr13 = create_dummy_user(self.company, "user13")
        self.usr14 = create_dummy_user(self.company, "user14")
        self.client.force_login(self.user_staff.user)

    def test_delete_user(self):
        test_usercomp_id = self.usr13.id
        url = reverse("polls:adm_delete_user", args=[self.company.comp_slug, self.usr13.id])
        response = self.client.get(url, follow=True)
        self.assertRaises(UserComp.DoesNotExist, UserComp.objects.get(id=test_usercomp_id))

The test log is the following:

Creating test database for alias 'default'...
System check identified no issues (0 silenced).
E
======================================================================
ERROR: test_delete_user (polls.tests_admin.TestAdmUsers)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "D:\Mes documents\Informatique\Developpement\Votes AG\projet_votes\polls\tests_admin.py", line 136, in test_delete_user
    self.assertRaises(UserComp.DoesNotExist, UserComp.objects.get(id=test_usercomp_id))
  File "C:\Users\Christophe\.virtualenvs\projet_votes-onIieQ0I\lib\site-packages\django\db\models\manager.py", line 82, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "C:\Users\Christophe\.virtualenvs\projet_votes-onIieQ0I\lib\site-packages\django\db\models\query.py", line 408, in get
    self.model._meta.object_name
polls.models.UserComp.DoesNotExist: UserComp matching query does not exist.

----------------------------------------------------------------------
Ran 1 test in 1.763s

FAILED (errors=1)
Destroying test database for alias 'default'...

I made other tests like this one:

    def test_delete_user(self):
        url = reverse("polls:adm_delete_user", args=[self.company.comp_slug, self.usr13.id])
        response = self.client.get(url)
        self.assertContains(response, self.usr12.user.username)
        self.assertNotContains(response, self.usr13.user.username)

that leads to this:

======================================================================
FAIL: test_delete_user (polls.tests_admin.TestAdmUsers)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "D:\Mes documents\Informatique\Developpement\Votes AG\projet_votes\polls\tests_admin.py", line 136, in test_delete_user
    self.assertNotContains(response, self.usr13.user.username)
  File "C:\Users\Christophe\.virtualenvs\projet_votes-onIieQ0I\lib\site-packages\django\test\testcases.py", line 465, in assertNotContains
    self.assertEqual(real_count, 0, msg_prefix + "Response should not contain %s" % text_repr)
AssertionError: 1 != 0 : Response should not contain 'user13'

----------------------------------------------------------------------

Or this one:

    def test_delete_user(self):
        test_usercomp_id = self.usr13.id
        url = reverse("polls:adm_delete_user", args=[self.company.comp_slug, self.usr13.id])
        response = self.client.get(url, follow=True)
        self.company.refresh_from_db()
        self.usr13.refresh_from_db()
        users = UserComp.get_users_in_comp(self.company.comp_slug)
        self.assertContains(response, self.usr12.user.username)
        self.assertNotContains(users, self.usr13)

with the following result:

======================================================================
ERROR: test_delete_user (polls.tests_admin.TestAdmUsers)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "D:\Mes documents\Informatique\Developpement\Votes AG\projet_votes\polls\tests_admin.py", line 137, in test_delete_user
    self.usr13.refresh_from_db()
  File "C:\Users\Christophe\.virtualenvs\projet_votes-onIieQ0I\lib\site-packages\django\db\models\base.py", line 628, in refresh_from_db
    db_instance = db_instance_qs.get()
  File "C:\Users\Christophe\.virtualenvs\projet_votes-onIieQ0I\lib\site-packages\django\db\models\query.py", line 408, in get
    self.model._meta.object_name
polls.models.UserComp.DoesNotExist: UserComp matching query does not exist.

----------------------------------------------------------------------

And this latest one that uses a class method:

    def test_delete_user(self):
        current_username = self.usr13.user.username
        url = reverse("polls:adm_delete_user", args=[self.company.comp_slug, self.usr13.id])
        response = self.client.get(url, follow=True)
        self.company.refresh_from_db()
        self.usr13.refresh_from_db()
        self.assertContains(response, self.usr12.user.username)
        self.assertNotContains(UserComp.get_users_in_comp(self.company.comp_slug), self.usr13)

but the result is still an error:

`======================================================================
ERROR: test_delete_user (polls.tests_admin.TestAdmUsers)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "D:\Mes documents\Informatique\Developpement\Votes AG\projet_votes\polls\tests_admin.py", line 137, in test_delete_user
    self.usr13.refresh_from_db()
  File "C:\Users\Christophe\.virtualenvs\projet_votes-onIieQ0I\lib\site-packages\django\db\models\base.py", line 628, in refresh_from_db
    db_instance = db_instance_qs.get()
  File "C:\Users\Christophe\.virtualenvs\projet_votes-onIieQ0I\lib\site-packages\django\db\models\query.py", line 408, in get
    self.model._meta.object_name
polls.models.UserComp.DoesNotExist: UserComp matching query does not exist.

----------------------------------------------------------------------

Related application code
Here is the code for the view:

def adm_delete_user(request, comp_slug, usr_id):
    del_usr = User.objects.get(pk=usr_id)
    msg = "Utilisateur {0} {1} supprimé.".format(del_usr.last_name, del_usr.first_name)
    User.objects.get(pk=usr_id).delete()

    messages.success(request, msg)
    return redirect("polls:adm_users", comp_slug=comp_slug)

And the model:

class UserComp(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, verbose_name="Utilisateur")
    company = models.ForeignKey(Company, on_delete=models.CASCADE, verbose_name="Société")
    phone_regex = RegexValidator(regex=r'^0[0-9]([ .-]?[0-9]{2}){4}$', message=("Format de numéro de téléphone invalide"))
    phone_num = models.CharField("numéro de téléphone", validators=[phone_regex], max_length=14, null=True, blank=True)
    is_admin = models.BooleanField("administrateur", default=False)

    def __str__(self):
        return '%s %s' % (self.user.last_name, self.user.first_name)
    class Meta:
        verbose_name = "Liens Utilisateurs / Sociétés"
        verbose_name_plural = "Liens Utilisateurs / Sociétés"

    @classmethod
    def create_usercomp(cls, user, company, phone_num='', is_admin=False):
        """ Create a new UserComp """
        usr_comp = UserComp(user=user, company=company, phone_num=phone_num, is_admin=is_admin)
        usr_comp.save()
        return usr_comp

    @classmethod
    def get_users_in_comp(cls, comp_slug):
        user_list = cls.objects.filter(company__comp_slug=comp_slug)
        return user_list

Complementary search results
Finally, I found some posts here that oriented my tests, but I wasn't able to find the solution:


Solution

  • assertRaises takes a callable as its (optional) second argument. Since .get(...) is not a callable, you should use the context manager form instead:

    with self.assertRaises(UserComp.DoesNotExist): 
        UserComp.objects.get(id=test_usercomp_id)