I have a situation where for some of the tests, I require to use different setup method than I have defined for all, And for this I though to use #with_setup decorator of nose.
However this doesn't seem to be working.
code:
import unittest
from nose.tools.nontrivial import with_setup
__author__ = 'gaurang_shah1'
class Demo(unittest.TestCase):
def setup_func(self):
print "setup_func"
def teardown_func(self):
print "teardown function"
def setUp(self):
print "setup"
#with_setup(setup_func, teardown_func)
def test_setup(self):
print "test setup"
I am expecting following output,
setup_func
test setup
teardown_func
However I am getting following output, is there anything wrong I am doing here.
setup
test setup
You are constructing a unittest subclass, and as such it will always use unittest.setUp and tearDown methods for the test. As described in the documentation:
Note that with_setup is useful only for test functions, not for test
methods or inside of TestCase subclasses.
If you want to use #with_setup, drop the class all together:
from nose.tools.nontrivial import with_setup
def setup_func():
print "setup_func"
def teardown_func():
print "teardown function"
#with_setup(setup_func, teardown_func)
def test_something():
print "test"
Or better yet, create another unittest class that does your custom setUp function.
Related
Using an edited version of the example from Django's own doc, lets say my code looks like this:
from django.test import TestCase
from myapp.models import Animal
class AnimalTestCase(TestCase):
def __init__(self, animal_family):
self.animal_family = animal_family
def setUp(self):
Animal.objects.create(name="lion", sound="roar", family=self.animal_family)
def test_animals_can_speak(self):
"""Animals that can speak are correctly identified"""
lion = Animal.objects.get(name="lion")
self.assertEqual(lion.speak(), 'The mammal lion says "roar"')
Basically, I want to pass in the animal_family parameter into my test, or something similar at least from my terminal. Something like this
python manage.py test myapp.tests.AnimalTestCase 'mammal'
Obviously, the above command does not work. I want to send the 'mammal' as the animal_family to the __init__ method in my test class.
Help would be greatly appreciated.
Whilst self-contained tests should be the best practice, if you really wanted to do this you could set an environment variable when you execute the test command.
For example:
import os
from django.test import TestCase
from myapp.models import Animal
class AnimalTestCase(TestCase):
def setUp(self):
# Retrieve the animal family from the environment variable
animal_family = os.environ['animal_family']
Animal.objects.create(name="lion", sound="roar", family=animal_family)
def test_animals_can_speak(self):
"""Animals that can speak are correctly identified"""
lion = Animal.objects.get(name="lion")
self.assertEqual(lion.speak(), 'The mammal lion says "roar"')
And then call the test command such as:
export animal_family=mammal;python manage.py test myapp.tests.AnimalTestCase
I need to unit test whether a method decorated by a Flask route() gets called or not.
I'd like to do this without modifying the original code under test, if possible, so mocking the method would suite my requirements perfectly.
Hence I am asking this specific question about how to mock a decorated request method (I want to stress this to try to avoid people wasting their time with less specific answers)...
Sample application jflask.py:
from flask import Flask
app = Flask(__name__)
app.config.from_object(__name__)
#app.route('/hello') # This method represents the code under test.
def hello(): # I want to assert that this method gets
return 'Hello, World' # called without modifying this code.
if __name__ == "__main__":
app.run()
In the unit test I'm using #patch() to mock the method so I can assert it was called, but the assertion fails. I.e. the mock method doesn't get called, when I expect it to.
Sample unit test test_hello.py:
import unittest
import jflask
from unittest.mock import patch
class jTest(unittest.TestCase):
def setUp(self):
#jflask.app.testing = True
self.app = jflask.app.test_client()
#patch('jflask.hello') # mock the hello() method
def test_hello(self, mock_method):
rv = self.app.get('/hello')
mock_method.assert_called() # this assertion fails
What am I doing wrong ?
Background
Some background information about the actual behaviour I'm trying to test
(since the above is just a condensed test case, and may not seem entirely sane by itself).
In the actual code I am unit testing, there is a before_request() handler
installed for the app. This gets called by Flask before each request is handled, and in
certain situations this handler has been designed to return a response value, which
causes Flask request processing to stop (in this application's case, this feature is used to centrally validate request parameters), so that the usual routed request handler will (deliberately) not get called.
My unit tests need to assert that request processing gets stopped
or continues, appropriately depending on the situation.
Hence, my test needs to mock the real request handler and assert whether
it was called or not.
This is a little hacky but you could inject a logger.
#app.route(...):
def hello(logger=None):
logger = logger or self.logger
logger.info(...)
return ...
def test_...(self):
logger = MagicMock()
self.app.get(logger)
self.assertTrue(logger.info.called)
from functools import wraps
import logging
from datetime import datetime
logging.basicConfig(filename=datetime.now().strftime('%d_%m_%Y.log'),level=logging.INFO)
def logger_required(f):
#wraps(f)
def decorated(*args, **kwargs):
logging.info(f.__name__ + ' was called')
return f(*args, **kwargs)
return decorated
#app.route('/hello')
#logger_required
def hello(): # I want to assert that this gets called
return 'Hello, World'
I have a problem when running the test methods on two different modules.
I have created suite function in a different module and defined it as a fixture.
On the two test classes, I have entered the created fixture, to use it as setup function just once.
For each test method, I have created setup and teardown methods.
When the test methods of the first module are run, the test from the other class (second module) is starting in the first class and then are run again in the second class. So the test methods in the second class are run twice, once from the first class in the first module and then from the second class in the second module.
I want to run the test methods once per class or module, and not to be run twice.
Can someone help me to get a solution?
PS: I use for the suite fixture the parameter scope='session' (tried with the module is the same)!
Example (conftest.py):
#pytest.fixture(scope="session")
def suite():
print "start application"
open_app()
Example (test.py):
def setup_method(self, method):
if method.__name__ == 'test_1':
pass
elif method.__name__ == 'test_2':
pass
else:
print "test method not found"
def teardown_method(self, method):
print "teardown methods"
def test_1(self):
pass
def test_2(self):
pass
def test_3(self):
pass
def setup_test_3(self, testcase):
print "this is only for the test methd: test_3"
def teardown_test_3(self):
print "cleanup state after running test method test_3"
You can pass the parameter to your setup and teardown functions and put the condition based on the class or method name or module name and act it accordingly.
for e.g:--
def setup_method(value):
if value.__name__ == '<name of method from the module1>':
pass
elif value.__name__ == '<name of method from the module2>':
pass
here's my view (simplified):
#login_required(login_url='/try_again')
def change_bar(request):
foo_id = request.POST['fid']
bar_id = request.POST['bid']
foo = models.Foo.objects.get(id=foo_id)
if foo.value > 42:
bar = models.Bar.objects.get(id=bar_id)
bar.value = foo.value
bar.save()
return other_view(request)
Now I'd like to check if this view works properly (in this simplified model, if Bar instance changes value when it should). How do I go about it?
I'm going to assume you mean automated testing rather than just checking that the post request seems to work. If you do mean the latter, just check by executing the request and checking the values of the relevant Foo and Bar in a shell or in the admin.
The best way to go about sending POST requests is using a Client. Assuming the name of the view is my_view:
from django.test import Client
from django.urls import reverse
c = Client()
c.post(reverse('my_view'), data={'fid':43, 'bid':20})
But you still need some initial data in the database, and you need to check if the changes you expected to be made got made. This is where you could use a TestCase:
from django.test import TestCase, Client
from django.urls import reverse
FooBarTestCase(TestCase):
def setUp(self):
# create some foo and bar data, using foo.objects.create etc
# this will be run in between each test - the database is rolled back in between tests
def test_bar_not_changed(self):
# write a post request which you expect not to change the value
# of a bar instance, then check that the values didn't change
self.assertEqual(bar.value, old_bar.value)
def test_bar_changes(self):
# write a post request which you expect to change the value of
# a bar instance, then assert that it changed as expected
self.assertEqual(foo.value, bar.value)
A library which I find useful for making setting up some data to execute the tests easier is FactoryBoy. It reduces the boilerplate when it comes to creating new instances of Foo or Bar for testing purposes. Another option is to write fixtures, but I find that less flexible if your models change.
I'd also recommend this book if you want to know more about testing in python. It's django-oriented, but the principles apply to other frameworks and contexts.
edit: added advice about factoryboy and link to book
you can try putting "print" statements in between the code and see if the correct value is saved. Also for update instead of querying with "get" and then saving it (bar.save()) you can use "filter" and "update" method.
#login_required(login_url='/try_again')
def change_bar(request):
foo_id = request.POST['fid']
bar_id = request.POST['bid']
foo = models.Foo.objects.get(id=foo_id)
if foo.value > 42:
models.Bar.objects.filter(id=bar_id).update(value=foo.value)
#bar.value = foo.value
#bar.save()
return other_view(request)
I am having a problem where my functional test is not isolating from the main database, there is data left over from the test. I ran python manage.py flush and the test works, but when I run the test again the data created by the test that should have been deleted is still there making my test fail. I am currently only using SQLite.
functional_test.py
from django.test import LiveServerTestCase
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
class NewUserTest(LiveServerTestCase):
def setUp(self):
self.browser = webdriver.Firefox()
self.browser.implicitly_wait(15)
def tearDown(self):
self.browser.quit()
def test_user(self):
#Some test
You forgot to indent your method definitions (the statements that begin with "def"). As a result, the Python interpreter thinks that you've defined a new class, called NewUserTest, that contains no attributes, and three top-level functions.
To solve the problem, simply indent the "def" statements by an appropriate amount (4 spaces is the standard convention amongst the Python community). It should look like this:
class NewUserTest(LiveServerTestCase):
def setUp(self):
self.browser = webdriver.Firefox()
self.browser.implicitly_wait(15)
def tearDown(self):
self.browser.quit()
...