Django mock message fails with module view - python

I am trying to make a test pass with a mocked function:
#mock.patch('apps.myapp.views.messages')
def test_message_get_called(self, messages):
# tests
assert messages.add_message.called
This tests pass perfectly by default, no problem here.
Because I have a long views.py file I try to refactor. Instead of having a single file, I create a folder named views, put my views.py inside as all.py and add the following __init__.py:
from __future__ import absolute_import
from .all import (
....
)
So I import all my views class into this file to have access to them. This make the application work without problem, so I'm guessing the tests should be fine.
But it turns out the test fails:
AttributeError: <module 'apps.myapp.views' from '.../views/__init__.pyc'>
does not have the attribute 'messages'
So I add messages in my list of import. And I get the following error:
MessageFailure: You cannot add messages without installing
django.contrib.messages.middleware.MessageMiddleware
I already found that using middleware during test may cause problem:
https://code.djangoproject.com/ticket/17971
Why don't my Django unittests know that MessageMiddleware is installed?
But my tests seems to pass without the module, and it fails with.
What can be the issue here ?

Related

How to skip imports that are not needed while unittesting python

Im trying to unittests methods in fileA.py. fileA.py contains imports to firebasehandler.py where Im setting a connection to firebase. The methods I'm trying to test have no relation or need at all with anything from firebasehandler.py, but when running the tests I don't want to go through the credentials checking phase. What can I do to skip that import when running the unittests?
I recommend taking a look at unittest mocking:
https://docs.python.org/3/library/unittest.mock.html
You could for example do this in your test code:
from unittest.mock import MagicMock
sys.modules['firebasehandler'] = MagicMock()
import fileA
This should prevent loading of the actual firebasehandler module AND you can see if the mocked version was accessed etc if you wish.
I guess you can mock the imported object or method from fileA.py in your UT.

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.

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.

Access part of module from pytest

I have an issue accessing part of imported module from the pytest.
Here is branch with code referenced below: https://github.com/asvc/snapshotr/tree/develop
In particular, when running this test, it works as expected for test_correct_installation() but test_script_name_checking() fails with AttributeError.
import main as ss
import os
class TestInit:
def test_correct_installation(self):
assert os.path.exists(ss.snapr_path)
assert os.path.isfile(ss.snapr_path + "/main/markup.py")
assert os.path.isfile(ss.snapr_path + "/main/scandir.py")
def test_script_name_checking(self):
assert ss.ssPanel.check_script('blah') is None # Here it fails
Link to the main which is being tested
What I'm trying to do is to "extract" isolated piece of code, run it with known data and compare result to some reference. Seems like extraction part doesn't work quite well, best practises for such cases would be greatly appreciated.
Traceback:
AttributeError: 'module' object has no attribute 'ssPanel'
I have tried a small hack in the test_init.py:
class dummy():
pass
nuke = dummy()
nuke.GUI = True
But it (obviously) doesn't work as nuke.GUI is being redefined in __init__.py upon every launch.
This is a quite complex situation. When you import main in test_init.py, it will import main/__init__.py and execute all the code. This will cause nuke being imported and also, if nuke.GUI is False, there will not be ssPanel, as you can see.
The problem is that, you can't fake a dummy nuke in the test script. It won't work. Because before the test is running, the real nuke was already imported.
My suggestion would be seperate ssPanel into another python file. Then in __init__.py we can do:
if nuke.GUI:
from sspanel import ssPanel
And in test scripts, we can also easily import it using:
from main.sspanel import ssPanel

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