Django Testing - ImportError: Start directory is not importable - python

I was trying to do a bit of testing on a pieace of code but I get the ImportError: Start directory is not importable. Below is my code. I would really appreciate if someone could help. I am using Python 2.7.5 and also pycharm.
This is the command I execute in virenv
manage.py test /project/tests.py
from django.test import TestCase
# Create your tests here.
from project.models import Projects
from signup.models import SignUp
class ProjectTestCase(TestCase):
def SetUp(self):
super(ProjectTestCase,self).SetUp()
self.john = SignUp.objects.get(email='john#john.com')
self.project = Projects.objects.get(pk=1)
def test_project_permission(self):
self.assertFalse(self.john.has_perm('delete',self.project))
self.assertTrue(self.john.has_perm('view',self.project))
self.assertTrue(self.john.has_perm('change',self.project))

You should verify that you have an __init__.py in your project directory (it can be an empty file)
You're not calling test correctly. Assuming you have an app known as project, the way to call the tests in that app is manage.py test project
[Edit for additional comment which is really getting into separate question territory]
I would suggest adding this to settings.py (at the bottom)
import sys
if 'test' in sys.argv:
DATABASES['default'] = {'ENGINE': 'django.db.backends.sqlite3'}
SOUTH_TESTS_MIGRATE = False
This:
A. Will use sqlite (sort of, I'm not sure if it's actually sqlite or an in-memory db that works like sqlite) ... I've noticed issues if I use postgres and am trying to have my permissions not be excessively liberal AND I've had a test abort)
B. Disables south migrations (so it will just start with a clean database built against whatever models are currently saying)

Related

PyCharm - no tests were found?

I've been getting na error in PyCharm and I can't figure out why I'm getting it:
No tests were found
This is what I have for my point_test.py:
import unittest
import sys
import os
sys.path.insert(0, os.path.abspath('..'))
from ..point import Point
class TestPoint(unittest.TestCase):
def setUp(self):
pass
def xyCheck(self,x,y):
point = Point(x,y)
self.assertEqual(x,point.x)
self.assertEqual(y,point.y)
and this point.py, what I'm trying to test:
import unittest
from .utils import check_coincident, shift_point
class Point(object):
def __init__(self,x,y,mark={}):
self.x = x
self.y = y
self.mark = mark
def patched_coincident(self,point2):
point1 = (self.x,self.y)
return check_coincident(point1,point2)
def patched_shift(self,x_shift,y_shift):
point = (self.x,self.y)
self.x,self,y = shift_point(point,x_shift,y_shift)
Is it something wrong with my run configuration? I looked at this SO post but I'm still utterly confused. My run configuration currently looks like this:
In order to recognize test functions, they must be named test_. In your case, rename xyCheck to test_xyCheck :)
I know it's more than a year since the question was asked, but I had the same issue and that post was the first result in search.
As I understood PyCharm (or Intellij Idea Python plugin) needs your test to meet the following criteria if you want it to be launched when you run all the tests in directory.
test functions should start with "test" (underscore is not necessary)
the file, containing the test should also start with "test". "Test" (with capital T doesn't work in my case
I'm using Intellij IDEA 2016.3.5 with Python plugin
If you want to run you tests with command line
python -m unittest
Then you should add __init__.py to test directory. Python still wants your test function names to start with "test", and you test file name to start with "test", but in case of files it doesn't care if the first "t" is capital or not. TestCase and test_case is equally fine.
One thing that can also cause this problem is if you have not selected the right testing framework in your settings:
settings > Python Integrated Tools > Testing > Default test runner
All my tests are in pytest, but it was set to unit test
Don't use dashes ("-") in your filename. These files were being ignored on my machine. renaming them from project-tests.py to project_tests.py solved the problem.
Another gotcha that has just bitten me.
I had a test file within my test package called test_queue.py which followed all of the above advice, however when I selected "Run UnitTests" in PyCharm the console reported no tests found.
The issue in my case was that I had a non-unit test file in the root of the project also called test_queue.py which had been used for some other purpose early on in the project and forgotten about.
Even though I was specifically selecting the test file in my tests folder, and the path was set to absolutely point at the unit test version of the file, it seems the file in the root of the project was being used.
So, one more thing to check, make sure there are no other files in your project with the same name.
Another issue you may want to check is if you see in the console output "## tests deselected by '-k XXXX'". This means you've added a Keyword to the Run/Debug Configuration, and Pycharm will only run tests whose name contains the keyword.
Adding another answer in the hopes that it helps someone down the road. I've been fighting this problem and just figured out the answer (I think). I originally deleted the standard Django file tests.py out of my application folder. I also created a subdirectory of my project called tests, which contains separate test scripts. In this situation, Pycharm failed to find the tests. I corrected this simply by creating an empty file called tests.py in my application folder.
So:
Make sure you have a file called tests.py in your application director (it can be an empty file)
It seems that a folder called tests, in your project, can contain separate test scripts and Pycharm seems to find and run these.
Here's a picture of the directory structure that's working for me:
I had this exception when running individual tests in a Django 1.8 project in PyCharm 2018.1. I could run all the tests together, but individual tests in one file crashed.
The exception was happening in unittest's loader.py
It was getting an ImportError trying to import test_admin_views.py, though the exception was hiding the details of that error.
To see the details of the ImportError, I opened a Python Console and ran:
import my_app.users.tests.test_admin_views
This gave me:
Traceback (most recent call last):
[...]
File "my_app/my_app/users/tests/model_factories.py", line 42, in <module>
from my_app.applications.tests.model_factories import ApplicationFactory
ImportError: cannot import name ApplicationFactory
I noticed that some of the other factories in that file are imported without using the full path, so I tried adding ApplicationFactory to the relative path import list:
from .model_factories import UserFactory, UserGroupFactory, ApplicationFactory
Which worked!
None of these helped me, but I was able to fix the issue by setting the working directory to the project directory.
I debugged this by first creating a new Django test configuration witj a target of one of the app names with tests.
That ran successfully. No idea why working directory should need to be specified.

Confusing broken imports with Python3 and Django

I finally made the jump from python2 to python3 (hooray). However, I'm now plagued with import errors that I cannot seem to sanely resolve.
I have the standard Django 1.8 layout like this:
foo_bar
| - foo_bar
| - settings.py
| - urls.py
| - app_one
| - app_two
| - manage.py
My problem comes in when I try to import something from another app. For instance, importing a model from app_one.models.py into app_two.views.py.
I receive server errors depending on what I do.
1. Absolute Import
# in app_two.views.py
from foo_bar.app_one.models import MyModel
This gives the error:
No module named foo_bar.app_one
If I toggle my project back to 2.7, this import of course works A-OK. Not to mention, PyCharm is able to resolve this path and do auto-complete. So.. it's very confusing.
2. Relative imports:
# in app_two.views.py
from ..app_one.models import MyModel
This gives the error:
attempted relative import beyond top-level package
Again, same thing, seems like it should work -- even PyCharm thinks it should work (and can again autocomplete from the path). However, whenever I run my server, it explodes when this view is loaded.
Kind of Resolving:
Now, I can get the imports to work, but in a way that seems to make zero sense. If I leave off the top level package and abandon the relative import notation, it will import without error.
# in app_two.views.py
from app_one.models import MyModel
But this makes even less sense to me than everything else! Why does this work??? This one, of course, breaks when I swap back to 2.x. Further, PyCharm (for what it's worth), shows this as an unresolvable import.
For importing for Foreign Key relationships in a model (in Django 1.8+), you do not need to import explicitly, but can use string quoted version:
# in app1, import Customer from app2
customer_fk = models.ForeignKey('app2.Customer')
Complete Example:
from django.db import models
# this app is 'cart'
class ShoppingCart(models.Model):
# Import Customer Plan from another app - account
plan = models.ForeignKey('account.CustomerPlan')
started = models.DateTimeField()
cart_id = models.BigIntegerField()

how to execute python script containing django functions

I have a python script test.py that imports make_password function from Django library. It does it like this:
from django.contrib.auth.hashers import make_password
.... a lot of other stuff
def init():
...
if __name__ == "__main__":
init()
So, I want to run it from the command line like:
python test.py
But this results in a whole list of error messages, which are all about importing Django module. If I comment out from django.contrib.auth.hashers import make_password, then everything is ok (except the fact that I can't use make_password function).
The error messages your are getting are most likely complaints that the settings module is not available.
Django initializes its runtime environment (via django.core.management.setup_environ()) when you import any of its core modules. The django ecosystem is not meant to function without a valid project environment.
You have at least two options:
1. Manually set django settings module
import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'yourapp.settings'
from django.contrib.auth.hashers import make_password
...
Note that this requires yourapp.settings to be available via sys.path, so it might be necessary to explicitly add the project path to sys.path (or PYTHON_PATH).
Other versions of basically the same thing are available.
2. Build a management command
This is explained in some detail in the documentation.
In principle, you need to provide a yourapp.management.mycommand module that contains a single Command class:
class Command(BaseCommand):
def handle(self, *args, **options):
# make_password()
The command can be run through django's manage.py.

Python: What's the right way to make modules visible to a TestRunner?

after watching a couple of presentations about django testing, I want to code my own TestRunner in order to skip django tests, and create better packages structures for my tests.
The problem is that we've changed the project structure and the test runner can't find the right path to do the tests discovery. This is how my project looks like:
project/
-src/
- project_name/
- apps/
- test/ # Not a good name, i know, will change it
- some_app/
- test_models.py
- manage.py
- development.db
Now, in order to test test_models.py I want to do this:
$ cd project/src/
$ python manage.py test some_app.test_models
The problem is that the test runner can't find that package (some_app) and module (test_models.py). It changes if I hardcode the name in the test runner, but i don't like to do it. Here's what I do to make it work.
test_labels = ["%s.%s" % ("project_name.test", l)
for l in test_labels
if not l.startswith("project_name.test")]
So, if you do
$ python manage.py test some_app.test_models
It will be rewritten to:
$ python manage.py test project_name.test.some_app.test_models
And that works fine.
I tried doing sys.path.append("(...)/project_name/test) but doesn't work neither.
This is the code of my TestRunner:
class DiscoveryDjangoTestSuiteRunner(DjangoTestSuiteRunner):
"""A test suite runner that uses unittest2 test discovery.
It's better than the default django test runner, becouse it
doesn't run Django tests and let you put your tests in different
packages, modules and classes.
To test everything in there:
$ ./manage.py test
To test a single package/module:
$ ./manage.py test package
$ ./manage.py test package.module
To test a single class:
$ ./manage.py test package.module.ClassName
"""
def build_suite(self, test_labels, extra_tests=None, **kwargs):
suite = None
discovery_root = settings.TEST_DISCOVERY_ROOT
if test_labels:
# This is where I append the path
suite = defaultTestLoader.loadTestsFromNames(test_labels)
# if single named module has no tests, do discovery within it
if not suite.countTestCases() and len(test_labels) == 1:
suite = None
discovery_root = import_module(test_labels[0]).__path__[0]
if suite is None:
suite = defaultTestLoader.discover(
discovery_root,
top_level_dir=settings.BASE_PATH,
)
if extra_tests:
for test in extra_tests:
suite.addTest(test)
return reorder_suite(suite, (TestCase,))
Your Python import hierarchy is rooted at project/src. Thus, the correct Python import path for your test_models module is project_name.test.some_app.test_models, so that's what I would expect to pass in as a test label.
But you don't like typing the project_name.test prefix every time you want to run a specific test module, since all your tests will be located there. That's fine: you're choosing to introduce some implicit non-obvious behavior in exchange for some convenience. You definitely should not add anything to sys.path in order to achieve this: the key to Python import sanity is having your import hierarchy for a given codebase rooted in one and exactly one place; overlapping sys.path entries will cause problems like doubled imports of the same module under different names.
Really all you want is a UI convenience, and it looks to me like the test-label-munging code you show is the obvious way to implement that convenience. You don't like having the project_name.test prefix hardcoded, but it's going to have to be hardcoded somewhere: there's no way the test runner is going to magically figure out that you want to prepend test labels with project_name.test. If you want your TestRunner to be more generic, you can pull it out into a setting like BASE_TEST_MODULE or some such and prepend the value of that setting to each test label.
Before you continue investing more time into your custom TestRunner, I would definitely recommend that you take a look at django-nose.
The custom test runner provided by django-nose implements nose's test runner which is extremely flexible and provides a lot of options for running your tests. It seamlessly overrides the default test management command and allows you to configure default test options in your project's settings module.
I'm really recommending it for several reasons:
The options for the test command are fully documented (take look at the output)
nose provides a lot of approaches for test discovery
Chances are your colleagues are already seasoned nose users
You didn't have to write the TestRunner class yourself

How do unit tests work in django-tagging, because I want mine to run like that?

Few times while browsing tests dir in various Django apps I stumbled across models.py and settings.py files (in django-tagging for example).
But there's no code to be found that syncs test models or applies custom test settings - but tests make use of them just as if django would auto-magically load them. However if I try to run django-tagging's tests: manage.py test tagging, it doesn't do even a single test.
This is exactly what I need right now to test my app, but don't really know how.
So, how does it work?
If you want to run the tests in django-tagging, you can try:
django-admin.py test --settings=tagging.tests.settings
Basically, it uses doctests which are in the tests.py file inside the tests package/directory. The tests use the settings file in that same directory (and specified in the command line to django-admin). For more information see the django documentation on writing doctests.
You mean, "How do I write unit tests in Django?" Check the documentation on testing.
When I've done it, I wrote unit tests in a test/ subdirectory. Make sure the directory has an empty __init__.py file. You may also need a models.py file. Add unit tests that derive from unittest.TestCase (in module unittest). Add the module 'xxxx.test' to your INSTALLED_APPS in settings.py (where 'xxxx' is the base name of your application).
Here's some sample code of mine to get you started:
#!/usr/bin/env python
# http://docs.djangoproject.com/en/dev/topics/testing/
from sys import stderr
import unittest
from django.test.client import Client
from expenses.etl.loader import load_all, load_init
class TestCase(unittest.TestCase):
def setUp(self):
print "setUp"
def testLoading(self):
print "Calling load_init()"
load_init()
print "Calling load_all()"
load_all()
print "Done"
if __name__ == '__main__':
unittest.main()
If you mean, "How do I get data loaded into my unit tests?", then use fixtures, described on the same documentation page.

Categories

Resources