django testing - confirm that model is unique, depending on another field

django, django-testing

Solution

You can use `assertRaises` and catch `IntegrityError`:

class MyTestCase(TestCase):
    def test_regular(self):
        topic_1 = Topic.objects.create(name='1')
        topic_2 = Topic.objects.create(name='2')
        for subtopic_name in ['a', 'b', 'c']:
            SubTopic.objects.create(name=subtopic_name, topic=topic_1)
            SubTopic.objects.create(name=subtopic_name, topic=topic_2)

        subtopics_1 = [topic.name for topic in topic_1.subtopic_set.all()]
        subtopics_2 = [topic.name for topic in topic_2.subtopic_set.all()]
        self.assertEqual(subtopics_1, subtopics_2, ['a', 'b', 'c'])

    def test_uniqueness(self):
        topic_1 = Topic.objects.create(name='1')
        SubTopic.objects.create(name='a', topic=topic_1)

        with self.assertRaises(IntegrityError):
            SubTopic.objects.create(name='a', topic=topic_1)

The `test_uniqueness` test would fail until you set the `unique_together`:

class SubTopic(models.Model):
    topic = ForeignKey(Topic)
    name = models.CharField(max_length=1)

    class Meta:
        unique_together = ('topic', 'name')

Problem

I'm just starting with django testing, so I'm still trying to wrap my head around it. I have two models. Lets say `Topic` and `SubTopic` ``` class Topic(models.Model): name = models.CharField(max_length=1, unique=True) class SubTopic(models.Model): topic = ForeignKey(Topic) name = models.CharField(max_length=1) ``` I want to set up a test case to check that this is possible: ``` topic: 1 subtopic:a (pk=1) subtopic:b (pk=2) subtopic:c (pk=3) topic: 2 subtopic:a (pk=4) subtopic:b (pk=5) subtopic:c (pk=6) ``` but this is not possible: ``` topic: 1 subtopic:a (pk=1) subtopic:a (pk=2) subtopic:c (pk=3) ``` My guess on how to do this: ``` def test_subtopics_cant_have_same_name(self): topic_1 = Topic.objects.create(name='1') suptopic_name = 'a' subtopic_1 = SubTopic.objects.create(name=subtopic_name) subtopic_2 = SubTopic.objects.create(name=subtopic_name) subtopics = [ topic.name for topic in topic.subtopic_set.all()] self.assertEqual(subtopics.count(subtopic_name),1) ``` Is this the right way? Bonus Question My guess at the logic to solve this problem would be something like: ``` class SubTopic(models.Model): topic = ForeignKey(Topic) name = models.CharField(max_length=1) def save(*args, **kwargs): subtopics = [ topic.name for topic in topic.subtopic_set.all()] if name in subtopics: raise IntegrityError('subtopic not unique for this topic') else: super(SubTopic, self).save(*args, **kwargs) ``` but I'm not sure if there's a better way..? because the test now fails before the check. (fails when subtopic_2 is saved)

Original source