Testing with TransactionTestCase uses real database - python

When I test using django.test.TransactionTestCase I have found that it uses the real database.
(django.test.TestCase works normally!)
I have confirmed this in my own project using the simple code:
class TestInventoryTransactions(TransactionTestCase):
def setUp(self):
print(Item.objects.all())
def test1(self):
pass
def test2(self):
pass
The output of this is
[...Bunch of items...]
[]
Showing that firstly that the real database is being used and not an empty test database.
Secondly, it removes everything from the database after the first test.
I really don't think this is the expected behaviour and don't see why it would be happening.

Using "manage.py test" does not have this problem. It only occurs when running the test file manually.

Related

Why is test case failing in Django when it returns True in Python intrepreter?

When I run this code in the Python interpreter, it returns True:
>>> from movies.models import Movie
>>> movie_list = Movie.objects.all()
>>> bool(movie_list)
True
When I run my test case, python3 manage.py test movies, it fails:
from django.test import TestCase
from .models import Movie
class QuestionMethodTests(TestCase):
def test_movie_list_empty(self):
movie_list = Movie.objects.all()
self.assertEqual(bool(movie_list), True)
What am I missing? Shouldn't the test pass?
I see. Does that mean the test cases only test the code but can't use
any of the actual database content in its tests?
By default no, and you don't want to mess with the actual DB anyway,
there is a usual way to provide the initial objects for the tests (the actual source can differ, e.g. loading from a file)
from django.test import TestCase
from .models import Movie
class QuestionMethodTests(TestCase):
def setUp(self):
# You can create your movie objects here
Movie.objects.create(title='Forest Gump', ...)
def test_movie_list_empty(self):
movie_list = Movie.objects.all()
self.assertEqual(bool(movie_list), True)
The TestCase class also contains a setUpTestData method if you fancy that, https://docs.djangoproject.com/en/1.8/topics/testing/tools/#django.test.TestCase.setUpTestData
PS: test_movie_list_empty name sounds weird, cause it seems to test that the movie list is NOT empty
Because in tests you are using a temporary database which doesn't have the objects:
Tests that require a database (namely, model tests) will not use your
“real” (production) database. Separate, blank databases are created
for the tests.
Regardless of whether the tests pass or fail, the test databases are
destroyed when all the tests have been executed.
It's dangerous to use the real database for tests. Especially that tests should be reproducible, on other machines too. You should use fixtures for tests. Look at factory_boy.

Google App Engine python datastore stub storing references?

I am trying to do a simple test of a model. I insert and retrieve the model and check all that data I inserted with is present. I expect this test to fail with a simple, blank model, but it passes. Is this a quirk of the testing framework that I have to live with? Can I set an option to prevent it from keeping refs to python objects?
In the following, I expect it to fail at line 30, but it does not. It fails at the ref comparison as I insists the refs be different and they are not..
import unittest
from google.appengine.ext import ndb
from google.appengine.ext import testbed
class Action(ndb.Model): pass
class ActionTestCase(unittest.TestCase):
def setUp(self):
# First, create an instance of the Testbed class.
self.testbed = testbed.Testbed()
# Then activate the testbed, which prepares the service stubs for use.
self.testbed.activate()
self.testbed.init_datastore_v3_stub()
self.testbed.init_memcache_stub()
def tearDown(self):
self.testbed.deactivate()
def testFetchRedirectAttribute(self):
act = Action()
act.attr = 'test phrase'
act.put()
self.assertEquals(1, len(Action.query().fetch(2)))
fetched = Action.query().fetch(2)[0]
self.assertEquals(fetched.attr, act.attr)
self.assertTrue(act != fetched)
if __name__ == '__main__':
unittest.main()
Models are defined as being equal if all of their properties are equal. If you care about identity instead (you probably shouldn't...), then you can use assertIs in your test.
As it turns out, storing refs is the behavior of stubs. However, for TDD purposes, we do need to check if a property is defined in the model. The simple way to do so is to use keyword argument. If I write the test as follows, then it fails as expected.
def testFetchRedirectAttribute(self):
act = Action(attr='test phrase)
act.put()
The solved my immediate problem of having a failing that that I could code against.

How can I, inside a transaction, read an entity that I just wrote?

I am using Python2.7, GAE and High Replication datastore.
I am trying to perform a transaction that first writes an entity and then reads it but the reading never finds the entity. This is a testcase I have:
class DemoTestCase(unittest.TestCase):
def setUp(self):
self.testbed = testbed.Testbed()
self.testbed.activate()
self.policy = datastore_stub_util.PseudoRandomHRConsistencyPolicy(probability=0)
self.testbed.init_datastore_v3_stub(consistency_policy=self.policy)
def tearDown(self):
self.testbed.deactivate()
def test1(self):
db.run_in_transaction(self._write)
db.run_in_transaction(self._read)
def test2(self):
db.run_in_transaction(self._write_read)
def _write(self):
self.root_key = db.Key.from_path("A", "root")
a = A(a=1, parent=self.root_key)
self.a_key = a.put()
def _read(self):
b = sample.read_a(self.a_key)
self.assertEqual(1, b.a)
self.assertEqual(1, A.all().ancestor(self.root_key).count(5))
def _write_read(self):
root_key = db.Key.from_path("A", "root")
a = A(a=1, parent=root_key)
a_key = a.put()
b = sample.read_a(a_key)
self.assertEqual(None, b)
self.assertEqual(0, A.all().ancestor(root_key).count(5))
Both testcases are passing now.
Test1 is running a transaction which performs a write. Then it's running a second transaction that performs two reads, one by key and one by ancestor-query. Reads work just fine in this case.
Test2 is running exactly the same code as test1, but this time everything gets run inside the same transaction. As you can see, reading the entity by key returns None. Doing a ancestor query returns 0 hits.
My question is: how can I, inside a transaction, read an entity that I just wrote? Or is this not possible?
Thanks.
You can't. All datastore reads inside the transaction show a snapshot of the datastore when the transaction started. Writes don't show up.
Theoretically, you shouldn't have to read, since you will have an instance of every entity your write. Use that instance.
Well, sometimes it's really helpful to re-read. A business rule may be triggered by the entity update and will need to reload it. BRs often are not aware of what triggered them and won't have immediate access to the new entity.
Don't know for Python but, in Java using Objectify, updates are made visible while in the transaction by Objectify session (transaction) cache. If there's something like a session cache in the Python persistence framework you are using, that may be a solution.

Testing cherrypy with nose/fixture/webtest (amidoinitrite)

I am developing a CherryPy application and I want to write some automated tests for it. I chose to use nosetests for it. The application uses sqlalchemy as db backend so I need to use fixture package to provide fixed datasets. Also I want to do webtests. Here is how I set it all together:
I have a helper function init_model(test = False) in the file where all models are created. It connects to the production or test (if test == True or cherrypy.request.app.test == True) database and calls create_all
Then I have created a base class for tests like this:
class BaseTest(DataTestCase):
def __init__(self):
init_model(True)
application.test = True
self.app = TestApp(application)
self.fixture = SQLAlchemyFixture(env = models, engine = meta.engine, style = NamedDataStyle())
self.datasets = (
# all the datasets go here
)
And now I do my tests by creating child classes of BaseTest and calling self.app.some_method()
This is my first time doing tests in python and all this seems very complicated. I want to know if I am using the mentioned packages as their authors intended and if it's not overcomplicated.
That looks mostly like normal testing glue for a system of any size. In other words, it's not overly-complicated.
In fact, I'd suggest slightly more complexity in one respect: I think you're going to find setting up a new database in each child test class to be really slow. It's more common to at least set up all your tables once per run instead of once per class. Then, you either have each test method create all the data it needs for its own sake, and/or you run each test case in a transaction and roll it all back in a finally: block.

Problems using User model in django unit tests

I have the following django test case that is giving me errors:
class MyTesting(unittest.TestCase):
def setUp(self):
self.u1 = User.objects.create(username='user1')
self.up1 = UserProfile.objects.create(user=self.u1)
def testA(self):
...
def testB(self):
...
When I run my tests, testA will pass sucessfully but before testB starts, I get the following error:
IntegrityError: column username is not unique
It's clear that it is trying to create self.u1 before each test case and finding that it already exists in the Database. How do I get it to properly clean up after each test case so that subsequent cases run correctly?
setUp and tearDown methods on Unittests are called before and after each test case. Define tearDown method which deletes the created user.
class MyTesting(unittest.TestCase):
def setUp(self):
self.u1 = User.objects.create(username='user1')
self.up1 = UserProfile.objects.create(user=self.u1)
def testA(self):
...
def tearDown(self):
self.up1.delete()
self.u1.delete()
I would also advise to create user profiles using post_save signal unless you really want to create user profile manually for each user.
Follow-up on delete comment:
From Django docs:
When Django deletes an object, it
emulates the behavior of the SQL
constraint ON DELETE CASCADE -- in
other words, any objects which had
foreign keys pointing at the object to
be deleted will be deleted along with
it.
In your case, user profile is pointing to user so you should delete the user first to delete the profile at the same time.
If you want django to automatically flush the test database after each test is run then you should extend django.test.TestCase, NOT django.utils.unittest.TestCase (as you are doing currently).
It's good practice to dump the database after each test so you can be extra-sure you're tests are consistent, but note that your tests will run slower with this additional overhead.
See the WARNING section in the "Writing Tests" Django Docs.
Precisely, setUp exists for the very purpose of running once before each test case.
The converse method, the one that runs once after each test case, is named tearDown: that's where you delete self.u1 etc (presumably by just calling self.u1.delete(), unless you have supplementary specialized clean-up requirements in addition to just deleting the object).

Categories

Resources