Как использовать exec для запуска файла Python unittest в коде - PullRequest
0 голосов
/ 04 июня 2019

Я хочу выполнить другой файл Python в моем коде, поэтому я использую этот код, он отлично работает:

runner.py

        with open(pyfile, encoding="utf-8") as f:
            code = f.read()
        gl = globals()
        gl["__name__"] = "__main__"
        gl["__file__"] = pyfile
        exec(compile(code, pyfile, 'exec'), gl)

, чтобы я мог выполнить код в a.py с помощью if __name__ in __main__:

a.py


def testprint():
    print(123321)


if __name__ == "__main__":
    testprint()

в runner.py, я изменяю __file__ и __name__, чтобы убедиться, что при запуске a.py в runner.py, точно так же, как я использую python a.py для его запуска.

это будет хорошо, пока я не получу файл Python, используя unittest, например:

b.py

import unittest

class Test(unittest.TestCase):
    def setUp(self):
        pass

    def test_case1(self):
        pass

    def tearDown(self):
        pass

if __name__ == '__main__':
    unittest.main()

при попытке запустить b.py в runner.py произойдет сбой:

 File "runner.py", line 72, in run_pyfile
    exec(compile(code, pyfile, 'exec'), gl)
  File "a.py", line 23, in <module>
    unittest.main()
  File "C:\Python36\Lib\unittest\main.py", line 96, in __init__
    self.parseArgs(argv)
  File "C:\Python36\Lib\unittest\main.py", line 143, in parseArgs
    self.createTests()
  File "C:\Python36\Lib\unittest\main.py", line 147, in createTests
    self.test = self.testLoader.loadTestsFromModule(self.module)
  File "C:\Python36\Lib\unittest\loader.py", line 123, in loadTestsFromModule
    tests.append(self.loadTestsFromTestCase(obj))
  File "C:\Python36\Lib\unittest\loader.py", line 92, in loadTestsFromTestCase
    loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames))
  File "C:\Python36\Lib\unittest\suite.py", line 24, in __init__
    for test in tests:
TypeError: __init__() takes 1 positional argument but 2 were given

эта проблема связана с тем, что в unittest он будет использовать __main__ для инициализации TestProgram, но он будет использовать runner.py как __main__, а не реальный путь к файлу (b.py)

class TestProgram(object):
    def __init__(self, module='__main__', defaultTest=None, argv=None,
                    testRunner=None, testLoader=loader.defaultTestLoader,
                    exit=True, verbosity=1, failfast=None, catchbreak=None,
                    buffer=None, warnings=None, *, tb_locals=False):
        if isinstance(module, str):
            self.module = __import__(module) # <---the result is self.module= runner.py, not b.py

-

Я пробовал эти способы, но они не работают:

  1. попробуйте использовать importlib
import importlib.util
spec = importlib.util.spec_from_file_location("__main__", "a.py")
foo = importlib.util.module_from_spec(spec)
spec.loader.exec_module(foo)

все еще хорошо работает, когда я использую a.py, но не удалось в b.py. потому что он передает какой-то странный argv на unittest (не путь b.py, а путь моего python.exe и какое-то странное число)

  1. попробуйте использовать runpy
import runpy
runpy.run_path("a.py")

Я могу получить дикт и некоторые результаты (некоторые вещи, связанные с авторским правом), но не то, что я хочу.

так как выполнить файл Python unittest в коде?

Я использую Python3.6 +

...