【问题标题】:Subclassing TestCase in Python: Overwriting Field in Parent TestCase在 Python 中子类化 TestCase:覆盖父 TestCase 中的字段
【发布时间】:2018-04-29 20:12:55
【问题描述】:

我正在为 Alexa 应用编写集成测试。

我们的应用程序使用控制器-请求-响应模式。控制器接收具有指定意图和会话变量的请求,将请求路由到对会话变量进行一些计算的函数,并返回一个包含计算结果的响应对象。

就 test_for_smoke 而言,我们从 UnhandledIntentTestCase 获得了正确的行为。但是, test_returning_reprompt_text 永远不会触发,因为returns_reprompt_text 永远不会被覆盖。

谁能解释我如何在父类中覆盖它和/或 正确的意图名称如何传递给 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

输出

======================================================================
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

----------------------------------------------------------------------

【问题讨论】:

    标签: python unit-testing testing python-unittest


    【解决方案1】:

    这是因为执行顺序。 SkipIf 装饰器在 IntentBaseCase 类的解析期间执行一次。它们不会为每个类或每次调用测试函数重新执行。

    SkipIf 的装饰器模式设计用于固定全局变量,例如依赖模块的版本、操作系统或其他可以在全局上下文中计算或知道可用性的外部资源。

    跳过测试也是出于外部原因,而不是出于内部原因,例如子类的需求。跳过仍然是报告中指出的一种失败测试,​​因此您可以看到您的测试套件没有行使项目的整个功能范围。

    您应该重新设计您的基类结构,以便函数只有在子类和跳过使用跳过的情况下才能运行。我的建议是:

    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 函数更改为更简单的 assertRepromptassertNoReprompt 函数。在 setUp 中设置测试是个好主意,但在那里运行实际代码不是一个好主意。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多