Reputation: 527
I want to be able to run and debug unit tests for a Django project from within Visual Studio Code. I am an experienced developer, but fairly new to both Django and Visual Studio Code.
The crux of the problem is that either the tests are undiscoverable within Visual Studio Code, or if they are discoverable, I get a ConnectionHandler exception when I run them. I provide details for both of these situations below.
I apologize for the length of this question, but I thought I should list the many solutions to the problem that I have tried unsuccessfully. I also think that it might be useful to put all of them into one place, rather than have them scattered all over StackOverflow and the rest of the Internet.
Best Solution So Far
The best solution I have found is at Problem with Django app unit tests under Visual Studio Code . It involves putting these four lines into an __init__.py file:
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "my_app_project.settings")
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
This works in my simple tutorial projects, described below, but in a real application some of the tests fail. It looks as though either Django isn't running the database models in isolation from the other tests, or that the tests' tearDown( ) method isn't being called. Also, it's not clear which __init__.py file to put these lines in. Finally, this solution causes unit tests to fail when run from the command line.
Other Solutions Tried
The StackOverflow question at How to fix "TypeError: argument of type 'ConnectionHandler' is not iterable" when running a django test? seems to be similar to the ConnectionHandler aspect of my problem, but no one has proposed a solution there.
I've found a Visual Studio Code extension that is supposed to resolve these problems: Django Test Runner (https://marketplace.visualstudio.com/items?itemName=Pachwenko.django-test-runner). It currently has an issue at https://github.com/Pachwenko/VSCode-Django-Test-Runner/issues/5 which describes the problem I'm having with the extension.
This blog says you can run Django unit tests in VSC with pytest: https://technowhisp.com/django-unit-testing-in-vscode/ . But even after carefully following his steps, I can't get pytest to discover the unit tests within Visual Studio Code.
The StackOverflow question at Django Unit Testing in Visual Studio 2017 or 2019: has no answer. The code the questioner presents as a partial solution is ugly and bloated. The question is tagged as a possible duplicate of Django Unit Testing in Visual Studio 2017 or 2019: , but that question has no answer either. Other questions on StackOverflow aren't related to Django or even Python.
My Setup
The rest of this question describes my environment and the exact nature of the problems I am having. I am working with an existing application but have managed to reproduce the problem on two tutorial projects--the one provided by the Django team in their "Writing your first Django app" online tutorial at https://docs.djangoproject.com/en/3.0/intro/ , and a second tutorial offered by the Visual Studio Code team at https://code.visualstudio.com/docs/python/tutorial-django . Structurally, the difference between the two projects is that the second has the manage.py script in the same directory as the project root, while the first project has the script one directory below the project root.
I am able to run the tests from the command line with no problem. I want to be able to run them from within Visual Studio Code because, sometimes, I want to run them through the debugger.
I am using python 3.7, Django 3.0.3, Visual Studio Code 1.42.1, Windows 10, the Windows Subsystem for Linux and the unittest framework.
As for my project, I will describe the setup for the first tutorial, since that is most similar to the way my real project is set up. The root directory is called mysite. Cleaned-up output from the tree
command gives this:
.
└── mysite
├── db.sqlite3
├── manage.py
├── mysite
│ ├── __init__.py
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── polls
├── __init__.py
├── admin.py
├── apps.py
├── migrations
├── models.py
├── mydate.py
├── tests.py
├── urls.py
└── views.py
Here is my VSC settings.json file:
{
"python.pythonPath": "venv/bin/python",
"python.testing.unittestArgs": [
"-v",
"-s",
// "/full/path/to/mysite",
"./mysite",
// "mysite",
"-p",
"test*.py"
],
"python.testing.pytestEnabled": false,
"python.testing.nosetestsEnabled": false,
"python.testing.unittestEnabled": true
}
The file shows two lines commented out after the "-s" argument. I get the same behavior no matter which of these three lines I use for the path.
ConnectionHandler Error within VSC
In Visual Studio Code, my polls/tests.py file looks like this:
As you can see, the "Run Test" and "Debug Test" buttons indicate the test is discoverable. With the unittest import, the test runs correctly within VSC, but with the django.test import I get a ConnectionHandler error with the following message stack:
======================================================================
ERROR: setUpClass (polls.tests.TestDjango)----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/jkurlandski/workspace/randd/djangoprojs/mysite/venv/lib/python3.7/site-packages/django/test/testcases.py", line 1123, in setUpClass super().setUpClass()
File "/home/jkurlandski/workspace/randd/djangoprojs/mysite/venv/lib/python3.7/site-packages/django/test/testcases.py", line 197, in setUpClass cls._add_databases_failures()
File "/home/jkurlandski/workspace/randd/djangoprojs/mysite/venv/lib/python3.7/site-packages/django/test/testcases.py", line 218, in _add_databases_failures cls.databases = cls._validate_databases() File "/home/jkurlandski/workspace/randd/djangoprojs/mysite/venv/lib/python3.7/site-packages/django/test/testcases.py", line 204, in _validate_databases if alias not in connections:
TypeError: argument of type 'ConnectionHandler' is not iterable
----------------------------------------------------------------------
Ran 0 tests in 0.001s
Import Problems within VSC
In mysite/mysite/polls/models.py I created the same Question and Choice models described in the Django tutorial referenced above. When I try to import them, however, the tests are no longer discoverable--the "Run" and "Debug" buttons disappear in VSC, and I get a message saying they are not discoverable.
from django.test import TestCase
# from unittest import TestCase
# not discoverable:
# from .models import Choice
# not discoverable:
# from polls.models import Choice
In VSC, the use of from polls.models import Choice
creates an "unresolved import 'polls.models' warning and causes the import statement to become underlined in yellow. The from .models import Choice
import does not cause the warning. Since the test is not discoverable I can't run it, or debug it, within VSC. (But note, as I've said, that from the command line the test runs correctly.)
As an experiment, I created the file mydate.py in polls, the same directory as models.py, containing a function called getNow( ). I can import this file into tests.py without losing test discoverability, but running the test causes the same ConnectionHandler error described above.
from django.test import TestCase
# from unittest import TestCase
# discoverable, but TypeError: argument of type 'ConnectionHandler' is not iterable:
from polls.mydate import getNow
# discoverable, but TypeError: argument of type 'ConnectionHandler' is not iterable:
# from .mydate import getNow
ConnectionHandler Error from Command Line
As I've said, I can run the unit tests from the command line with python manage.py test
. However, I can replicate the ConnectionHandler error by running python -m unittest
from the manage.py directory.
Thanks in advance for any help you guys can give me.
Upvotes: 16
Views: 4350
Reputation: 2259
You need to load the django configuration previous to run any test, for that reason the code in __init__.py
file.
If pytest
is an option for you, you have to install pytest
and pytest-django
pip install pytest pytest-django
create a pytest
configuration (ex: pytest.ini
) at the same level of manage.py
file with the following content.
[pytest]
DJANGO_SETTINGS_MODULE=mysite.settings
python_files=test*.py
The configuration DJANGO_SETTINGS_MODULE
is the import needed for the project setting (settings.py
file). By default, the file tests.py
is created for every app when you use python manage.py startapp app_name
, but this file doesn't match with the default pytest
file pattern, for that reason you have to add the python_files
options if you want to use the default file name.
Update the setting.json
configuration file with:
{
"python.pythonPath": "venv/bin/python",
"python.testing.pytestArgs": [
"mysite",
"-s",
"-vv"
],
"python.testing.pytestEnabled": true,
"python.testing.nosetestsEnabled": false,
"python.testing.unittestEnabled": false
}
About the error unresolved import 'polls.models'
, you need to configure the Python extension on VSCode creating a .env
file in the root of your project with PYTHONPATH=source_code_folder
(for more information VS Code Python Environment):
PYTHONPATH=mysite/
Finally, your project structure should be
. <-- vs code root
├── .env <-- file created with the PYTHONPATH entry
└── mysite
├── pytest.ini <-- pytest configuration
├── db.sqlite3
├── manage.py
├── mysite
│ ├── __init__.py
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── polls
├── __init__.py
├── admin.py
├── apps.py
├── migrations
├── models.py
├── mydate.py
├── tests.py
├── urls.py
└── views.py
Upvotes: 6