Why when creating instance as a class attribute:
class ModelTestsProducts(TestCase):
# Create example objects in the database
product_category = models.Product_category.objects.create(
name='Spring'
)
product_segment = models.Product_segment.objects.create(
name='PS1',
product_category=self.product_category
)
product_group = models.Product_group.objects.create(
name='PG1',
product_segment=self.product_segment
)
def test_product_category(self):
self.assertEqual(str(self.product_category), self.product_category.name)
def test_product_segment(self):
self.assertEqual(str(self.product_segment), self.product_segment.name)
def test_product_group(self):
self.assertEqual(str(self.product_group), self.product_group.name)
I am getting following error when running test for the 2nd time?
django.db.utils.IntegrityError: duplicate key value violates unique constraint "products_product_category_name_key"
DETAIL: Key (name)=(dadsad) already exists.
When I use setUp method and then create objects insite this setUp method it works fine, but I cant understand why the above method somehow creates every object multiple times and thus fails the unique constraint set in the model.
Is it because django test suite somehow calls this class everytime every test function is run, thus every attribute is assigned multiple times?
But then if I move the object assignment outside the class (in the test file) then I also get this duplicate error, so that would mean whole test file is being called multiple times every time test is being run.
One more thing I use docker to run this Django app and and run django test from docker-compose command.
If you're using Django's TestCase, Django will run each test in a separate transaction, that will be rolled back after the test is finished, which means there will be no changes in your database and everything you'll try to run, will only exist inside your test. This is done to make sure your tests are not affecting each other.
setUp function is also executed inside this transaction and it's invoked before every test in your test class. But everything you run outside of that function, in your case in the class body, will not be wrapped in such transaction, so it won't be rolled back between your tests. If this code is reached twice (which may be done under the hood by the test runner), your code will try to create some data in the database that already exists and it will fail.
If you want to do some optimizations of how your tests are being executed, you may use setUpTestData, so your test data is initialized only once for all tests in a single test class. It'll be wrapped in an outer-shell transaction and will be rolled back after all tests from such test case are done.
Related
I have a a test case that uses setUp and looks like this:
from django.test import TestCase, Client, TransactionTestCase
...
class TestPancakeView(TestCase):
def setUp(self):
self.client = Client()
# The Year objects are empty (none here - expected)
print(Year.objects.all())
# When I run these Test by itself, these are empty (expected)
# When I run the whole file, this prints out a number of
# Pancake objects causing these tests to fail - these objects appear
# to be persisting from previous tests
print(Pancake.objects.all())
# This sets up my mock/test data
data_setup.basic_setup(self)
# This now prints out the expected years that data_setup creates
print(Year.objects.all())
# This prints all the objects that I should have
# But if the whole file is ran - it's printing objects
# That were created in other tests
print(Pancake.objects.all())
[...tests and such...]
data_setup.py is a file that just creates all the appropriate test-data for my tests when it needs them. I'm using Factory Boy for creating test data.
When I run TestPancakeView by itself - my tests pass as expected.
When I run my entire test_views.py file, my TestPancakeView tests fail.
If I change it to TransactionTestCase - it still fails when I run the whole file.
I'm creating the Pancake test data like this:
f.PancakeFactory.create_batch(
2,
flavor=blueberry,
intensity='high'
)
No other tests exhibit this behavior, they all act the same way when I run them individually or when I run them as part of the entire file.
So I found the reason for this was because my Pancake class was from a different application in the Django project (which was tied to a different DB table); because of that - when I was creating those objects initially - since they existed on a different test DB, they were persisting.
Solution:
Use the tearDown functionality for each test.
Each test now has the following:
def tearDown(self):
food.Pancake.objects.all().delete()
This ensures that my Pancake objects are removed after each test - so my tests against Pancake specifically pass regardless of being run on their own or with the rest of the file.
I don't understand how teardown in FactoryBoy + Django works.
I have a testcase like this:
class TestOptOutCountTestCase(TestCase):
multi_db = True
def setUp(self):
TestCase.setUp(self)
self.date = datetime.datetime.strptime('05Nov2014', '%d%b%Y')
OptoutFactory.create(p_id=1, cdate=self.date, email='inv1#test.de', optin=1)
def test_optouts2(self):
report = ReportOptOutsView()
result = report.get_optouts()
self.assertEqual(len(result), 1)
self.assertEqual(result[0][5], -1)
setUp is running once for all tests correct? Now if I had a second test and needed a clean state before running it, how do I achieve this? Thanks
If I understand you correctly you don't need tearDown in this case, as resetting the database between each test is the default behaviour for a TestCase.
See:
At the start of each test case, before setUp() is run, Django will flush the database, returning the database to the state it was in directly after migrate was called.
...
This flush/load procedure is repeated for each test in the test case, so you can be certain that the outcome of a test will not be affected by another test, or by the order of test execution.
Or do you mean to limit the creation of instances via the OutputFactory to certain tests?
Then you probably shouldn’t put the creation of instances into setUp.
Or you create two variants of your TestCase, one for all tests that rely on the factory and one for the ones that don't.
Regarding the uses of tearDown check this answer: Django when to use teardown method
In my daily unit test coding with Xcode, I only use XCTestCase. There are also these other classes that don't seem to get used much such as: XCTestSuite, XCTest, XCTestRun.
What are XCTestSuite, XCTest, XCTestRun for? When do you use them?
Also, XCTestCase header has a few methods such as:
defaultTestSuite
invokeTest
testCaseWithInvocation:
testCaseWithSelector:
How and when to use the above?
I am having trouble finding documentation on the above XCTest-classes and methods.
Well, this question is pretty good and I just wondering why this question is being ignored.
As the document saying:
XCTestCase is a concrete subclass of XCTest that should be the override point for
most developers creating tests for their projects. A test case subclass can have
multiple test methods and supports setup and tear down that executes for every test
method as well as class level setup and tear down.
On the other hand, this is what XCTestSuite defined:
A concrete subclass of XCTest, XCTestSuite is a collection of test cases. Alternatively, a test suite can extract the tests to be run automatically.
Well, with XCTestSuite, you can construct your own test suite for specific subset of test cases, instead of the default suite ( [XCTestCase defaultTestSuite] ), which as all test cases.
Actually, the default XCTestSuite is composed of every test case found in the runtime environment - all methods with no parameters, returning no value, and prefixed with ‘test’ in all subclasses of XCTestCase.
What about the XCTestRun class?
A test run collects information about the execution of a test. Failures in explicit
test assertions are classified as "expected", while failures from unrelated or
uncaught exceptions are classified as "unexpected".
With XCTestRun, you can record information likes startDate, totalDuration, failureCount etc when the test is starting, or somethings like hasSucceeded when done, and therefore you got the result of running a test. XCTestRun gives you controlability to focus what is happening or happened about the test.
Back to XCTestCase, you will notice that there are methods named testCaseWithInvocation: and testCaseWithSelector: if you read source code. And I recommend you to do for more digging.
How do they work together ?
I've found that there is an awesome explanation in Quick's QuickSpec source file.
XCTest automatically compiles a list of XCTestCase subclasses included
in the test target. It iterates over each class in that list, and creates
a new instance of that class for each test method. It then creates an
"invocation" to execute that test method. The invocation is an instance of
NSInvocation, which represents a single message send in Objective-C.
The invocation is set on the XCTestCase instance, and the test is run.
Some links:
http://modocache.io/probing-sentestingkit
https://github.com/Quick/Quick/blob/master/Sources/Quick/QuickSpec.swift
https://developer.apple.com/reference/xctest/xctest?language=objc
Launch your Xcode, and use cmd + shift + O to open the quickly open dialog, just type 'XCTest' and you will find some related files, such as XCTest.h, XCTestCase.h ... You need to go inside this file to check out the interfaces they offer.
There is a good website about XCTest: http://iosunittesting.com/xctest-assertions/
I have written test case for deletion of entity. In test case I simply pick first record by select query and pass its id to deletion method. Entity I want to delete can have some child entities restricting it from deletion. So I suppose I should create a entity first in my deletion test case and destroy same then so that I don't face issues of child dependency.
Is it good practice to write code for creation of entity before deletion. Its kind of testing creation method before deletion method.Please suggest
Edit:
I am working on Rail platform, so I have features like loading database with fixtures (not using currently, facing some error with same, see this https://stackoverflow.com/questions/5288142/rails-fixture-expects-table-name-to-be-prefixed-with-module-name-how-to-disable ). And yes I am using configuration to restore database state after test case run.
In unit-testing, you usually perform some sort of set-up before you run your tests.
Many testing frameworks support this sort of operation. Normally you don't do it through external queries though; for instance, you could directly create an object with certain properties, instead of performing an externally-exposed create query.
Because you directly create the object in the first place, you are not testing your creation query code (unless the way you internally create objects is flawed, but if you are concerned about that, you can test it too), and your deletion code is the only thing being tested.
In test case i simply pick first
record by select query
This is wrong. You should not execute queries during unit testing.
Test that I see can be:
Delete an existent;
Delete a non
existent Entity;
Delete a child;
Delete a non existent child;
If your unit testing framework allows test dependencies, i.e. run test X only if test Y passes and pass Y's return value as a parameter to X, you can get away with it. Here's how that would look in PHP:
function setUp() {
$this->dao = new UserDao(...);
}
function testCreate() {
$user = $this->dao->create('Bob');
assertThat($user, notNullValue());
// more assertions about the new user
return $user->getId();
}
/**
* #depends testCreate
*/
function testDelete($id) {
assertThat($this->dao->delete($id), is(true));
}
PHPUnit will skip testDelete() if testCreate() fails. This is a good work-around if you cannot setup a standard test data set before each test run.
Is it good practice to write code for creation of entity before deletion. Its kind of testing creation method before deletion method.Please suggest
Yes, it's good practice to create the entity whose deletion you are testing, so that the test does not depend on external state, and is repeatable independent of other tests.
This doesn't test creation, but uses creation in order to set up for testing deletion.
If you have multiple tests relying on the same data, the creation can be pulled out to a method that you call in each of your tests that needs that data. Most test frameworks also have a mechanism for specifying setup methods that are run before each test, and you could put the creation there if the data is needed for all tests in a test class.
In my tests I do not only test for the perfect case, but especially for edge cases and error conditions. So I wanted to ensure some uniqueness constraints work.
While my test and test fixtures are pretty complicated I was able to track the problem down to the following example, which does not use any custom models. To reproduce the behaviour just save the code into tests.py and run the django test runner.
from django.contrib.auth.models import User
from django.db import IntegrityError
from django.test import TransactionTestCase
class TransProblemTest(TransactionTestCase):
def test_uniqueness1(self):
User.objects.create_user(username='user1', email='user1#example.com', password='secret')
self.assertRaises(IntegrityError, lambda :
User.objects.create_user(username='user1', email='user1#example.com', password='secret'))
def test_uniqueness2(self):
User.objects.create_user(username='user1', email='user1#example.com', password='secret')
self.assertRaises(IntegrityError, lambda :
User.objects.create_user(username='user1', email='user1#example.com', password='secret'))
A test class with a single test method works, but fails with two identical method implementations.
The first test throwing exception breaks the Django testing environment and makes all the following tests fail.
I am using Django 1.1 with Ubuntu 10.04, Postgres 8.4 and psycopg2.
Does the problem still exist in Django 1.2?
Is it a known bug or am I missing something?
Django has two flavors of TestCase: "plain" TestCase and TransactionTestCase. The documentation has the following to say about the difference between the two of them:
TransactionTestCase and TestCase are identical except for the manner in which the database is reset to a known state and the ability for test code to test the effects of commit and rollback. A TransactionTestCase resets the database before the test runs by truncating all tables and reloading initial data. A TransactionTestCase may call commit and rollback and observe the effects of these calls on the database.
A TestCase, on the other hand, does not truncate tables and reload initial data at the beginning of a test. Instead, it encloses the test code in a database transaction that is rolled back at the end of the test.
You are using TransactionTestCase to execute these tests. Switch to plain TestCase and you will see the problem vanish provided you maintain the existing test code.
Why does this happen? TestCase executes test methods inside a transaction block. Which means that each test method in your test class will be run inside a separate transaction rather than the same transaction. When the assertion (or rather the lambda inside) raises an error it dies with the transaction. The next test method is executed in a new transaction and therefore you don't see the error you've been getting.
However if you were to add another identical assertion in the same test method you would see the error again:
class TransProblemTest(django.test.TestCase):
def test_uniqueness1(self):
User.objects.create_user(username='user1', email='user1#example.com', password='secret')
self.assertRaises(IntegrityError, lambda :
User.objects.create_user(username='user1', email='user1#example.com', password='secret'))
# Repeat the test condition.
self.assertRaises(IntegrityError, lambda :
User.objects.create_user(username='user1', email='user1#example.com', password='secret'))
This is triggered because the first assertion will create an error that causes the transaction to abort. The second cannot therefore execute. Since both assertions happen inside the same test method a new transaction has not been initiated unlike the previous case.
Hope this helps.
I'm assuming when you say "a single test method works", you mean that it fails, raises the exception, but doesn't break the testing environment.
That said, you are running with AutoCommit turned off. In that mode, everything on the shared database connection is a single transaction by default and failures require the transaction to be aborted via ROLLBACK before a new one can be started. I recommend turning AutoCommit on, if possible--unless you have a need for wrapping multiple write operations into a single unit, having it off is overkill.