Skip to content

Unittest discovery fails when tornado.testing.AsyncTestCase is used #17285

@jonasehrlich

Description

@jonasehrlich

Since the update to v2021.9.1191016588 discovery of unittests fails when tornado.testing.AsyncTestCase is used.

Environment data

  • VS Code version: 1.60.0
  • Extension version (available under the Extensions sidebar): v2021.9.1191016588
  • OS and version: XXX
  • Python version (& distribution if applicable, e.g. Anaconda): at least Python 3.7.4 & 3.8, but should affect all versions
  • Type of virtual environment used (N/A | venv | virtualenv | conda | ...): N/A
  • Relevant/affected Python packages and their versions: tornado==6.0.3
  • Value of the python.languageServer setting: Pylance

Expected behaviour

Successful discovery of test cases, similar to how it happens for bare unittest tests.

image

Actual behaviour

Discovery of unittests fails, and no unittests are reported. This seems to be the case because the AsyncTestCase wraps test methods into a class _TestMethodWrapper which cannot be handled by inspect.getsourcelines(). While this could be fixed in tornado, without too much hassle, this does not solve this issue for other test classes which wrap the test methods.

Steps to reproduce:

  1. Create a test file (e.g my_package/test_foo.py)
from tornado.testing import AsyncTestCase
import unittest

class TestFoo(AsyncTestCase):
    def test_foo(self):
        self.assertEqual(10, 10)
  1. Configure unittests
{  
  "python.testing.unittestArgs": [
      "-v",
      "-s",
      "./my_package",
      "-p",
      "test_*.py"
  ],
}
  1. Discovery fails, as if tests weren't configured
    image

Logs

Output when running the discovery code directly

When running the piece of Python code that is run by the extension on discovery (from Python extension output) directly.

import unittest
import inspect

def get_sourceline(obj):
    s, n = inspect.getsourcelines(obj)
    for i, v in enumerate(s):
        if v.strip().startswith('def'):
            return str(n+i)
    return '*'

def generate_test_cases(suite):
    for test in suite:
        if isinstance(test, unittest.TestCase):
            yield test
        else:
            for test_case in generate_test_cases(test):
                yield test_case

loader = unittest.TestLoader()
suite = loader.discover("./my_package", pattern="test_*.py")

print("start")  # Don't remove this line
loader_errors = []
for s in generate_test_cases(suite):
    tm = getattr(s, s._testMethodName)
    testId = s.id()
    if testId.startswith("unittest.loader._FailedTest"):
        loader_errors.append(s._exception)
    else:
        print(testId.replace(".", ":") + ":" + get_sourceline(tm))

for error in loader_errors:
    try:
        print("=== exception start ===")
        print(error.msg)
        print("=== exception end ===")
    except:
        pass

The following exception is raised

start
Traceback (most recent call last):
  File "/home/jonas/conda/envs/playground/lib/python3.7/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/home/jonas/conda/envs/playground/lib/python3.7/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/home/jonas/.vscode-server/extensions/ms-python.python-2021.9.1191016588/pythonFiles/lib/python/debugpy/__main__.py", line 45, in <module>
    cli.main()
  File "/home/jonas/.vscode-server/extensions/ms-python.python-2021.9.1191016588/pythonFiles/lib/python/debugpy/../debugpy/server/cli.py", line 444, in main
    run()
  File "/home/jonas/.vscode-server/extensions/ms-python.python-2021.9.1191016588/pythonFiles/lib/python/debugpy/../debugpy/server/cli.py", line 285, in run_file
    runpy.run_path(target_as_str, run_name=compat.force_str("__main__"))
  File "/home/jonas/conda/envs/playground/lib/python3.7/runpy.py", line 263, in run_path
    pkg_name=pkg_name, script_name=fname)
  File "/home/jonas/conda/envs/playground/lib/python3.7/runpy.py", line 96, in _run_module_code
    mod_name, mod_spec, pkg_name, script_name)
  File "/home/jonas/conda/envs/playground/lib/python3.7/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/home/jonas/projects/playground/discovery.py", line 30, in <module>
    print(testId.replace(".", ":") + ":" + get_sourceline(tm))
  File "/home/jonas/projects/playground/discovery.py", line 5, in get_sourceline
    s, n = inspect.getsourcelines(obj)
  File "/home/jonas/conda/envs/playground/lib/python3.7/inspect.py", line 955, in getsourcelines
    lines, lnum = findsource(object)
  File "/home/jonas/conda/envs/playground/lib/python3.7/inspect.py", line 768, in findsource
    file = getsourcefile(object)
  File "/home/jonas/conda/envs/playground/lib/python3.7/inspect.py", line 684, in getsourcefile
    filename = getfile(object)
  File "/home/jonas/conda/envs/playground/lib/python3.7/inspect.py", line 666, in getfile
    type(object).__name__))
TypeError: module, class, method, function, traceback, frame, or code object was expected, got _TestMethodWrapper

Metadata

Metadata

Assignees

Labels

area-testingbugIssue identified by VS Code Team member as probable bug

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions