python - Subclassing TestCase in Python: Overwriting Field in Parent TestCase
问题描述
I'm writing integration tests for an Alexa app.
Our application uses a controller-request-response pattern. The controller receives a request with a specified intent and session variables, routes the request to functions that do some computation with the session variables, and returns a response object with the results of that computation.
We get the right behavior from UnhandledIntentTestCase as far as test_for_smoke is concerned. However, test_returning_reprompt_text never fires, because returns_reprompt_text is never overwritten.
Can someone explain how I can overwrite it in the parent class and/or how the correct intent name is passed to the request object in setUpClass?
intent_base_case.py
import unittest
import mycity.intents.intent_constants as intent_constants
import mycity.mycity_controller as mcc
import mycity.mycity_request_data_model as req
import mycity.test.test_constants as test_constants
###############################################################################
# TestCase parent class for all intent TestCases, which are integration tests #
# to see if any changes in codebase have broken response-request model. #
# #
# NOTE: Assumes that address has already been set. #
###############################################################################
class IntentBaseCase(unittest.TestCase):
__test__ = False
intent_to_test = None
returns_reprompt_text = False
@classmethod
def setUpClass(cls):
cls.controller = mcc.MyCityController()
cls.request = req.MyCityRequestDataModel()
key = intent_constants.CURRENT_ADDRESS_KEY
cls.request._session_attributes[key] = "46 Everdean St"
cls.request.intent_name = cls.intent_to_test
cls.response = cls.controller.on_intent(cls.request)
@classmethod
def tearDownClass(cls):
cls.controller = None
cls.request = None
def test_for_smoke(self):
self.assertNotIn("Uh oh", self.response.output_speech)
self.assertNotIn("Error", self.response.output_speech)
def test_correct_intent_card_title(self):
self.assertEqual(self.intent_to_test, self.response.card_title)
@unittest.skipIf(not returns_reprompt_text,
"{} shouldn't return a reprompt text".format(intent_to_test))
def test_returning_reprompt_text(self):
self.assertIsNotNone(self.response.reprompt_text)
@unittest.skipIf(returns_reprompt_text,
"{} should return a reprompt text".format(intent_to_test))
def test_returning_no_reprompt_text(self):
self.assertIsNone(self.response.reprompt_text)
test_unhandled_intent.py
import mycity.test.intent_base_case as base_case
########################################
# TestCase class for unhandled intents #
########################################
class UnhandledIntentTestCase(base_case.IntentBaseCase):
__test__ = True
intent_to_test = "UnhandledIntent"
returns_reprompt_text = True
output
======================================================================
FAIL: test_correct_intent_card_title (mycity.test.test_unhandled_intent.UnhandledIntentTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/wdrew/projects/alexa_311/my_city/mycity/mycity/test/intent_base_case.py", line 44, in test_correct_intent_card_title
self.assertEqual(self.intent_to_test, self.response.card_title)
AssertionError: 'UnhandledIntent' != 'Unhandled intent'
- UnhandledIntent
? ^
+ Unhandled intent
? ^^
======================================================================
FAIL: test_returning_no_reprompt_text (mycity.test.test_unhandled_intent.UnhandledIntentTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/wdrew/projects/alexa_311/my_city/mycity/mycity/test/intent_base_case.py", line 56, in test_returning_no_reprompt_text
self.assertIsNone(self.response.reprompt_text)
AssertionError: 'So, what can I help you with today?' is not None
----------------------------------------------------------------------
解决方案
这是因为执行顺序。装饰器在类的SkipIf
解析期间执行一次IntentBaseCase
。它们不会为每个类或每次调用测试函数重新执行。
装饰器模式SkipIf
设计用于固定全局变量,例如依赖模块的版本、操作系统或其他可以在全局上下文中计算或知道可用性的外部资源。
跳过测试也是出于外部原因而应该做的事情,而不是出于内部原因,例如子类的需求。跳过仍然是报告中指出的一种失败测试,因此您可以看到您的测试套件没有行使项目的整个功能范围。
您应该重新设计您的基类结构,以便函数仅在子类和跳过使用 Skip 时才能运行。我的建议是:
class IntentBaseCase(unittest.TestCase):
...
class RepromptBaseCase(IntentBaseCase):
def test_returning_reprompt_text(self):
self.assertIsNotNone(self.response.reprompt_text)
class NoRepromptBaseCase(IntentBaseCase):
def test_returning_no_reprompt_text(self):
self.assertIsNone(self.response.reprompt_text)
您还应该考虑将响应部分移出 setUp 并将其放入它自己的 test_ 函数中,并将这些 test_returning 函数更改为更简单的assertReprompt
函数assertNoReprompt
。在 setUp 中设置测试是个好主意,但在那里运行实际代码不是一个好主意。
推荐阅读
- c# - 无法将图像文件上传到 Firebase Storage Unity C#
- docker - 为什么'docker-compose run'命令与常规'docker build'相比,从同一个Dockerfile构建不同的图像?
- javascript - 如何在功能组件中使用 componentWillReceiveProps
- javascript - 如何访问嵌套但固定的数组和对象结构中的特定属性
- asp.net-mvc - 如何使用反射来获取所有 mvc 页面而不是部分视图
- blazor - Blazor 中的 EditForm:EventCallback 给出错误方法组
- dynamic - NextJs Link 不会重新加载页面但会重新加载组件
- google-sheets - 如何在 Google Sheet 上自动将字符串 YYYY|MM 列转换为日期列 YYYY/MM?
- oracle - 如何为 oracle 数据库中的远程数据库对象正确应用 index_desc 提示?
- python - 从 err KeyError: 'fbs' in different dataset 获取 raise KeyError(key)