Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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)

like image 288
Ben Avatar asked Jun 01 '14 01:06

Ben


1 Answers

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')
like image 192
alecxe Avatar answered Oct 04 '22 15:10

alecxe