簡體   English   中英

django 單元測試異常

[英]django unit test for exceptions

我在 django 項目中工作並編寫服務以促進 apis.in 服務,我有這樣的類和類方法,

class ProductService(object):
    def delete_product(self, product_id, deleting_user):
        try:
            product = Product.objects.get(pk=product_id)
        except Product.DoesNotExist:
            raise ObjectDoesNotExist(_('no product found for this id {}'.format(product_id)))

        try:
            deleting_user = Customer.objects.get(owner=deleting_user)
        except Customer.DoesNotExist:
            raise ValidationError(_('No owner found for this deleting user'))

我為此方法編寫了以下單元測試,

def setUp(self):
    self.product_service = ProductService()
    self.wrong_id = 0
    self.right_id = 1
    self.right_user = _user
    self.wrong_user = wrong_user  

def test_raise_does_not_exist_error_for_wrong_product_id(self):
    with self.assertRaises(ObjectDoesNotExist) as e:
        self.product_service.delete_product(
            self.product_id=self.wrong_id,
            user=self.right_user     
        )
    self.assertEqual(e.exception.message, 'no product found for this id {}'.format(wrong_id))

def test_raise_validtaion_error_for_wrong_deleting_user(self):
    with self.assertRaises(ObjectDoesNotExist) as e:
        self.product_service.delete_product(
            self.product_id=self.right_id,
            user=self.wrong_user     
        )
    self.assertEqual(e.exception.message, 'No owner found for this deleting user') 

到目前為止一切順利,所有測試都正常!

但是,假設我有很多這樣的測試用例。也就是說,測試“錯誤”,如果將來我必須更改錯誤消息,那么我也必須更改測試用例,這可能是一個混亂,但在另一方面,我還需要適當地測試errors

問題是,我如何測試不同場景的異常?因為我測試的方式,雖然現在還可以,但對於未來,它可能會一團糟,所以我需要你們提供一些建議來處理這種情況以一種有效的方式。

我們在這種情況下使用 Enum:

class ProductErrors(Enum):
    not_found = "Product {} not found"
    doesnt_exist = "Product {} doesn't exist"

這將允許您在測試中使用這個枚舉並像這樣檢查它:

def test_raise_does_not_exist_error_for_wrong_product_id(self):
    with self.assertRaisesMessage(
        ObjectDoesNotExist, 
        ProductErrors.not_found.value.format(wrong_id)
    ):
        self.product_service.delete_product(
            self.product_id=self.wrong_id,
            user=self.right_user     
        )

現在我明白了目標是允許在不中斷測試的情況下更改錯誤文本的原始問題,我建議使用translations 而不是錯誤的完整英文文本,只需使用鍵/代號。 即:而不是_('No owner found for this deleting user'))使用_('product_delete_error_no_owner_found')並翻譯 PO 文件中外部的實際文本。

當然,這可能會導致其他問題(需要確保您的所有翻譯字符串都已實際翻譯,在翻譯過程中不會遺漏動態內容(變量),並且所有翻譯文件都已正確部署),但它會使以問題希望的方式測試穩定

如果我理解正確,您會擔心大量重復的代碼,如果發生任何變化(例如:方法的簽名接受新參數等),這會使測試難以維護。

引入輔助方法可能會有所幫助(注意不要創建太多相互使用的輔助方法,否則測試代碼將變得難以理解),例如:

def test_raise_validtaion_error_for_wrong_deleting_user(self):
    self.assert_delete_product_raises_error(
        exception_cls=ObjectDoesNotExist,
        error_message='No owner found for this deleting user',
        product_id=self.right_id,
        user=self.wrong_user
    )

def assert_delete_product_raises_error(self, exception_cls, error_message, **delete_product_kwargs):
    with self.assertRaises(exception_cls) as raised:
         self.product_service.delete_product(**delete_product_kwargs)
    self.assertEqual(error_message, raised.exception.message)

這種方式應該為底層方法改變一些東西(例如:一個新的、必需的參數,與這些測試無關,它可以作為默認值添加到輔助方法中,並且實際測試將保持穩定。

但如上所述,避免有太多的輔助方法和默認值——如果有很多,考慮將測試類重構為多個測試類。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM