Python 从 PyCharm 社区版中的鼠标右键单击上下文菜单运行/调试 Django 应用程序的 UnitTests?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/42989471/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 22:23:41  来源:igfitidea点击:

Run / Debug a Django application's UnitTests from the mouse right click context menu in PyCharm Community Edition?

pythondjangounit-testingpycharm

提问by CristiFati

I must emphasize on PyCharm CommunityEditionwhich does not have any Djangointegration(v2016.3.2at question time).

我必须强调PyCharm社区,它没有任何Django集成(问题时间为v 2016.3.2)。

I've Googled my problem and (surprisingly,) I did not get any answers, (of course I don't exclude the possibility that there might be some, be but I just missed them).

我已经用谷歌搜索了我的问题,并且(令人惊讶的是)我没有得到任何答案,(当然我不排除可能存在一些问题的可能性,但是我只是错过了它们)。

The question is simple: in PyCharm, one can Run (Debug) an Unit Test (TestCaseor one of its methods) with a simple mouse right click (from the context menu) just as in the image below:

问题很简单:在PyCharm 中,只需单击鼠标右键(从上下文菜单中)即可运行(调试)单元测试(TestCase或其方法之一),如下图所示:

Run Django Unit Test at RClick

在 RClick 上运行 Django 单元测试

Unfortunately, that yields an exception:

不幸的是,这产生了一个例外:

Traceback (most recent call last):
    File "C:\Install\PyCharm Community Edition16.3.2\helpers\pycharm\utrunner.py", line 254, in <module>
        main()
    File "C:\Install\PyCharm Community Edition16.3.2\helpers\pycharm\utrunner.py", line 232, in main
        module = loadSource(a[0])
    File "C:\Install\PyCharm Community Edition16.3.2\helpers\pycharm\utrunner.py", line 65, in loadSource
        module = imp.load_source(moduleName, fileName)
    File "E:\Work\Dev\Django\Tutorials\proj0\src\polls\tests.py", line 7, in <module>
        from polls.models import Question
    File "E:\Work\Dev\Django\Tutorials\proj0\src\polls\models.py", line 9, in <module>
        class Question(models.Model):
    File "E:\Work\Dev\Django\Tutorials\proj0\src\polls\models.py", line 10, in Question
        question_text = models.CharField(max_length=200)
    File "E:\Work\Dev\VEnvs\py2713x64-django\lib\site-packages\django\db\models\fields\__init__.py", line 1043, in __init__
        super(CharField, self).__init__(*args, **kwargs)
    File "E:\Work\Dev\VEnvs\py2713x64-django\lib\site-packages\django\db\models\fields\__init__.py", line 166, in __init__
        self.db_tablespace = db_tablespace or settings.DEFAULT_INDEX_TABLESPACE
    File "E:\Work\Dev\VEnvs\py2713x64-django\lib\site-packages\django\conf\__init__.py", line 53, in __getattr__
        self._setup(name)
    File "E:\Work\Dev\VEnvs\py2713x64-django\lib\site-packages\django\conf\__init__.py", line 39, in _setup
        % (desc, ENVIRONMENT_VARIABLE))
    django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.
Traceback (most recent call last):
    File "C:\Install\PyCharm Community Edition16.3.2\helpers\pycharm\utrunner.py", line 254, in <module>
        main()
    File "C:\Install\PyCharm Community Edition16.3.2\helpers\pycharm\utrunner.py", line 232, in main
        module = loadSource(a[0])
    File "C:\Install\PyCharm Community Edition16.3.2\helpers\pycharm\utrunner.py", line 65, in loadSource
        module = imp.load_source(moduleName, fileName)
    File "E:\Work\Dev\Django\Tutorials\proj0\src\polls\tests.py", line 7, in <module>
        from polls.models import Question
    File "E:\Work\Dev\Django\Tutorials\proj0\src\polls\models.py", line 9, in <module>
        class Question(models.Model):
    File "E:\Work\Dev\Django\Tutorials\proj0\src\polls\models.py", line 10, in Question
        question_text = models.CharField(max_length=200)
    File "E:\Work\Dev\VEnvs\py2713x64-django\lib\site-packages\django\db\models\fields\__init__.py", line 1043, in __init__
        super(CharField, self).__init__(*args, **kwargs)
    File "E:\Work\Dev\VEnvs\py2713x64-django\lib\site-packages\django\db\models\fields\__init__.py", line 166, in __init__
        self.db_tablespace = db_tablespace or settings.DEFAULT_INDEX_TABLESPACE
    File "E:\Work\Dev\VEnvs\py2713x64-django\lib\site-packages\django\conf\__init__.py", line 53, in __getattr__
        self._setup(name)
    File "E:\Work\Dev\VEnvs\py2713x64-django\lib\site-packages\django\conf\__init__.py", line 39, in _setup
        % (desc, ENVIRONMENT_VARIABLE))
    django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.

Note: I only added the question to provide an answer that might be useful to someone.

注意:我添加这个问题只是为了提供一个可能对某人有用的答案。

回答by CristiFati

1. Background info

1. 背景资料

  • I am only working with Djangofor ~3 months
  • Regarding PyCharm, I worked with it for some years, but only as an IDE (like PyCharm for dummies), so I didn't get into its advanced stuff
  • 我只与Django 合作了大约 3 个月
  • 关于PyCharm,我用它工作了几年,但只是作为一个 IDE(就像PyCharm for dummies),所以我没有进入它的高级东西

Considering the above, some (or all) parts of the solution might seem cumbersome / stupid for some advanced users, so please bear with me. I will incorporate any possible comment that adds value into the solution.

考虑到上述情况,对于某些高级用户来说,解决方案的某些(或全部)部分可能看起来很麻烦/愚蠢,所以请耐心等待。我将在解决方案中加入任何可能增加价值的评论。

Back to the question: I did my tests / research on a project that consists of Django Tutorial([DjangoProject]: Writing your first Django app) + some parts from Django Rest Framework Tutorial([DRF]: Quickstart). As an example, I'm going to attempt running polls/tests.py: QuestionViewTests.test_index_view_with_no_questions()

回到问题:我对一个项目进行了测试/研究,该项目由Django 教程[DjangoProject]:编写您的第一个 Django 应用程序)+ Django Rest 框架教程[DRF]:快速入门)中的一些部分组成。例如,我将尝试运行polls/tests.pyQuestionViewTests.test_index_view_with_no_questions()

As a note, setting DJANGO_SETTINGS_MODULEas the exception instructs, triggers another one, and so on ...

请注意,DJANGO_SETTINGS_MODULE设置为异常指示,触发另一个,依此类推......

2. Creating a Pythonconfiguration

2. 创建Python配置

Although this is not an answer to the question (it's only remotely related), I'm posting it anyway (I'm sure that many people already did it):

虽然这不是问题的答案(它只是远程相关),但我还是要发布它(我相信很多人已经这样做了):

  • Click on the menu Run -> Edit Configurations...
  • On the Run/Debug Configurationsdialog:
    • Add a new configuration having the type: Python
    • Set the Working directoryto the root path of your project (for me it is "E:\Work\Dev\Django\Tutorials\proj0\src"). By default, this will also add the path in the Python's modules search paths
    • Set the Scriptto your Djangoproject startup script (manage.py)
    • Set the Script parametersto the test parameters (test QuestionViewTests.test_index_view_with_no_questions)
    • Give your configuration a name (optional) and click OK. Now, you will be able to run this test
  • 单击菜单运行 -> 编辑配置...
  • 运行/调试配置对话框中:
    • 添加具有以下类型的新配置:Python
    • 工作目录设置为项目的根路径(对我来说是“ E:\Work\Dev\Django\Tutorials\proj0\src”)。默认情况下,这也会在Python的模块搜索路径中添加路径
    • 脚本设置为您的Django项目启动脚本 ( manage.py)
    • 脚本参数设置为测试参数 ( test QuestionViewTests.test_index_view_with_no_questions)
    • 为您的配置命名(可选)并单击OK。现在,您将能够运行此测试

Of course, having to do this for every test case (and their methods) is not the way to go (it is truly annoying), so this approach is not scalable.

当然,必须为每个测试用例(及其方法)执行此操作并不是可行的方法(这确实很烦人),因此这种方法不可扩展。

3. Adjusting PyCharmto do what we want

3. 调整PyCharm来做我们想做的事

Just to be noted that I don't see this as a true solution, it's more like a (lame) workaround (gainarie), and it's also intrusive.

需要注意的是,我不认为这是一个真正的解决方案,它更像是一种(蹩脚的)解决方法(Gainarie),而且它也具有侵入性。

Let's start by looking what happens when we RClickon a test(I'm going to use this term in general - it might mean Test Case or method or whole test file, unless specified otherwise). For me, it is running the following command:

让我们首先看看当我们RClick一个测试时会发生什么(我将一般使用这个术语 - 它可能意味着测试用例或方法或整个测试文件,除非另有说明)。对我来说,它正在运行以下命令:

"E:\Work\Dev\VEnvs\py2713x64-django\Scripts\python.exe" "C:\Install\PyCharm Community Edition16.3.2\helpers\pycharm\utrunner.py" E:\Work\Dev\Django\Tutorials\proj0\src\polls\tests.py::QuestionViewTests::test_index_view_with_no_questions true
"E:\Work\Dev\VEnvs\py2713x64-django\Scripts\python.exe" "C:\Install\PyCharm Community Edition16.3.2\helpers\pycharm\utrunner.py" E:\Work\Dev\Django\Tutorials\proj0\src\polls\tests.py::QuestionViewTests::test_index_view_with_no_questions true

As you can see, it's launching "C:\Install\PyCharm Community Edition\2016.3.2\helpers\pycharm\utrunner.py" (I'm going to refer to it as utrunner) with a bunch of arguments (the 1stmatters to us, since it's the test specification). utrunneruses a test run framework which does not care about Django(actually there is some Djangohandling code, but that's not helping us).

如您所见,它正在启动“ C:\Install\PyCharm Community Edition\2016.3.2\helpers\pycharm\utrunner.py”(我将其称为utrunner)并带有一堆参数(第一个对我们很重要,因为它是测试规范)。utrunner使用一个不关心Django的测试运行框架(实际上有一些Django处理代码,但这对我们没有帮助)。

A few words on PyCharm`s Run/Debug configurations:

关于PyCharm运行/调试配置的几句话:

  • When RClick-ing on a test, PyCharmautomatically creates a new Run configuration(that you will be able to save), just like you would from the Run/Debug Configurationsdialog. An importantthing to note is the configuration type which is Python tests/Unittests(which automatically fires utrunner)
  • When creating a Run configurationin general, PyCharm"copies" the settings from that configuration type Defaults(can be viewed in the Run/Debug Configurationsdialog), into the new configuration, and fills the others with specific data. One important thing about Default configurationsis that they are project based: they reside in the .ideafolder (workspace.xml) of the project, so modifying them would not impact other projects (as I first feared)
  • RClick测试上时PyCharm 会自动创建一个新的运行配置(您将能够保存),就像您在运行/调试配置对话框中所做的一样。需要注意的重要一点是配置类型是Python 测试/单元测试(它会自动触发utrunner
  • 通常在创建运行配置时,PyCharm 会将该配置类型的默认设置(可以在运行/调试配置对话框中查看)“复制”到新配置中,并用特定数据填充其他配置。关于默认配置的一件重要的事情是它们是基于项目的:它们驻留在项目.idea文件夹(workspace.xml)中,因此修改它们不会影响其他项目(正如我最初担心的那样)

With the above in mind, let's proceed:

考虑到上述情况,让我们继续:

First thingyou need to do is: from the Run/Debug Configurationsdialog (menu: Run -> Edit Configurations...), edit the Defaults/Python tests/Unittestssettings:

您需要做的第一件事是:从Run/Debug Configurations对话框(菜单:Run -> Edit Configurations...),编辑Defaults/Python 测试/Unittests设置:

  • Set the Working directoryjust like in the previous approach
  • In the Environment variablesadd a new one named DJANGO_TEST_MODE_GAINARIEand set it to any string (other than empty/null)
  • 像以前的方法一样设置工作目录
  • 环境变量中添加一个名为DJANGO_TEST_MODE_GAINARIE的新变量并将其设置为任何字符串(空/除外)

Second thingand the trickier one (also involving intrusion): patching utrunner.

第二件事也是更棘手的一件事(也涉及入侵):修补utrunner

utrunner.patch:

utrunner.patch

--- utrunner.py.orig    2016-12-28 19:06:22.000000000 +0200
+++ utrunner.py 2017-03-23 15:20:13.643084400 +0200
@@ -113,7 +113,74 @@
   except:
     pass

-if __name__ == "__main__":
+
+def fileToMod(filePath, basePath):
+  if os.path.exists(filePath) and filePath.startswith(basePath):
+    modList = filePath[len(basePath):].split(os.path.sep)
+    mods = ".".join([os.path.splitext(item)[0] for item in modList if item])
+    return mods
+  else:
+    return None
+
+
+def utrunnerArgToDjangoTest(arg, basePath):
+  if arg.strip() and not arg.startswith("--"):
+    testData = arg.split("::")
+    mods = fileToMod(testData[0], basePath)
+    if mods:
+      testData[0] = mods
+      return ".".join(testData)
+    else:
+      return None
+  else:
+    return None
+
+
+def flushBuffers():
+  sys.stdout.write(os.linesep)
+  sys.stdout.flush()
+  sys.stderr.write(os.linesep)
+  sys.stderr.flush()
+
+
+def runModAsMain(argv, codeGlobals):
+  with open(argv[0]) as f:
+    codeStr = f.read()
+  sys.argv = argv
+  code = compile(codeStr, os.path.basename(argv[0]), "exec")
+  codeGlobals.update({
+    "__name__": "__main__",
+    "__file__": argv[0]
+    })
+  exec(code, codeGlobals)
+
+
+def djangoMain():
+  djangoTests = list()
+  basePath = os.getcwd()
+  for arg in sys.argv[1: -1]:
+    djangoTest = utrunnerArgToDjangoTest(arg, basePath)
+    if djangoTest:
+      djangoTests.append(djangoTest)
+  if not djangoTests:
+    debug("/ [DJANGO MODE] Invalid arguments: " + sys.argv[1: -1])
+  startupTestArgs = [item for item in os.getenv("DJANGO_STARTUP_TEST_ARGS", "").split(" ") if item]
+  startupFullName = os.path.join(basePath, os.getenv("DJANGO_STARTUP_NAME", "manage.py"))
+  if not os.path.isfile(startupFullName):
+    debug("/ [DJANGO MODE] Invalid startup file: " + startupFullName)
+    return
+  djangoStartupArgs = [startupFullName, "test"]
+  djangoStartupArgs.extend(startupTestArgs)
+  djangoStartupArgs.extend(djangoTests)
+  additionalGlobalsStr = os.getenv("DJANGO_STARTUP_ADDITIONAL_GLOBALS", "{}")
+  import ast
+  additionalGlobals = ast.literal_eval(additionalGlobalsStr)
+  flushBuffers()
+  runModAsMain(djangoStartupArgs, additionalGlobals)
+  flushBuffers()
+
+
+def main():
   arg = sys.argv[-1]
   if arg == "true":
     import unittest
@@ -186,3 +253,10 @@

   debug("/ Loaded " + str(all.countTestCases()) + " tests")
   TeamcityTestRunner().run(all, **options)
+
+
+if __name__ == "__main__":
+  if os.getenv("DJANGO_TEST_MODE_GAINARIE"):
+    djangoMain()
+  else:
+    main()

The above is a diff([man7]: DIFF(1)) (or a patch- the names can be used conjunctively - I preffer (and will use) patch): it shows the differences between utrunner.py.orig(the original file - that I saved before starting modifying, you don't need to do it) and utrunner.py(the current version containing the changes). The command that I used is diff --binary -uN utrunner.py.orig utrunner.py(obviously, in utrunner's folder). As a personal remark, patchis the preferred form of altering 3rdparty source code (to keep changes under control, and separate).

上面是一个diff( [man7]: DIFF(1))(或一个补丁- 名称可以连用 - 我喜欢(并将使用)补丁):它显示了utrunner.py.orig(原始文件 - 我在开始修改之前保存的,你不需要这样做)和utrunner.py(包含更改的当前版本)。我使用的命令是diff --binary -uN utrunner.py.orig utrunner.py(显然,在utrunner的文件夹中)。作为个人的话,补丁是改变3优选形式RD方的源代码(控制住的变化,并分离)。

What the code in the patchdoes (it's probably harder to follow than plain Pythoncode):

补丁中的代码做了什么(它可能比普通的Python代码更难理解):

  • Everything under the mainblock (if __name__ == "__main__":or the current behavior) has been moved into a function called main(to keep it separate and avoid altering it by mistake)
  • The mainblock was modified, so that if the env var DJANGO_TEST_MODE_GAINARIEis defined (and not empty), it will follow the new implementation (djangoMainfunction), otherwise it will act normally. The new implementation:
    • fileToModsubtracts basePathfrom filePathand converts the difference into Pythonpackage style. Ex: fileToMod("E:\Work\Dev\Django\Tutorials\proj0\src\polls\tests.py", "E:\Work\Dev\Django\Tutorials\proj0\src"), will return polls.tests
    • utrunnerArgToDjangoTest: uses the previous function and then adds the class name (QuestionViewTests) and (optionally) the method name (test_index_view_with_no_questions), so at the end it converts the test specification from utrunnerformat (E:\Work\Dev\Django\Tutorials\proj0\src\polls\tests.py::QuestionViewTests::test_index_view_with_no_questions) to manage.pyformat (polls.tests.QuestionViewTests.test_index_view_with_no_questions)
    • flushBuffers: writes an eolnchar and flushes the stdoutand stderrbuffers (this is needed because I noticed that sometimes the outputs from PyCharmand Djangoare interleaved, and the final result is messed up)
    • runModAsMain: typically, all the relevant manage.pycode is under if __name__ == "__main__":. This function "tricks" Pythonmaking it believe that manage.pywas run as its 1stargument
  • 下一切主要块(if __name__ == "__main__":或当前行为)已经被移动到一个名为函数(为了保持分开,避免改变其错误)
  • 块被修改,因此,如果的环境变量DJANGO_TEST_MODE_GAINARIE定义(而不是空的),它会按照新的实现(djangoMain功能),否则将采取行动正常。新的实现:
    • fileToModfilePath 中减去basePath并将差异转换为Python包样式。例如:,将返回fileToMod("E:\Work\Dev\Django\Tutorials\proj0\src\polls\tests.py", "E:\Work\Dev\Django\Tutorials\proj0\src")polls.tests
    • utrunnerArgToDjangoTest:使用前面的函数,然后添加类名(QuestionViewTests)和(可选)方法名(test_index_view_with_no_questions),所以最后它将测试规范从utrunner格式(E:\Work\Dev\Django\Tutorials\proj0\src\polls\tests.py::QuestionViewTests::test_index_view_with_no_questions)转换为manage.py格式(polls.tests.QuestionViewTests.test_index_view_with_no_questions
    • flushBuffers: 写入一个eolnchar 并刷新stdoutstderr缓冲区(这是必需的,因为我注意到有时来自PyCharmDjango的输出是交错的,并且最终结果一团糟)
    • runModAsMain:通常,所有相关的manage.py代码都在if __name__ == "__main__":. 这个函数“欺骗”了Python,让它相信manage.py是作为它的第一个参数运行的

Patching utrunner:

修补utrunner

  • I did these modifications on my own (I didn't search for versions having Djangointegration and inspire from there)
  • utrunneris part of PyCharm. It's obvious why JetBrainsguys didn't include any Djangointegration in the Community Edition: to make people buy the Professional Edition. This kinda steps on their toes. I'm not aware of the legal implications of modifying utrunner, but anyway if you patch it, you're doing it on your own responsibility and risk
  • Coding style: it sucks (at least from naming / indenting PoV), but it's consistent with the rest of the file (the only case when coding style should be allowed to suck). [Python]: PEP 8 -- Style Guide for Python Codecontains the coding style guidelines for Python
  • The patch is applied on the original file (utrunner.py), with the following properties (still valid for v2019.2.3(last checked: 20190930)):
    • size: 5865
    • sha256sum: db98d1043125ce2af9a9c49a1f933969678470bd863f791c2460fe090c2948a0
  • Applying the patch:
    • utrunneris located in "${PYCHARM_INSTALL_DIR}/helpers/pycharm"
    • Typically, ${PYCHARM_INSTALL_DIR}points to:
      • Nix: /usr/lib/pycharm-community
      • Win: "C:\Program Files (x86)\JetBrains\PyCharm 2016.3" (adapt to your version number)
    • Save the patchcontent (in a file called e.g. utrunner.patch, let's assume it's under /tmp)
    • Nix- things are easy, just (cdto utrunner's folder and) run patch -i /tmp/utrunner.patch. [man7]: PATCH(1)is an utility that is installed by default (part of patchdpkg in Ubtu). Note that since utrunner.pyis owned by root, for this step you would need sudo
    • Win- similar steps to be followed, but things are trickier since there's no native patchutility. However, there are workarounds:
      • Use Cygwin. As in Nix(Lnx) case, patchutility is available, but it doesn't get installed by default. The patchpkg must be explicitlyinstalled from Cygwin setup. I tried this and it works
      • There are alternatives (I didn't try them):
      • As in Nix's case, patching the file would (most likely) have to be done by one of the Administrators. Also, watch out for file paths, make sure to (dbl)quotethem if they contain spaces
    • Reverting the patch:
      • Backups are not harmful (except from the free disk space's PoV, or when they start to pile up, managing them becomes a pain). There's no need for them in our case. In order to revert the changes, just run the command on the modified file: patch -Ri /tmp/utrunner.patch, and it will switch it back to its original content (it will also create an utrunner.py.origfile with the modified content; it will actually switch the .pyand .py.origfiles).
        Nevertheless always back 3rd-party files up before modifying them(especially if they're being tracked by some tools / installers), so that if something goes wrong while modifying them, there's always a way to restore the original state
    • Although not the case here, but if the changes are in another form, like the file with the patchapplied (e.g. on GitHub), you can obviously get the entire file (if there are many files, tracking all of them down could become a pain) and overwrite yours. But again, back it (them) up first!
  • 我自己做了这些修改(我没有搜索具有Django集成和启发的版本)
  • utrunnerPyCharm 的一部分。很明显为什么JetBrains人没有社区版中包含任何Django集成:让人们购买专业版。这有点踩在他们的脚趾上。我不知道修改utrunner的法律含义,但无论如何,如果您修补它,您将自行承担责任和风险
  • 编码风格:它很糟糕(至少从命名/缩进PoV来看),但它与文件的其余部分一致(应该允许编码风格糟糕的唯一情况)。[Python中]:PEP 8 -风格指南Python代码包含了编码样式准则的Python
  • 该补丁应用于原始文件(utrunner.py),具有以下属性(对v 2019.2.3仍然有效(最后检查:20190930)):
    • 尺寸:5865
    • sha256sum: db98d1043125ce2af9a9c49a1f933969678470bd863f791c2460fe090c2948a0
  • 应用补丁
    • utrunner位于“ ${PYCHARM_INSTALL_DIR}/helpers/pycharm
    • 通常,${PYCHARM_INSTALL_DIR}指向:
      • 尼克斯/usr/lib/pycharm-community
      • Win: " C:\Program Files (x86)\JetBrains\PyCharm 2016.3"(适应你的版本号)
    • 保存补丁内容(在一个名为utrunner.patch的文件中,假设它在/tmp 下
    • Nix- 事情很简单,只需(cdutrunner的文件夹并)运行patch -i /tmp/utrunner.patch. [man7]:PATCH(1)是一个默认安装的实用程序(Ubtu补丁dpkg 的一部分)。请注意,由于utrunner.pyroot 所有,因此在此步骤中您需要sudo
    • Win- 要遵循类似的步骤,但由于没有本机补丁实用程序,因此事情变得更加棘手。但是,有一些解决方法:
      • 使用Cygwin。在Nix( Lnx) 情况下,补丁实用程序可用,但默认情况下不会安装。该补丁PKG必须明确地从安装Cygwin的设置。我试过了,它有效
      • 还有其他选择(我没有尝试过):
      • Nix的情况一样,修补文件(很可能)必须由其中一位管理员完成。另外,注意文件路径,如果它们包含空格,请确保(dbl)引用它们
    • 恢复补丁
      • 备份是无害的(除了来自可用磁盘空间的PoV,或者当它们开始堆积时,管理它们变得很痛苦)。在我们的案例中不需要它们。为了恢复更改,只需在修改后的文件上运行命令:patch -Ri /tmp/utrunner.patch,它将把它切换回原来的内容(它还会用修改后的内容创建一个utrunner.py.orig文件;它实际上会切换. py.py.orig文件)。
        不过总是回到3三方修改之前文件了(特别是如果他们被一些工具/安装跟踪),这样,如果在修改他们不顺心的事,总有恢复原来状态的方法
    • 虽然这里不是这种情况,但是如果更改是另一种形式,例如应用补丁的文件(例如在GitHub 上),您显然可以获得整个文件(如果有很多文件,跟踪所有文件可能会变成一个痛)并覆盖你的。但同样,首先支持它(他们)

Couple of words about this approach:

关于这种方法的几句话

  • The code can handle (optional) env vars (other than DJANGO_TEST_MODE_GAINARIE- which is mandatory):

    • DJANGO_STARTUP_NAME: in case that manage.pyhas other name (for whatever reason?), or is located in another folder than the Working directory. An importantthing here: when specifying file paths, use the platform specific path separator: slash(/) for Nix, bkslash(\) for Win
    • DJANGO_STARTUP_TEST_ARGS: additional arguments that manage.py testaccepts (run manage.py test --helpto get the whole list). Here, I have to insist on -k/ --keepdbwhich preserves the test database (test_${REGULAR_DB_NAME}by default or set in settingsunder the TESTdictionary) between runs. When running a single test, creating the DB(and applying all the migrations) and destroying it can be be time consuming (and very annoying as well). This flag ensures that the DBis not deleted at the end and will be reused at the next test run
    • DJANGO_STARTUP_ADDITIONAL_GLOBALS: this must have the string representation of a Python dict. Any values that for some reason are required by manage.pyto be present in the globals()dictionary, should be placed here
  • When modifying a Default configuration, all previously created configurations that inherit it, won't be updated, so they have to be manually removed(and will be automatically recreated by new RClicks on their tests)

  • 代码可以处理(可选)环境变量(除了DJANGO_TEST_MODE_GAINARIE- 这是强制性的):

    • DJANGO_STARTUP_NAME:如果manage.py有其他名称(出于某种原因?),或者位于除工作目录之外的另一个文件夹中。这里有一件重要的事情:指定文件路径时,使用平台特定的路径分隔符:斜线( /) 代表Nixbkslash( \) 代表Win
    • DJANGO_STARTUP_TEST_ARGSmanage.py test接受的附加参数(运行manage.py test --help以获取整个列表)。在这里,我必须坚持-k/ --keepdb在运行之间保留测试数据库(默认情况下test_${REGULAR_DB_NAME}或在TEST字典下的设置中设置)。运行单个测试时,创建数据库(并应用所有迁移)并销毁它可能很耗时(而且也很烦人)。此标志确保数据库在最后不会被删除,并将在下一次测试运行时重新使用
    • DJANGO_STARTUP_ADDITIONAL_GLOBALS:这必须具有Python dict的字符串表示形式。由于某种原因,manage.py要求出现在globals()字典中的任何值都应该放在这里
  • 修改默认配置时,所有先前创建的继承它的配置都不会更新,因此必须手动删除它们(并且将在其测试中由新的RClick自动重新创建)

RClickon the same test (after deleting its previous configuration :d), and voilà:

R单击相同的测试(删除其先前的配置后:d),然后

E:\Work\Dev\VEnvs\py2713x64-django\Scripts\python.exe "C:\Install\PyCharm Community Edition16.3.2\helpers\pycharm\utrunner.py" E:\Work\Dev\Django\Tutorials\proj0\src\polls\tests.py::QuestionViewTests::test_index_view_with_no_questions true
Testing started at 01:38 ...


Using existing test database for alias 'default'...
.
----------------------------------------------------------------------
Ran 1 test in 0.390s

OK

Preserving test database for alias 'default'...


Process finished with exit code 0
E:\Work\Dev\VEnvs\py2713x64-django\Scripts\python.exe "C:\Install\PyCharm Community Edition16.3.2\helpers\pycharm\utrunner.py" E:\Work\Dev\Django\Tutorials\proj0\src\polls\tests.py::QuestionViewTests::test_index_view_with_no_questions true
Testing started at 01:38 ...


Using existing test database for alias 'default'...
.
----------------------------------------------------------------------
Ran 1 test in 0.390s

OK

Preserving test database for alias 'default'...


Process finished with exit code 0

Debugging also works (breakpoints, and so on ...).

调试也有效(断点,等等......)。

Caveats(so far I identified 2 of them):

注意事项(到目前为止,我确定了其中的 2 个):

  • This is benign, it's only an UIissue: utrunner(most likely) has some initialization that PyCharmexpects to take place, which obviously doesn't in our case. So, even if the test ended successfully, from PyCharm's PoVthey didn't and therefore the Outputwindow will contain a warning: "Test framework quit unexpectedly"
  • This is a nasty one, and I wasn't able to get to the bottom of it (yet). Apparently, in utrunnerany input(raw_input) call is not handled very well; the prompt text: "Type 'yes' if you would like to try deleting the test database 'test_tut-proj0', or 'no' to cancel:" (which appears if the previous test run crashed, and its DBwas not destroyed at the end) is not being displayed and the program freezes (this doesn't happen outside utrunner), without letting the user to input text (maybe there are threads in the mix?). The only way to recover is stopping the test run, deleting the DBand running the test again. Again, I have to promote the manage.py test -kflag which will get around this problem
  • 这是良性的,它只是一个UI问题:utrunner(很可能)有一些PyCharm期望发生的初始化,这在我们的例子中显然没有。因此,即使测试成功结束,从PyCharmPoV来看他们也没有,因此输出窗口将包含警告:“测试框架意外退出
  • 这是一个令人讨厌的问题,我(还)无法深入了解它。显然,在utrunner 中,任何input( raw_input) 调用都没有得到很好的处理;提示文本:“如果您想尝试删除测试数据库‘test_tut-proj0’,请输入‘yes’,或者‘no’取消:”(如果之前的测试运行崩溃,并且其数据库在最后)没有被显示并且程序冻结(这不会发生在utrunner之外),而不让用户输入文本(也许混合中有线程?)。恢复的唯一方法是停止测试运​​行,删除数据库并再次运行测试。再次,manage.py test -k

I've worked/tested on the following environments:

我已经在以下环境中工作/测试过:

  • Nix(Lnx):
    • Ubtu 16.04 x64
    • PyCharm Community Edition 2016.3.3
    • Python 3.4.4(VEnv)
    • Django 1.9.5
  • Win:
    • W10 x64
    • PyCharm Community Edition 2016.3.2
    • Python 2.7.13(VEnv)
    • Django 1.10.6
  • 尼克斯Lnx):
    • 16.04 x64
    • PyCharm 社区版 2016.3.3
    • Python 3.4.4( VEenv)
    • Django 1.9.5
    • W10 x64
    • PyCharm 社区版 2016.3.2
    • Python 2.7.13( VEenv)
    • Django 1.10.6

Notes:

注意事项

  • I will continue investigating the current issues (at least the 2ndone)
  • A cleansolution would be to override somehow in PyCharmthe Unit Test running default settings (what I did from code), but I couldn't find any config files (probably it's in the PyCharmjars?)
  • I noticed a lot of files/folders that are specific to Djangoin the helpers(utrunner's parent) folder, maybe those can be used too, will have to check
  • 我将继续调查当前的问题(至少是第二个)
  • 一个干净的解决方案是在PyCharm 中以某种方式覆盖运行默认设置的单元测试(我从代码中所做的),但我找不到任何配置文件(可能它在PyCharmjar 中?)
  • 我注意到有很多文件/文件夹所特有的的Django的助手utrunner的母公司)的文件夹,也许那些可以使用过多,则要检查

As I stated at the beginning, any suggestion is more than welcome!

正如我在开头所说的,任何建议都非常受欢迎!

@EDIT0:

@编辑0

  • As I replied to @Udi's comment, this is an alternative for people who can't afford (or companies that aren't willing) to pay the PyCharm Professional Editionlicense fee (on a quick browse it looks like it's ~100$-200$/ year for each instance)
  • 正如我在回复@Udi 的评论时所说,对于负担不起(或不愿意的公司)支付PyCharm 专业版许可费的人来说,这是一个替代方案(快速浏览它看起来大约是 100 美元-200 美元)每个实例的$/ 年)

回答by AndreyMZ

See https://github.com/AndreyMZ/jb_django_test_runner/blob/master/README.md.

请参阅https://github.com/AndreyMZ/jb_django_test_runner/blob/master/README.md

Pros:

优点:

  1. It works with PyCharm 2019.3.2.
  2. Output windows shows test results instead of error "Test framework quit unexpectedly".
  1. 它适用于 PyCharm 2019.3.2。
  2. 输出窗口显示测试结果而不是错误“测试框架意外退出”。