jiaaro / django-badges

An easy to use django app that provides Foursquare/Stack Overflow style badges
GNU General Public License v3.0
44 stars 21 forks source link

Badge creation metaclasses don't play nicely with tests #6

Open alastair opened 9 years ago

alastair commented 9 years ago

I've been chasing down a problem with badges not being in my database when I run unit tests. It's related to the registered_badges dictionary.

The post_syncdb hook in listeners.py creates database objects based on MetaBadges and populates Badge._badge with a reference to the model. However, my transaction-wrapped unit tests truncate the database at the beginning and end of each test. Now the database is empty but the Badge believes it still has an object.

In the end, I've solved it by running this in my setUp method:

    from badges import listeners
    from badges.utils import registered_badges
    for badge in registered_badges.values():
        del badge._badge
    listeners.sync_badges_to_db()

My view is that a method like sync_badges_to_db should always create badges in the database, or maybe there should be a method to force this.

More generally the post_syncdb hook in listeners has been causing problems too - in fact, the django documentation for this hook explicitly says that it's not recommended to change the database in this hook: https://docs.djangoproject.com/en/1.7/ref/signals/#post-syncdb I understand that it's a useful way of making sure the database reflects the MetaBadges, but it feels like magic that is a little bit unexplained. I prefer the current system to when badges were created in __new__, but I would like it more if badge creation was explicit. Maybe now django 1.7's AppConfig.ready could be something to look at.

jiaaro commented 9 years ago

yeah...

I have this embarrassing helper function in the tests.py for some of my projects that use django-badges:

def generateBadges():
    from badges.utils import registered_badges
    for badge in registered_badges.values():
        delattr(badge, "_badge")
        badge.badge

I'll take a look at AppConfig.ready, thanks for the pointer

jiaaro commented 9 years ago

Actually, looking over it now, it has a scary disclaimer about doing queries in AppConfig.ready:

Warning

Although you can access model classes as described above, avoid interacting with the database in your ready() implementation. … For example, even though the test database configuration is separate from the production settings, manage.py test would still execute some queries against your production database!