-
Notifications
You must be signed in to change notification settings - Fork 102
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Resetting DB sequences in Django #52
Comments
Same situation here. |
Would anyone like to create a PR to fix this? |
I'm unable to reproduce this. There is some potentially problematic subclassing going on in snapshottest.unittest and snapshottest.django, but I'm hesitant to change it without a reproducible problem. @jentyk and @thecylax I realize it's been a couple of years, but do you happen to remember any details about what versions of Python, Django, and snapshottest you were using back in late 2018? I've tried the test case below (by modifying the example django project) using Django 3.1, 2.2, and 1.11, with both the current snapshottest and v0.5.1 (though not in every combination), all on Python 3.7. from lists.models import List
from snapshottest.django import TestCase
class ListTest(TestCase):
def test_resets_db_1(self):
self.assertEqual(0, List.objects.count())
List.objects.create(name="test")
self.assertEqual(1, List.objects.count())
def test_resets_db_2(self):
# This is the same test as above. We don't know what order
# the tests will run, but if the DB isn't reset between them,
# at least one will fail.
self.assertEqual(0, List.objects.count())
List.objects.create(name="test")
self.assertEqual(1, List.objects.count()) Using mysql@5.7 via these settings:
|
Hmmm... your test seems not testing what it should test for. It seems testing if the DB if being torn down between tests, which it is. |
[Summary: If your tests need isolated auto-increment field sequences, Django requires you use TransactionTestCase with Thanks for the clarification @jentyk. I somehow hadn't made the connection that "DB sequences" was referring to auto-increment fields. Now I have a reproducible case. But it fails with both Django's own TestCase and snapshottest's augmented version: # This fails (with mysql) using *either* TestCase import
from lists.models import List
# from django.test import TestCase
from snapshottest.django import TestCase
class ListTest(TestCase):
def test_resets_auto_fields_1(self):
obj = List.objects.create(name="test")
self.assertEqual(obj.id, 1)
def test_resets_auto_fields_2(self):
# This is the same test as above. We don't know what order
# the tests will run, but if DB auto increment sequences
# aren't reset reset between them, at least one will fail.
obj = List.objects.create(name="test")
self.assertEqual(obj.id, 1) There are two things going on here:
# This works. (Also demonstrates snapshot test of serialized Django models.)
import snapshottest
from django.core.serializers import serialize
from django.test import TransactionTestCase
from lists.models import List
class ListTest(snapshottest.TestCase, TransactionTestCase):
reset_sequences = True # <-- critical for isolated ids on all DB engines
def test_resets_auto_fields_1(self):
obj = List.objects.create(name="test")
self.assertEqual(obj.id, 1)
self.assertMatchSnapshot(serialize('json', [obj]))
def test_resets_auto_fields_2(self):
obj = List.objects.create(name="test")
self.assertEqual(obj.id, 1)
self.assertMatchSnapshot(serialize('json', [obj])) (Note that's mixing in the base I think we should treat this as a feature request to expose a snapshottest-augmented TransactionTestCase. Given that it's likely to be used for snapshots, the snapshottest version should set |
I'm good with that 👍
Despite it being what most people would want, I think it is probably confusing to have a different behavior between our TransactionTestCase and Django's. I'd suggest we let users set We could also emit a warning in our TransactionTestCase when |
Very good idea.
True
Or just create another class with that variable True by default. @medmunds thanks for investigating 👍 |
So I guess I'd argue that However, having two different things called "TransactionTestCase" seems like it's just asking for confusion. (Or worse, three things called just "TestCase"—see #139.) Maybe snapshottest.django should instead expose Users who need something different could, of course, always mix |
To play devil's advocate here… The layers we have, on the surface, seem to provide convenience, but at they also obscure what's going on. Another way we could go is the opposite. Instead of adding more convenience layers, we could deprecate these convenience classes, and require all Django users to use a mixin. That way there's one obvious way of doing it, and it's explicit. Not totally sure the explicit way would be better, however I really don't like having ~8 classes which all have slightly different class hierarchies and behaviors and names which are very similar or identical to each other. It seems like a recipe for confusion. |
Oh, that sounds like it would feel much cleaner. Let's take it for a test drive in the (edit: hypothetical future!) docs...
I like it! (I also updated the example to be a little more Djangotic.) |
I like it too.
|
It could, but then I think we'd want to export it from I'd probably also want to keep the word "Test" to distinguish from a "TestRunner" mixin. (We already have a TestRunnerMixin in django, and will have one soon in unittest.) So: |
Although, aren't mixins basically a pattern for To be honest I'd rather have a flatter import structure than a nested one; if it's possible that all the things developers need can live in one namespace, it's simpler to talk about them.
Hmm, yes, this is a good point! |
I do not agree, I think this is absolutely fine. We have to take the whole namespace under consideration and then obviously it differs. "django.test.TestCase" differs from "snapshottest.django.TestCase" even if the last part of the name is the same. There is no point of inventing weird and cryptic names just to make them differ from names of dozens of other classes which have the same name but sits in different packages and have different functionality. Actually the name is very appropriate "TestCase". One is Django test case the other is snapshot tests Django test case. The same way as a dog has a paw and a cat has a paw, but dog.paw differs from cat.paw . |
That's an excellent point. I retract some of my earlier suggestions.
I see the attraction, but it might be tricky to make all the things developers need fit in one namespace. The snapshottest package currently supports either two or four testing frameworks (depending on how you count): pytest, unittest, and the django and nose derivatives of unittest. And it currently spreads its public API across a variety of namespaces, including the module root, framework-specific submodules, and other submodules. See list below. At a minimum, it seems hard to avoid naming conflicts between the django and unittest submodules if everything developers need is re-exported at the module root. E.g., we'd end up with
Good question; I don't know the answer. Mixins are a pattern for any class based code. Unittest is always class based. And I thought pytest was generally not used with class based tests, but then I saw in #53 a lot of people seem to be mixing the two. FYI, here's a list of current and likely-near-future snapshottest public or semi-public APIs, showing the namespace where they're exposed:
|
Also, no matter what we decide about namespaces, I do think we should expose something called For whatever reason, a lot of developers seem to think in terms of, "I want something like my custom unittest case, but also with snapshottest capabilities mixed in": from snapshottest import SnapshotTestMixin
from .my_test_utils import CustomTestCase
class MyTests(SnapshotTestMixin, CustomTestCase): ... rather than "I want something that behaves like both a snapshottest TestCase and my custom unittest case": import snapshottest
from .my_test_utils import CustomTestCase
class MyTests(snapshottest.TestCase, CustomTestCase): ... (even though it's the exact same multiple inheritance, and If we go with per-framework namespaces, I'd (re-)export |
To be honest, I don't think this is bad. I think not having to rely on the namespace makes it easier to talk about these classes, both in discussions and in documentation, and easier to verify that code is using the correct one. Also, imagine you've got a bunch of test modules using If separate namespaces are desired, a possible compromise might be to keep the classes unique. e.g. Really hoping we can find something that seems to work well all around. Agreed about adding
I'm in two minds about putting the same thing in multiple namespaces. It's confusing because some of the same-named things are the same (like SnapshotTestMixin), and others are different (like TestCase). Maybe best to sort out the larger question of namespace philosophy first, and then circle back to this one. |
Wow, I've never seen tests like that before! I still am not super concerned about calling it |
Currently, AFAIK snapshottest.django.TestCase does not reset DB sequences between tests which django.test.TestCase does. It leads to the situation when snapshots differ depends on the order of test execution, i. e. IDs are different.
The text was updated successfully, but these errors were encountered: