Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature suggestion: run Django unittests #73

Closed
DonJayamanne opened this issue Nov 13, 2017 · 75 comments · Fixed by #23935 · May be fixed by irinazheltisheva/vscode-python#3 or Aqeelkha/vscode-python#4
Closed

Feature suggestion: run Django unittests #73

DonJayamanne opened this issue Nov 13, 2017 · 75 comments · Fixed by #23935 · May be fixed by irinazheltisheva/vscode-python#3 or Aqeelkha/vscode-python#4
Assignees
Labels
area-testing feature-request Request for new features or functionality needs PR Ready to be worked on

Comments

@DonJayamanne
Copy link

From @jvaesteves on January 16, 2017 22:28

Django unittest extends from unittests, but you can't run as the former on this extension. For this, you need to "manage.py test", but it would be awesome if there were those same shortcuts.

Copied from original issue: DonJayamanne/pythonVSCode#648

@DonJayamanne
Copy link
Author

From @guhuajun on January 19, 2017 6:51

I did something like following. I think it's supported now.

default

default

@DonJayamanne
Copy link
Author

From @jvaesteves on January 19, 2017 12:13

I tried your suggestion, copying the same parameters on the settings.json file, but running the "Run Unit Test Method..." command still doesn't work. The Output Console gives me the following message:

ImproperlyConfigured: Requested setting DATABASES, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.

And then, when I configure this environment variable to my global_settings.py path, the message change to: ImportError: Import by filename is not supported.

@DonJayamanne
Copy link
Author

DonJayamanne commented Nov 13, 2017

From @guhuajun on January 20, 2017 0:22

https://github.com/DonJayamanne/pythonVSCode/wiki/unitest-(Standard-Unit-testing)-Framework#test-discovery
Please try to place a __init__.py.

Yes, missing DJANGO_SETTINGS_MODULE is annoying. I encountered this issue when writing tests for a django-cms project.

@DonJayamanne
Copy link
Author

@jvaesteves Will be closing this issue as @guhuajun has a solution.

@DonJayamanne
Copy link
Author

@jvaesteves please confirm @guhuajun suggestion works, so I can close this issue.

@DonJayamanne
Copy link
Author

From @jvaesteves on February 2, 2017 10:46

No, it didn't.

@DonJayamanne
Copy link
Author

From @james-perretta on March 5, 2017 4:35

It looks to me like the suggestion from @guhuajun gets us part of the way there for running Django test cases. Unless I'm mistaken, you can't really use unittest to run tests for any serious Django project.
When you run python manage.py test, it first does general setup (figuring out which settings module to use and calling django.setup()). After that, it hands the rest off to a test-runner class that does even more important things like creating and destroying the databases that the test cases need to operate on.

I did a bit of digging, and although I'm not particularly familiar with the implementation details of your plugin, I think this is a starter summary of what it would require to add this:

  • Add client modules similar to those for nose and pytest (I have almost zero knowledge of how this part works)
  • Add handling for testFx == 'django' in testlauncher.py. This would involve code similar to what you see here in the runtests.py snippet.
  • Possibly add a workspace settings option that lets the user specify the value for DJANGO_SETTINGS_MODULE. That environment variable needs to be set before calling django.setup()
  • Certain manage.py test options should always be passed, such as --no-input
  • Add support for other django-specific unit test options, such as --tag, --exclude-tag, and maybe --parallel

Thoughts?

@DonJayamanne
Copy link
Author

From @PlugaruT on October 3, 2017 11:15

Because I have different settings files for each environment (production, local, test), I can't run tests because with this plugin because DJANGO_SETTINGS_MODULE is not set when trying to run the tests. I would be nice if I could set this env variable in in the workspace.json or somewhere else.

@DonJayamanne
Copy link
Author

@PlugaruT Environment variables can be set for the workspace. Just create a file named .env in your workspace root and add the necessary variables in there.

@wsantos
Copy link

wsantos commented Dec 21, 2017

Any update here?, I have a bunch of tests file, I'm not sure where to put django.setup() if that is a real solution.

@Kurara
Copy link

Kurara commented Dec 21, 2017

You don't need to configure DJANGO_SETTINGS_MODULE if you use the option: "--settings < filesetting >" Just saying because maybe we can make thah unittest plugin doesn't need env variable, just tell him the setting and if not, use default.

And just one question about my closed issue.

My problem is not implementation of new feature for django. But tests are not DISCOVERED at all. I could make them run at least in part, but if it doesn't discover them I can't. When I use python -m unittest it discovers the tests, so the structure must be ok.

@yardensachs
Copy link

yardensachs commented Mar 7, 2018

Any decision on this? This is somewhat of a small ask, but it will make dev work better for those who use django and not pytest/nose/etc.

@brettcannon
Copy link
Member

@yardensachs not at the moment (we're tied up with other things that impact all Python developers). If anyone wants to submit a PR to introduce a fix for this we would happily review it.

@antoniogamizbadger
Copy link

So.. any update on this? I tried setting up our company project with VSCode and the extension is still unable to find django test modules.

@khamaileon
Copy link

Apparently the next step is here and we need votes to get things going. If the 300+ people who liked this post could make their voices heard.

@carltongibson
Copy link

@khamaileon Nice. Good spot. I didn't even know about that other issue.

@mh-firouzjah
Copy link

Apparently the next step is here and we need votes to get things going. If the 300+ people who liked this post could make their voices heard.

As long as the proposed procedure is taking approval, I have tested a new idea, and it worked well for me. I am awaiting feedback and information on whether it works properly for you and others, or if there are any issues.

I expected that after running the tests, there would be a change in the main project database Which it did not and the main database is clear; because in this approach, I did not use a CustomTestRunner.

NOTE: This method requires fewer changes in the vscode extension and is also easier to modify the django_settings_module for each project, especially when we have multiple modules as settings for different scenarios such as development, production, and so on.

1- Vscode Python Extension Requirement
edit the __init__.py module in ~/.vscode/extensions/ms-python.python-VERSION/pythonFiles/unittestadapter/__init__.py and add the code below:

try:
    import django
    django.setup()
except:
    pass

2- Django Project Requirement
create a .env file and inside of it declare DJANGO_SETTINGS_MODULE. an example is:

DJANGO_SETTINGS_MODULE=my_django_project_name.settings

@khamaileon
Copy link

@mh-firouzjah I tried but it didn't work out.

Here's my vscode settings:

{
  "editor.codeActionsOnSave": {
    "source.organizeImports": "explicit"
  },
  "editor.formatOnSave": true,
  "python.defaultInterpreterPath": "~/.virtualenvs/acme-api/bin/python",
  "python.envFile": "${workspaceFolder}/.env.local",
  "editor.rulers": [100],
  "python.testing.unittestArgs": ["-v", "-s", "./src", "-p", "test*.py"],
  "python.testing.pytestEnabled": false,
  "python.testing.unittestEnabled": true
}

And here's the kind of output I got:

2024-02-06 10:36:32.276 [info] Telemetry level is off
2024-02-06 10:36:32.276 [info] Experiments are disabled, only manually opted experiments are active.
2024-02-06 10:36:32.276 [info] Default formatter is set to ms-python.black-formatter for workspace /home/me/workspace/acme/mars-api
2024-02-06 10:36:32.276 [info] Test server listening.
2024-02-06 10:36:32.276 [info] VS Code was launched from an activated environment: 'mars-api', selecting it as the interpreter for workspace.
2024-02-06 10:36:32.276 [info] Python interpreter path: ~/.virtualenvs/mars-api/bin/python
2024-02-06 10:36:34.315 [info] Starting Pylance language server.
2024-02-06 10:36:43.381 [info] Discover tests for workspace name: mars-api - uri: /home/me/workspace/acme/mars-api
2024-02-06 10:36:43.405 [info] > . ~/.virtualenvs/mars-api/bin/activate && echo '<some_uuid>' && python ~/.vscode/extensions/ms-python.python-2024.0.0/pythonFiles/printEnvVariables.py
2024-02-06 10:36:43.405 [info] shell: bash
2024-02-06 10:36:43.457 [info] > ~/.virtualenvs/mars-api/bin/python ~/.vscode/extensions/ms-python.python-2024.0.0/pythonFiles/testing_tools/unittest_discovery.py ./src test*.py
2024-02-06 10:36:43.457 [info] cwd: .
2024-02-06 10:36:44.068 [error] Error discovering unittest tests:
 Failed to import test module: account.tests
Traceback (most recent call last):
  File "/usr/lib/python3.12/unittest/loader.py", line 394, in _find_test_path
    module = self._get_module_from_name(name)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/unittest/loader.py", line 337, in _get_module_from_name
    __import__(name)
  File "/home/me/workspace/acme/mars-api/src/account/tests.py", line 15, in <module>
    from account.models import Session, User
  File "/home/me/workspace/acme/mars-api/src/account/models.py", line 3, in <module>
    from django.contrib.auth.models import AbstractUser
  File "/home/me/.virtualenvs/mars-api/lib/python3.12/site-packages/django/contrib/auth/models.py", line 3, in <module>
    from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
  File "/home/me/.virtualenvs/mars-api/lib/python3.12/site-packages/django/contrib/auth/base_user.py", line 58, in <module>
    class AbstractBaseUser(models.Model):
  File "/home/me/.virtualenvs/mars-api/lib/python3.12/site-packages/django/db/models/base.py", line 129, in __new__
    app_config = apps.get_containing_app_config(module)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/me/.virtualenvs/mars-api/lib/python3.12/site-packages/django/apps/registry.py", line 260, in get_containing_app_config
    self.check_apps_ready()
  File "/home/me/.virtualenvs/mars-api/lib/python3.12/site-packages/django/apps/registry.py", line 138, in check_apps_ready
    raise AppRegistryNotReady("Apps aren't loaded yet.")
django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.

DJANGO_SETTINGS_MODULE=project.settings is read correctly, otherwise I'm told it's necessary.

The problem may be that my code is in a src folder and not in the root. 🤷‍♂️

@mh-firouzjah
Copy link

hi @khamaileon,
yes, DJANGO_SETTINGS_MODULE is read. but for the error you got it seems that django.setup() had not been called at the beginning of the process.
being in a subdirectory could be the case but if you also have error when using manage.py check/runserver/...
otherwise I don't think thats the problem here.

@khamaileon
Copy link

khamaileon commented Feb 8, 2024

Yet I'm able to launch it with the manage command inside vscode and outside (from the src folder).
Here is my launch.json config file.

{
  // Use IntelliSense to learn about possible attributes.
  // Hover to view descriptions of existing attributes.
  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Python: Django",
      "type": "python",
      "request": "launch",
      "program": "${workspaceFolder}/src/manage.py",
      "args": ["runserver"],
      "django": true,
      "envFile": "${workspaceFolder}/.env.local",
      "justMyCode": true
    }
  ]
}

@mardukbp
Copy link

Thank you @mh-firouzjah! Your solution works great :)

@eleanorjboyd
Copy link
Member

eleanorjboyd commented Aug 15, 2024

Hello Everyone! The long requested ask is live!! Django tests are now supported in the VS Code python extension! Currently this is pre-release and would greatly appreciate Django users try this out and give feedback / submit bugs! (there will likely be bugs so I appeciate your patience as we work through them)

Steps:

  1. Change your python extension so you are on the pre-release of the extension
    1. specifically version v2024.13.2024081501 or newer
  2. Add an environment variable called MANAGE_PY_PATH='path-string-to-manange.py-path' - below are steps specifically if you aren’t sure how to do this:
    1. create a .env file
    2. add MANAGE_PY_PATH='path-string-to-manange.py-path' to the file
    3. add the following to your settings.json "python.envFile": "${workspaceFolder}/.env” to pick up this file as part of the environment (edit path as necessary if .env not at root)
  3. Now click on the “beaker” icon and pull up the test explorer panel
  4. If not already selected, select “unittest” as your testing framework (you can also do the following in settings.json "python.testing.unittestEnabled": true,)
  5. From here your tests should be discovered and populated in the tree and then run and debug should work! if this is not working try:
    1. adding "python.testing.unittestArgs": [], maybe the tests just aren’t being found
    2. look at the python output panel- this will show error messages
    3. try from command line to make sure it works, then transfer that exact command to how it needs to be represented in VS Code. For example you have python manage.py test --arg to get the same in VS Code make MANAGE_PY_PATH='./manage.py' "python.testing.unittestArgs": [--arg] and check the output as it should print the final command that is actually run
    4. attempt using absolute path for manage.py if you are using relative to start
  6. Let me know how it went! If it works or doesn’t please let me know so we can get an idea of how the feature is doing
  7. To submit a bug:
    1. try it again but with your logs on verbose, turn this on via “developer: set log level” command in the command palette
    2. use the command palette and select python: report issue.. command, follow steps there and add your logs copied above
    3. either describe your repo structure / tests or include your repo (or it can be a minimal repro if your repo is private) so I can try it myself.

Thank you!

@swebra
Copy link

swebra commented Aug 15, 2024

@eleanorjboyd just some quick spelling mistakes to save anyone copy pasting:

  • In 2 and 2ii, manange.py should be fixed to manage.py in MANAGE_PY_PATH=..., i.e. it should be MANAGE_PY_PATH='path-string-to-manage.py-path'
  • In 2iii, the setting JSON snippet should end in a straight double quote (") rather than a closing (curly) double quote ()

And some very initial feedback: manage.py seems to be called with a verbosity -v flag without providing a verbosity level, causing the test discovery to error out:

2024-08-15 14:02:27.371 [info] Discovering unittest tests for workspace /home/eric/django-test with arguments: /home/eric/.vscode-server/extensions/ms-python.python-2024.13.2024081501-linux-x64/python_files/unittestadapter/discovery.py,--udiscovery,-v,-s,./mysite,-p,test_*.py

2024-08-15 14:02:27.371 [info] > ./.direnv/python-3.11.0rc1/bin/python ~/.vscode-server/extensions/ms-python.python-2024.13.2024081501-linux-x64/python_files/unittestadapter/discovery.py --udiscovery -v -s ./mysite -p test_*.py
2024-08-15 14:02:27.371 [info] cwd: .
2024-08-15 14:02:27.557 [info] MANAGE_PY_PATH is set, running Django discovery with path to manage.py as: $./manage.py
Running Django tests with command: ['/home/eric/django-test/.direnv/python-3.11.0rc1/bin/python', './manage.py', 'test', '--testrunner=django_test_runner.CustomDiscoveryTestRunner', '-v', '-s', './mysite', '-p', 'test_*.py']

2024-08-15 14:02:28.233 [error] usage: manage.py test [-h] [--noinput] [--testrunner TESTRUNNER] [--failfast]
                      [-t TOP_LEVEL] [-p PATTERN] [--keepdb]
                      [--shuffle [SEED]] [-r] [--debug-mode] [-d]
                      [--parallel [N]] [--tag TAGS]
                      [--exclude-tag EXCLUDE_TAGS] [--pdb] [-b]
                      [--no-faulthandler] [--timing] [-k TEST_NAME_PATTERNS]
                      [--version] [-v {0,1,2,3}] [--settings SETTINGS]
                      [--pythonpath PYTHONPATH] [--traceback] [--no-color]
                      [--force-color]
                      [test_label ...]
manage.py test: error: argument -v/--verbosity: expected one argument

Django test discovery process exited with non-zero error code See stderr above for more details.

This is reproducible against a generated Django v5.1 project created with django-admin startproject mysite as per the Django docs tutorial. Also note the -s ./mysite argument, which also does not seem to be supported.

LMK if you want me to flesh this out into a proper GH issue.

@eleanorjboyd
Copy link
Member

Hi @swebra thank you for trying it! Ill make those fixes to the instructions. So for the args, you should be able to go into python.testings.unittestArgs in your workspace settings.json and remove all those args and just add the args you need for Django (not required just if you want a verbosity level or anything). The -v is a carry-over from unittest args but since they share the same setting for both we will have to update the default there. Thanks!

@swebra
Copy link

swebra commented Aug 16, 2024

Ah of course. Test execution now works as expected in the generated project!

The only thing else of note there is a rogue error without any message during test discovery, just before the Found X test(s) info log. Seem to happen both on manual discovery (shown) and automatic discovery, and I similarly see it in "real" (non-generated) projects:

024-08-16 14:52:42.652 [debug] Testing: Manually triggered test refresh
2024-08-16 14:52:42.652 [debug] Testing: Clearing all discovered tests
2024-08-16 14:52:42.652 [debug] Testing: Forcing test data refresh
2024-08-16 14:52:42.652 [debug] Testing: Refreshing all test data
2024-08-16 14:52:42.674 [debug] Python API env change detected /home/eric/django-test/.direnv/python-3.11.0rc1/bin/python update
2024-08-16 14:52:42.675 [info] Discover tests for workspace name: django-test - uri: /home/eric/django-test
2024-08-16 14:52:42.675 [info] Running discovery for unittest using the new test adapter.
2024-08-16 14:52:42.675 [debug] Starting Test Discovery named pipe
2024-08-16 14:52:42.675 [debug] Creating named pipe server on /run/user/1000/python-test-discovery-1334eef7af79d65a9496.sock
2024-08-16 14:52:42.676 [warning] could not find a pixi interpreter for the interpreter at /home/eric/django-test/.direnv/python-3.11.0rc1/bin/python
2024-08-16 14:52:42.683 [info] Discovering unittest tests for workspace /home/eric/django-test with arguments: /home/eric/.vscode-server/extensions/ms-python.python-2024.13.2024081501-linux-x64/python_files/unittestadapter/discovery.py,--udiscovery,-p,test_*.py

2024-08-16 14:52:42.684 [info] > ./.direnv/python-3.11.0rc1/bin/python ~/.vscode-server/extensions/ms-python.python-2024.13.2024081501-linux-x64/python_files/unittestadapter/discovery.py --udiscovery -p test_*.py
2024-08-16 14:52:42.684 [info] cwd: .
2024-08-16 14:52:42.740 [info] MANAGE_PY_PATH is set, running Django discovery with path to manage.py as: $./manage.py

2024-08-16 14:52:42.740 [info] Running Django tests with command: ['/home/eric/django-test/.direnv/python-3.11.0rc1/bin/python', './manage.py', 'test', '--testrunner=django_test_runner.CustomDiscoveryTestRunner', '-p', 'test_*.py']

2024-08-16 14:52:42.986 [debug] new client is connected to the socket, connectionCount:  1 /run/user/1000/python-test-discovery-1334eef7af79d65a9496.sock
2024-08-16 14:52:42.986 [debug] Test Discovery named pipe /run/user/1000/python-test-discovery-1334eef7af79d65a9496.sock connected
2024-08-16 14:52:42.988 [debug] Test Discovery named pipe /run/user/1000/python-test-discovery-1334eef7af79d65a9496.sock received data
2024-08-16 14:52:42.988 [debug] Testing: Resolving item /home/eric/django-test
2024-08-16 14:52:42.989 [debug] Test Discovery named pipe /run/user/1000/python-test-discovery-1334eef7af79d65a9496.sock received data
2024-08-16 14:52:42.989 [debug] client emitted close event, connectionCount:  0
2024-08-16 14:52:42.989 [debug] connection count is <= 0, closing the server:  /run/user/1000/python-test-discovery-1334eef7af79d65a9496.sock
2024-08-16 14:52:42.989 [debug] Test Discovery named pipe /run/user/1000/python-test-discovery-1334eef7af79d65a9496.sock closed
2024-08-16 14:52:42.989 [debug] Test Discovery named pipe /run/user/1000/python-test-discovery-1334eef7af79d65a9496.sock disposed
2024-08-16 14:52:43.074 [error] 

2024-08-16 14:52:43.074 [info] Found 1 test(s).


2024-08-16 14:52:43.086 [debug] deferredTill EOT resolved
2024-08-16 14:52:43.194 [debug] Testing: Resolving item /home/eric/django-test/mysite

@eleanorjboyd
Copy link
Member

hm yes I see that error- ill see if I can track it down. Does it change the outcome of the discovery or just appears in the logs?

@swebra
Copy link

swebra commented Aug 19, 2024

Just appears in the logs as far as I can tell.

@eleanorjboyd eleanorjboyd mentioned this issue Aug 21, 2024
3 tasks
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Sep 19, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.