我的 tornado.testing.AsyncTestCase 测试可以有一个抽象基础 class 吗?

Can I have an abstract base class for my tornado.testing.AsyncTestCase tests?

是否可以使用基础 classes 来定义 tornado 中的测试,而这些测试本身并不是 运行 测试?

假设我有以下最小示例作为基础 class:

from tornado.testing import AsyncTestCase, gen_test
from tornado.httpclient import HTTPRequest

class AbstractTestCase(AsyncTestCase):
    def set_parameters(self):
        #Set some parameter value here: self.uri = ...
        raise NotImplementedError

    @gen_test
    def test_common_functionality(self):
        req = HTTPRequest(self.uri, method = "GET")
        response = yield self.client.fetch(req, raise_error=False)
        self.assertEqual(200, response.code)

现在,我想制作几个继承自此的测试用例,为 self.uri 定义它们自己的值...并进行一些它们自己的特定测试。像这样:

class ConcreteTestCase(AbstractTestCase):
    def set_parameters(self):
        self.uri = "www.whosebug.com"

    @gen_test
    def test_some_other_thing(self):
        self.assertEqual(2, 1+1)

但是,当我尝试 运行 时,AbstractTestCase 本身也是 运行,给出错误(NotImplementedError)。即使我只尝试 运行 继承测试也会发生这种情况。

有什么办法可以解决这个问题,还是我必须在每个测试用例中复制功能?

CLI

python3 -m tornado.testing ConcreteTestCase.ConcreteTestCase

testmain.py

#!/usr/bin/env python3
import unittest
from tornado.testing import main


def all():
    cases = ['ConcreteTestCase.ConcreteTestCase']
    return unittest.defaultTestLoader.loadTestsFromNames(cases)

main()

test/runtests.py 就是一个很好的例子。

实现此目的的一种方法是使用多重继承。只要 class 在运行时位于继承层次结构中,抽象 class 就不需要扩展 AsyncTestCase。

class AbstractTestCase(object):
    def set_parameters(self):
        #Set some parameter value here: self.uri = ...
        raise NotImplementedError

    @gen_test
    def test_common_functionality(self):
        req = HTTPRequest(self.uri, method = "GET")
        response = yield self.client.fetch(req, raise_error=False)
        self.assertEqual(200, response.code)

class ConcreteTestCase(AbstractTestCase, AsyncTestCase):
    def set_parameters(self):
        self.uri = "www.whosebug.com"

    @gen_test
    def test_some_other_thing(self):
        self.assertEqual(2, 1+1)

这确实有点奇怪,mypy 类型检查不喜欢它。但它既简单又有效,而且我还没有找到我喜欢的 mypy 友好的替代方案。