我在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')
到目前为止一切顺利,所有测试都没问题!
但是,我说我有很多像这样的测试用例。也就是说,测试错误'如果将来我必须更改错误消息,那么我也必须更改测试用例,这可能是一个MESS,但另一方面我还需要适当地测试errors
。
问题是,我如何测试不同场景的异常?因为我测试的方式,虽然现在可以,但是对于未来,它可能是一团糟,所以我需要你们的一些建议来以有效的方式处理这种情况。
答案 0 :(得分:3)
我们在这种情况下使用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.assertRaises(ObjectDoesNotExist) as e:
self.product_service.delete_product(
self.product_id=self.wrong_id,
user=self.right_user
)
self.assertEqual(e.exception.message, ProductErrors.not_found.value.format(wrong_id))
答案 1 :(得分:0)
如果我理解正确,你会担心重复的代码很多,如果有任何改变,就会很难维护测试(例如:方法的签名接受新参数等)。
介绍一个帮助器方法可能有所帮助(注意不要创建太多使用彼此的辅助方法,因为测试代码将变得难以遵循),例如:
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)
这种方式应该为底层方法改变(例如:一个新的,必需的参数,与这些测试无关,它可以作为默认值添加到辅助方法中,并且实际测试将保持稳定。 / p>
但如上所述,避免使用太多辅助方法和默认值 - 如果有很多辅助方法和默认值,请考虑将测试类重构为多个测试类。
答案 2 :(得分:0)
既然我理解了最初的问题,即目标是允许在不让测试中断的情况下更改错误文本,我建议使用translations。而不是错误的完整英文文本,只需使用键/代号。 I.e。:而不是JavascriptExecutor je = (JavascriptExecutor) dr;
je.executeScript("window.scrollTo(0,document.body.scrollHeight);")
dr.findElement(By.partialLinkText("Mail")));
使用_('No owner found for this deleting user'))
并在PO文件中翻译实际文本。
当然,这可能导致其他问题(需要确保所有翻译字符串实际翻译,翻译期间不会遗漏动态内容(变量),并且所有翻译文件都已正确部署),但它会以问题的方式使测试稳定