Why are my App tests not being recognized by Django tests? [duplicate] - python

This question already has an answer here:
How to split Django app tests across several files
(1 answer)
Closed 9 years ago.
Background:
I have the following django project setup:
>TopLevel:
> - App1:
> * models.py
> * forms.py
> * views.py
> * __init__.py
> * Tests/
> * __init__.py
> * test_simple.py
Here is the code in test_simple.py:
from django.test import TestCase
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.assertEqual(1 + 1, 2)
Now, when I run:
> python manage.py test app1
I get the following output:
>Creating test database for alias 'default'...
>
>----------------------------------------------------------------------
>Ran 0 tests in 0.000s
>
>OK
>Destroying test database for alias 'default'...
But, if I instead use the following project structure:
>TopLevel:
> - App1:
> * models.py
> * forms.py
> * views.py
> * __init__.py
> * tests.py
Where tests.py has the following code:
from django.test import TestCase
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.assertEqual(1 + 1, 2)
Now, when I run:
> python manage.py test app1
I get:
>Creating test database for alias 'default'...
>.
>----------------------------------------------------------------------
>Ran 1 test in 0.002s
>
>OK
>Destroying test database for alias 'default'...
Question:
Why does Django not recognize my Tests directory && why won't any tests listed inside Tests/ be picked up by Django's unittest structure to run?

One option to have a good sleep and don't even think about test discovery is to use nose. It has a lot features, one of it is automatic tests discovery.
There is package called django_nose that will help you to integrate your django project with nose:
Features
All the goodness of nose in your Django tests, like...
...
Obviating the need to import all your tests into tests/__init__.py. This not only saves busy-work but also eliminates the possibility of accidentally shadowing test classes.
...
Hope that helps.

You will require to change your Tests to tests and import every test to tests/__init__.py up until django 1.5 AFAIK. Also there is a test runner which will work the way unittest2 discovery work. This functionality has been integrated into django1.6.

Have a look at: running tests in Django
Test discovery is based on the unittest module’s built-in test discovery. By default, this will discover tests in any file named “test*.py” under the current working directory.

Related

Python: basic project structure & import paths

For my Python 3 project, I have the following directory structure:
├── myapp
│   ├── compute
│   │   └── compute.py
│   └── mymain.py
├── setup.py
└── tests
└── compute
└── compute_test.py
My goal is to be able to run the code here in three ways:
Unit tests. I've randomly chosen pytest for these but whichever framework should be fine;
python myapp/mymain.py <arguments> for when I want to do a quick "manual test";
Something like pip install and/or a Docker image for a proper deployment.
Now, the first and third of these seem to be no problem, but I'm having trouble with the middle one.
Here are the contents of the files:
compute.py:
import math
class MyComputation:
# performs an extremely difficult and relevant computation
#staticmethod
def compute(i: int) -> float:
return math.sqrt(abs(i))
compute_test.py:
import pytest
from myapp.compute.compute import MyComputation
def test_computation_normal_case():
ins = [-4, 9, -36, 121]
outs = list(map(lambda i: MyComputation.compute(i), ins))
expected = [2.0, 3.0, 6.0, 11.0]
assert outs == expected
mymain.py:
import random
from myapp.compute.compute import MyComputation
class MyApp:
#staticmethod
def main():
print("Loading data...")
i = random.randint(1, 100000)
print("Input: {}".format(i))
print("Computing...")
f = MyComputation.compute(i)
print("Output: {}".format(f))
print("Done!")
if __name__ == "__main__":
MyApp.main()
When I run, say, pytest from the command line, it works fine: finds the test, runs it, test passes.
However, when I try to run the main class:
$ python myapp/mymain.py
Traceback (most recent call last):
File "myapp/mymain.py", line 8, in <module>
from myapp.compute.compute import MyComputation
ImportError: No module named myapp.compute.compute
It makes no difference whether I add __init__.py files inside the directories or not.
But if I add the following to mymain.py, it can then be run from the command line as expected:
import os
import sys
root_path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '../'))
sys.path.insert(0, root_path)
So, questions:
1) What is the correct, Pythonic, idiomatic way to do the main class? What I want is essentially "run this code here, in-place, as is". Where do I put my main class? Do I need to pip install my stuff locally first? Do I need to do the imports differently?
2) Surely the sys.path.insert() stuff cannot be the "official" way of accomplishing what I want to do here? There must be a less ridiculous way... right?
3) Why do the unit tests work just fine while the main class doesn't? Does the unit test framework do something similar to the sys.path.insert() stuff under the covers? Or is there a better way of handling the imports?

Django tests manage.py

To run my Django's tests, I was using the manage.py file.
But I decided to create my own file runtests.py.
As specified in the Django's doc, the manage.py file will execute all methods whose name is starting like "test" and whose class inherits TestCase !
My aim is to use this searching method to display all possible tests (not running them).
So do you know where I could get this "searching method" ?
Thank you !
What you're looking for is called "test discovery", and you don't need to do it manually.
If you want to write a standalone script that runs your tests, you can simply invoke Django's test runner manually from Python code after configuring. The process for this is:
# First you need settings.
# You can do this by setting DJANGO_SETTINGS_MODULE:
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'path.to.your.settings')
# Or you can do it manually:
SETTINGS_DICT = {
# Put all the settings you'll need in here...
}
from django.conf import settings
settings.configure(**SETTINGS_DICT)
import django
django.setup()
import sys
# Now you can run tests:
from django.test.utils import get_runner
TestRunner = get_runner(settings)
test_runner = TestRunner(verbosity=2, interactive=True)
failures = test_runner.run_tests(
['test_module_to_look_in']
)
sys.exit(bool(failures))

django testrunner not running my tests

I've got the following tests.py file:
from django.test import TestCase
from lxml import etree
import tempfile
import utils
class CreateSurveyFromCsvTextTests(TestCase):
def parsesSurveyPassedInAsCsvAndReturnsXmlRepresentation(self):
text = """"survey",,,,,
,"name","type","label","hint","required"
,"gps","geopoint","Record your current location",,"false"
,"start","start",,,
,"end","end",,,
"settings",
,"form_title"
,"New survey" """
xml = create_survey_from_csv_text(text)
lxml.fromstring(xml)
when I run my module with python manage.py test, the output is
Ran 0 tests in 0.000s
I know the runner is picking up the file because if I make an invalid import it throws an error.
Why is the test not being called?
The name of the test methods need to start with test_. This allows the class to have both test methods and helper methods that you may write as well.
Hence you should rename your method to test_parsesSurveyPassedInAsCsvAndReturnsXmlRepresentation (and perhaps shorten the name too).

Django and tests in docfiles

I'm having a small problem with my test suite with Django.
I'm working on a Python package that can run in both Django and Plone (http://pypi.python.org/pypi/jquery.pyproxy).
All the tests are written as doctests, either in the Python code or in separate docfiles (for example the README.txt).
I can have those tests running fine but Django just do not count them:
[vincent ~/buildouts/tests/django_pyproxy]> bin/django test pyproxy
...
Creating test database for alias 'default'...
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
But if I had some failing test, it will appear correctly:
[vincent ~/buildouts/tests/django_pyproxy]> bin/django test pyproxy
...
Failed example:
1+1
Expected nothing
Got:
2
**********************************************************************
1 items had failures:
1 of 44 in README.rst
***Test Failed*** 1 failures.
Creating test database for alias 'default'...
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
This is how my test suite is declared right now:
import os
import doctest
from unittest import TestSuite
from jquery.pyproxy import base, utils
OPTIONFLAGS = (doctest.ELLIPSIS |
doctest.NORMALIZE_WHITESPACE)
__test__ = {
'base': doctest.testmod(
m=base,
optionflags=OPTIONFLAGS),
'utils': doctest.testmod(
m=utils,
optionflags=OPTIONFLAGS),
'readme': doctest.testfile(
"../../../README.rst",
optionflags=OPTIONFLAGS),
'django': doctest.testfile(
"django.txt",
optionflags=OPTIONFLAGS),
}
I guess I'm doing something wrong when declaring the test suite but I don't have a clue what it is exactly.
Thanks for your help,
Vincent
I finally solved the problem with the suite() method:
import os
import doctest
from django.utils import unittest
from jquery.pyproxy import base, utils
OPTIONFLAGS = (doctest.ELLIPSIS |
doctest.NORMALIZE_WHITESPACE)
testmods = {'base': base,
'utils': utils}
testfiles = {'readme': '../../../README.rst',
'django': 'django.txt'}
def suite():
return unittest.TestSuite(
[doctest.DocTestSuite(mod, optionflags = OPTIONFLAGS)
for mod in testmods.values()] + \
[doctest.DocFileSuite(f, optionflags = OPTIONFLAGS)
for f in testfiles.values()])
Apparently the problem when calling doctest.testfile or doctest.testmod is that the tests are directly ran.
Using DocTestSuite/DocFileSuite builds the list and then the test runner runs them.

Django unit testing - Why can't I just run ./tests.py on myApp?

So I'm very familiar with manage.py test myapp. But I can't figure out how to make my tests.py work as an stand-alone executable. You may be wondering why I would want to do this.. Well I'm working (now) in Eclipse and I can't seem to figure out how to set up the tool to simply run this command. Regardless it would be very nice to simply wrap tests.py in a simple manner to just run that.
Here is what my tests.py looks like.
"""
This simply tests myapp
"""
import sys
import logging
from django.test import TestCase
from django.conf import settings
from django.test.utils import get_runner
class ModelTest(TestCase):
def test_model_test1(self):
"""
This is test 1
"""
self.failUnlessEqual(1 + 1, 2)
def test_model_test2(self):
"""
This is test 2
"""
self.failUnlessEqual(1 + 1, 2)
def test_model_test3(self):
"""
This is test 3
"""
self.failUnlessEqual(1 + 1, 2)
def run_tests():
test_runner = get_runner(settings)
failures = test_runner([], verbosity=9, interactive=False)
sys.exit(failures)
if __name__ == '__main__':
# Setup Logging
loglevel = logging.DEBUG
logging.basicConfig(format="%(levelname)-8s %(asctime)s %(name)s %(message)s",
datefmt='%m/%d/%y %H:%M:%S', stream=sys.stdout)
log = logging.getLogger("")
run_tests()
I think the solution is located on this line but I can't seem to figure out what the first argument needs to be in order for it to magically start working..
failures = test_runner([], verbosity=9, interactive=False)
Thanks for helping!!
**** Updates ****
What I am looking to do (Doh!) is to simply run "myApp" tests. The problem is that this works (and chmod is not the problem) but it wants to run the entire test suite. I don't want that. I just want to run the myApp test suite.
Thanks again!
You could create an "External Tool" configuration for your project, such as:
Location: ${project_loc}/src/${project_name}/manage.py
Working Directory: ${project_loc}/src/${project_name}/
Arguments: test ${string_prompt}
This will run manage.py test <whatever name you type in the string prompt>.
The values above assume that you created a pydev project in Eclipse and then housed your Django project in the pydev src directory. It also assumes that you have the project name for pydev be the same name of your Django project. It will use the currently selected project in the package explorer to determine project_loc and project_name.
a. this should be the first line at your code file (tests.py)
#!/usr/bin/env python
b. run $ chmod +x tests.py

Categories

Resources