django:模型的@属性 函数的测试用例

django: test case for @property function of a Model

我有一个 Django 库应用程序,它具有以下 BookInstance 模型:

class BookInstance(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4,help_text='Unique ID for this particular book across whole library')
    book = models.ForeignKey('Book', on_delete=models.SET_NULL, null=True)
    due_back = models.DateField(null=True, blank=True)
    borrower = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)

    STATUS_MAINTENANCE = 'm'
    STATUS_ON_LOAN = 'o'
    STATUS_AVAILABLE = 'a'
    STATUS_RESERVED = 'r'

    LOAN_STATUS = (
      (STATUS_MAINTENANCE, 'Maintenance'),
      (STATUS_ON_LOAN, 'On loan'),
      (STATUS_AVAILABLE, 'Available'),
      (STATUS_RESERVED, 'Reserved'),
    )

    status = models.CharField(
       max_length=1,
       choices=LOAN_STATUS,
       blank=True,
       default=STATUS_MAINTENANCE,
       help_text='Book availability',
     )

    class Meta:
        ordering = ['due_back']
        permissions = (("can_mark_returned", "Set book as returned"), ("can_create_book", "Create new book"), ("can_update_book", "Update book details"), ("can_delete_book", "Delete book"),)


    # how to develop test case for this function
    @property
    def is_overdue(self):
       if self.due_back and date.today() > self.due_back:
        return True
    return False

在我的 tests.py 文件中,我有 test_object_name_is_name 函数来测试它,但是我的覆盖率报告显示该函数没有经过测试。

class BookInstanceModelTest(TestCase):
"""
    Test case for Book Instance
"""
   @classmethod
   def setUpTestData(cls):
       # Set up non-modified objects used by all test methods
       test_user1 = User.objects.create_user(username='testuser1', password='1X<ISRUkw+tuK',
                                          email='testuser1@test.com')
       test_user2 = User.objects.create_user(username='testuser2', password='2HJ1vRV0Z&3iD',
                                          email='testuser2@test.com')

       test_author = Author.objects.create(first_name='William', last_name='Shakespeare')
       test_book = Book.objects.create(title='Hamlet', author=test_author, summary='Published in 1990',
                                    isbn='123456789123')
       genre_objects_for_book = Genre.objects.all()
       test_book.genre.set(genre_objects_for_book)

       return_date1 = datetime.date.today()
       BookInstance.objects.create(book=test_book, borrower=test_user1, due_back=return_date1,
                                status='o')
       return_date2 = datetime.date.today() + datetime.timedelta(days=5)
       BookInstance.objects.create(book=test_book, borrower=test_user2, due_back=return_date2,
                                status='o')

       return_date3 = datetime.date.today() - datetime.timedelta(days=5)
       BookInstance.objects.create(book=test_book, borrower=test_user2, due_back=return_date3,
                                status='o')

   # test case I developed
   def test_book_is_overdue(self):
       last_date = datetime.date.today()
       for book in BookInstance.objects.all():
          if book.due_back == last_date:
              self.assertTrue(True)
          elif book.due_back > last_date:
              self.assertTrue(True)
          elif book.due_back < last_date:
              self.assertFalse(False)

我检查了 due_back 是否迟到或低于截止日期, 测试成功执行,但 并未实际测试 BookInstance 模型的 is_overdue()。 请指导我如何正确测试此功能!谢谢

我认为您误解了测试用例在 Django 中的工作方式;您应该在测试方法前加上 test_ 前缀,然后是您想要的任何名称,但它对功能并不重要,也不会调用函数。

要测试您的 属性,您应该在测试中调用它:

 def test_book_is_overdue(self):
       last_date = datetime.date.today()
       for book in BookInstance.objects.all():
          value = book.is_overdue
          # test whatever you want

这是一个合适的测试用例。请注意,1/ 我为每个条件创建一个测试方法(我单独测试每个条件)和 2/ 我创建要在测试方法本身中测试的书(使测试更加明显和可读)。我只将 setUp() 用于测试所需的固定装置,但不是测试本身的一部分。此外,我在 self.assertXXX 调用中添加了更多明确的错误消息(因为将 "False is not True" 作为失败测试的报告并没有真正帮助)。

class BookInstanceModelTest(TestCase):
    def setUp(self):
        self.test_user1 = User.objects.create_user(
            username='testuser1', 
            password='1X<ISRUkw+tuK',
            email='testuser1@test.com'
        )

        self.test_author = Author.objects.create(
           first_name='William', 
           last_name='Shakespeare'
        )

        self.test_book = Book.objects.create(
            title='Hamlet', 
            author=self.test_author, 
            summary='Published in 1990',                                       
            isbn='123456789123'
        )

        genre_objects_for_book = Genre.objects.all()
        self.test_book.genre.set(genre_objects_for_book)


    def test_book_is_not_overdue_if_due_back_date_is_today(self)            
        due_date = datetime.date.today()
        book = BookInstance.objects.create(
           book=self.test_book, 
           borrower=self.test_user1, 
           due_back=due_date, 
           status='o'
        )
        self.assertFalse(book.is_overdue, "book should not be overdue")


    def test_book_is_not_overdue_if_due_back_date_is_later_than_today(self):
        due_date = datetime.date.today() + datetime.timedelta(days=5)
        book = BookInstance.objects.create(
           book=self.test_book, 
           borrower=self.test_user1, 
           due_back=due_date, 
           status='o'
        )
        self.assertFalse(book.is_overdue, "book should not be overdue")


    def test_book_is_not_overdue_if_due_back_date_is_none(self):
        due_date = None
        book = BookInstance.objects.create(
           book=self.test_book, 
           borrower=self.test_user1, 
           due_back=due_date, 
           status='o'
        )
        self.assertFalse(book.is_overdue, "book should not be overdue")


    def test_book_is_overdue_if_due_back_date_is_past(self):
        due_date = datetime.date.today() - datetime.timedelta(days=5)
        book = BookInstance.objects.create(
           book=self.test_book, 
           borrower=self.test_user1, 
           due_back=due_date, 
           status='o'
        )
        self.assertTrue(book.is_overdue, "book should be overdue")

您可以简单地创建一个实例并从该实例中获取 属性。

instance = BookInstance(due_back=datetime.today())

# Then property can be accessed like this
instance.is_overdue