Configure a django test with no migrations in pyCharm - django

I am new to both django and pycharm! I can run the tests in my code on terminal using:
python manage.py test Repo/tests/testUnit1.py --failfast -n
and it works! Recently, I tried to use pycharm (professional) to run and debug the tests. The problem is that when I specify the option --nomigrations it gives the following error:
Usage: /Applications/PyCharm.app/Contents/helpers/pycharm/django_test_manage.py test [options]
[path.to.modulename|path.to.modulename.TestCase|path.to.modulename.TestCase.test_method]...
Discover and run tests in the specified modules or the current directory.
/Applications/PyCharm.app/Contents/helpers/pycharm/django_test_manage.py: error: no such option: --nomigrations
I found similar question here but it suggests the same thing that I have already tried. Does this happen because the test unit and the code that I want to test are not in the same folder? How can I run a test in pycharm without migrations?

In case this saves someone else some time here is how to set it up (took me awhile to figure out the first couple steps)...
Select Edit configurations
Create a new Python configuration (not a Django tests configuration)
In Script put manage.py
In Script parameters put test --nomigrations <optional test labels>
Optionally may need to specify a Working directory, depending on how PyCharm is started
As always, make sure your Environment variables, Python interpreter and Interpreter options are set to your project
This is on PyCharm 2016.2.3 and Django 1.8.9 with django-test-without-migrations installed

I figured out my mistake. I edited Python Run/Debug configuration and passed manage.py to Script. Also, I pasted the path that I used to use on command terminal (plus --failfast -n at the end) in Script parameters and it starts working!

Rather than use the configuration menu, I just edit the source.
You'll see when running tests that PyCharm that it uses its work test runner, something like
/Applications/PyCharm.app/Contents/helpers/pycharm/django_test_manage.py
Opening it up, I add the functional part that's taken from django-test-without-migrations
# added this class
class DisableMigrations(object):
def __contains__(self, item):
return True
def __getitem__(self, item):
return "notmigrations"
# ... right before this built-in
class PycharmTestCommand(Command):
def get_runner(self):
TEST_RUNNER = 'django_test_runner.run_tests'
test_path = TEST_RUNNER.split('.')
#....
Then, inside of the PycharmTestCommand.handle() method:
def handle(self, *test_labels, **options):
# Add this line
settings.MIGRATION_MODULES = DisableMigrations()
# That's it!
# ....
Now it works on all your projects, whether or not they have that lib installed. I still install the lib in case I need to run tests outside of PyCharm.

Related

What Django TEST_RUNNER supports xunit xml and logging capture?

I'm attempting to set up a new django project, and I've configured TEST_RUNNER in settings.py to be django_nose.NoseTestSuiteRunner.
I chose this test runner because it seems to be the only one I can find that has the following features:
writes xunit xml test report
captures logging/stdout and only displays for failed tests.
However I've heard that nose is unmaintained and I'm having a hard time finding a suitable replacement. The standard test runner doesn't capture logging nor writes xunit as far as I'm able to tell (would love to be proven wrong!)
I run tests like so:
python -m coverage run manage.py test --noinput
python -m coverage report --include="app/*" --show-missing --fail-under=100
python -m coverage xml --include="app/*" -o ./reports/coverage.xml
With this in settings.py:
TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'
And this setup.cfg:
[nosetests]
verbosity=0
with-xunit=1
xunit-file=./reports/xunit.xml
logging-clear-handlers=1
The last two lines are the real juicy bits I can't seem to find in other test runners. nose captures the logging and clears other logging handlers (eg, the handler that dumps on stdout) so the test runs output is much cleaner (you only see logging for tests that failed).
In other non-django projects I typically use nose2 but django-nose2 project appears to be 6 years old and lacking python3 support??
Please let me know which test runner is the "recommended" one (eg, most popular) with django support, thanks.
I have had success with unittest-xml-reporting:
TEST_RUNNER = 'xmlrunner.extra.djangotestrunner.XMLTestRunner'
https://github.com/xmlrunner/unittest-xml-reporting#django-support
The output directory can be configured with the TEST_OUTPUT_DIR setting.
You may still use nose runner:
INSTALLED_APPS += ['django_nose']
TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'
NOSE_ARGS = [
'--with-xunit',
'--xunit-file=nosetests.xml',
'--with-coverage',
'--cover-erase',
'--cover-xml',
'--cover-xml-file=nosecover.xml',
]
So pytest produces some very nice test output. I've unset TEST_RUNNER in settings.py and changed my test script to:
python -m coverage run -m pytest --junitxml=./reports/junit.xml
python -m coverage report --include="app/*" --show-missing --fail-under=100
python -m coverage xml --include="app/*" -o ./reports/coverage.xml
This works, and captures ALL logging output (nose was a little buggy and let one or two logging statements slip through, very strange behavior).
The only thing is that I'm a django novice so I don't know if there are any bad side-effects of not using manage.py test for testing django. Any guidance is appreciated, thanks!

how to debug twisted trial unittest in pycharm

I am new to twisted and I have a twisted unit test in python, and I want to debug in pycharm with trial.
I can run the tests in command line fine (for e.g. like :~ nathan$ trial smoke_tests ) but would like to step through the test in an IDE
in another question
How debuging twisted application in PyCharm
It has been suggested that "configure the "Script" setting to point to that twistd" . so for 'trial' I tried pointing to /Library/Python/2.7/site-packages/twisted/trial/runner.py , but that fails.
Script
Assuming your working directory is /home/myself/mypythonproject/myworkingdirectory ,
Create a python file in your working directory with name trial_try.py. This is a copy of /usr/local/bin/trial. So use a copy of the version you have.
import os, sys
try:
import _preamble
except ImportError:
try:
sys.exc_clear()
except AttributeError:
# exc_clear() (and the requirement for it) has been removed from Py3
pass
# begin chdir armor
sys.path[:] = map(os.path.abspath, sys.path)
# end chdir armor
sys.path.insert(0, os.path.abspath(os.getcwd()))
from twisted.scripts.trial import run
run()
Configuration
Create a new Run Configuration in Pycharm.
for Script Enter
/home/myself/mypythonproject/myworkingdirectory/trial_try.py
for Parameters Enter you Parameters that you would use when running trial on the command line
for e.g. test_smoke
for Working directory Enter
/home/myself/mypythonproject/myworkingdirectory
You should be all Set !

How to use pdb.set_trace() in a Django unittest?

I want to debug a Django TestCase just like I would any other Python code: Simply call pdb.set_trace() and then drop into an interactive session. When I do that, I don't see anything, as the tests are run in a different process. I'm using django-discover-runner, but my guess is that this applies to the default Django test runner.
The question:
Is it possible to drop into a pdb session while using django-discover-runner a) on every error / fail, AND/OR b) only when I call pdb.set_trace() in my test code?
Some research:
This answer explains that Django creates another process, and suggests using a call to rpdb2 debugger, a part of winpdb, but I don't want to use winpdb, I'd rather use ipdb.
This answer solves the problem for django-nose by running the test command like this: ./manage.py test -- -s, but that option's not available for django-discover-runner.
This answer shows that I can do this with ipython:
In [9]: %pdb
Automatic pdb calling has been turned ON
That seems like a potential option, but it seems a bit cumbersome to fire up ipython every time I run tests.
Finally, this answer shows that nose comes with a --pdb flag that drops into pdb on errors, which is what I want. Is my only option to switch to the django-nose test runner?
I don't see any options for this in the built-in help for django-discover-runner:
$ python manage.py help test --settings=settings.test
Usage: manage.py test [options] [appname ...]
Runs the test suite for the specified applications, or the entire site if no apps are specified.
Options:
-v VERBOSITY, --verbosity=VERBOSITY
Verbosity level; 0=minimal output, 1=normal output,
2=verbose output, 3=very verbose output
--settings=SETTINGS The Python path to a settings module, e.g.
"myproject.settings.main". If this isn't provided, the
DJANGO_SETTINGS_MODULE environment variable will be
used.
--pythonpath=PYTHONPATH
A directory to add to the Python path, e.g.
"/home/djangoprojects/myproject".
--traceback Print traceback on exception
--noinput Tells Django to NOT prompt the user for input of any
kind.
--failfast Tells Django to stop running the test suite after
first failed test.
--testrunner=TESTRUNNER
Tells Django to use specified test runner class
instead of the one specified by the TEST_RUNNER
setting.
--liveserver=LIVESERVER
Overrides the default address where the live server
(used with LiveServerTestCase) is expected to run
from. The default value is localhost:8081.
-t TOP_LEVEL, --top-level-directory=TOP_LEVEL
Top level of project for unittest discovery.
-p PATTERN, --pattern=PATTERN
The test matching pattern. Defaults to test*.py.
--version show program's version number and exit
-h, --help show this help message and exit
Django does not run tests in a separate process; the linked answer claiming it does is simply wrong. (The closest is the LiveServerTestCase for Selenium tests, which starts up a separate thread to run the development server, but this is still not a separate process, and it doesn't prevent use of pdb). You should be able to insert import pdb; pdb.set_trace() anywhere in a test (or in the tested code) and get a usable pdb prompt. I've never had trouble with this, and I just verified it again in a fresh project with Django 1.5.1 and django-discover-runner 1.0. If this isn't working for you, it's due to something else in your project, not due to Django or django-discover-runner.
Nose captures all output by default, which breaks import pdb; pdb.set_trace(). The -s option turns off output capturing. This is not necessary with the stock Django test runner or django-discover-runner, since neither of them do output-capturing to begin with.
I don't know of any equivalent to nose's --pdb option if you're using django-discover-runner. There is a django-pdb project that provides this, but a quick perusal of its code suggests to me that it wouldn't play well with django-discover-runner; its code might give you some clues towards implementing this yourself, though.
FWIW, personally I use py.test with pytest-django rather than django-discover-runner or django-nose. And even though py.test provides a --pdb option like nose, I don't use it; I often want to break earlier than the actual point of error in order to step through execution prior to the error, so I usually just insert import pytest; pytest.set_trace() (importing set_trace from pytest does the equivalent of nose's -s option; it turns off py.test's output capturing before running pdb) where I want it in the code and then remove it when I'm done. I don't find this onerous; YMMV.
Try to use ipdb instead of pdb -
import ipdb;ipdb.set_trace()
or (works in case of nose test runner)
from nose.tools import set_trace;set_trace()

(Django) Create a management command that will override the default settings in BaseCommand

We always run our tests off of settings_test, like so: ./manage.py test someapp --settings=settings_test. The problem is that it's sometimes problematic to remember to add the option.
I'd like to introduce a common app that just has the management command test.py. Depending on it's placement in the INSTALLED_APPS setting, it will override the default. Inside the command itself, I'd like to change the default of the --settings option. How can I do that?
I am aware that I can create a local.py file that is similar to manage.py but with settings_test instead of settings. However, the point is to still run ./manage.py, but with having settings_test as default instead of constantly typing "--settings=settings_test" after ./manage.py test someapp
After several attempts, I found that manage.py sets the settings long enough before the actual management command gets called that it's basically impossible (as far as I can tell) to change them there.
Eventually I decided that, since it's seems to be OK to alter manage.py - there's your default settings file there, for instance - that would be a reasonable place to deal with this, so I implemented it there:
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myapp.settings")
argv = sys.argv
try:
if argv[1] == 'test' and not any([k.startswith('--settings') for k in argv]):
os.environ["DJANGO_SETTINGS_MODULE"] = "myapp.test_settings"
except IndexError:
pass
from django.core.management import execute_from_command_line
execute_from_command_line(argv)
This seems to work as expected and I don't see any major disadvantage or problem - happy to be corrected.
You can override default commands by implemeting them in your app (say: common_app).
Create a management.commands package in common_app.
And implement a test command in there:
# this is commonapp/management/commands/test.py
try:
from south.management.commands import test
except ImportError:
from django.core.management.commands import test
class Command(test.Command):
def handle(self, *args, **kwargs):
kwargs['settings'] = kwargs.get('settings', 'common_app.settings')
super(Command, self).handle(*args, **kwargs)
This will use the settings.py file in common_app if there's no '--settings=' flag in given. But you can change that string in "settings_test" and it will load the first settings_test.py it can find on your python path.
South does this command overriding too, so for completeness I added the south import. But if any of your other installed apps also override the test command... you get the idea.
Don't forget the empty __init__.py files to make 'management' and 'commands' packages.
RTFM for more info on Django custom management commands.
You can override a django command as #Chris Wesseling describe in his answer.
Note: if there are other apps that are extending the command, move your app above those apps in the INSTALLED_APPS list, i.e.
to override runserver command and you are using 'django.contrib.staticfiles', place your app before staticfiles app
to override test command and you are using a test app i.e. django_nose, the same, place your app before django_nose app

How do I preload imports into Django's manage.py shell command?

When I run manage.py shell on my Django project to take a peek at something there are common imports that I always want to run at the start of the shell (e.g. I always want to import my model files.) How can I have these run automatically everytime I run the shell command?
2nd related question, when I hit the up arrow I get the "^A" character instead of the previously run command in the manage.py shell (and in my regular python shell), how can I fix this so it loads the previous command like on the Linux/Unix command line?
For the first question, look at the manage.py shell_plus command provided by the django-extensions project. It will load all your model files on shell startup. The project has got a whole load of other useful tricks too, so it's definitely worth checking out.
For the second question, I can only guess that you need to install readline.
you can replicate what
python manage.py shell
does by just doing:
from django.core.management import setup_environ
from mysite import settings
setup_environ(settings)
and you will have the environment all set up for the rest of that script. There are some other ways to do this here too: http://www.b-list.org/weblog/2007/sep/22/standalone-django-scripts/
One single thing which can solve both of your problem is ipython. ipython stores the previous executions and it can give you completion as well.
Auto importing frequently used packages in python manage.py shell_plus
Example:
# local_settings
SHELL_PLUS_PRE_IMPORTS = (
('<app_name>.models', '*'),
('<app_name>.forms', '*'),
('<app_name>.views', '*'),
('django.core.urlresolvers', '*'),
('django.db', 'connection'),
('django.db', 'reset_queries'),
)
SHELL_PLUS_DONT_LOAD = ['<app_name>', '<app_name>']
Reference:
https://github.com/django-extensions/django-extensions/blob/master/docs/shell_plus.rst
Adding extra stuff to the django shell can be done using as a starting point the shell_plus command provided in the django-extesions app, and modifying it by adding whatever you want to make available to the 'imported_objects' dictionary.
Eg if you duplicate the shell_plus.py file and add these two lines at the end:
# .......
alist = range(1000)
imported_objects['alist'] = alist
code.interact(local=imported_objects) # <-- this is the original final line
When you run the shell using the new file the 'alist' reference will be available.
I put a longer example here: http://www.michelepasin.org/techblog/?p=1012