Hi David,

On 11/11/2014 08:37 AM, dpalao.pyt...@gmail.com wrote:
> Dear Carl,
> 
> Thank you for the answer.
> 
> On Tuesday, November 11, 2014 3:13:18 PM UTC+1, Carl Meyer wrote:
> 
>     Hi David,
> 
>     On 11/11/2014 07:01 AM, dpalao...@gmail.com <javascript:> wrote:
>     > I see your point. You might be right, but it is not clear to me
>     how to
>     > do it and if it would work: I have already tried to subclass
>     > DiscoverRunner to modify its behaviour with little success.
> 
>     If there are specific aspects of "how to do it" that are confusing to
>     you, I could try to clarify. Or if you try it and have specific
>     problems.
> 
> 
> Well, I never worked with sql directly. And as I said in my post when I
> tried to subclass  DiscoverRunner I got the impression that it is not
> straightforward (at least for my limited experience with Django).
> 
>     > Another problem that I see: it is not an homogenous approach. I mean,
>     > the models are created from the production database. Now I create an
>     > independent database for testing. Of course, you will tell me that I
>     > have to follow the TDD approach to the end: for the code that creates
>     > the testing database too! And I would agree. But it is clearly a
>     bit too
>     > complicated.
> 
>     I'm afraid I am quite confused by this paragraph.
> 
>     I don't know what you mean by "not an homogenous approach".
> 
>     And I don't know what you mean by "the models are created from the
>     production database."
> 
>     And I don't know what you mean by "an independent database for
>     testing."
>     Django already creates a new database for each test run. I'm not
>     suggesting creating any additional database beyond that, just running
>     some SQL to create your legacy (un-managed) tables in the testing
>     database.
> 
>     The code that creates the testing database will be exercised at the
>     start of every test run, and if it's not working your tests will fail
>     because the legacy tables are not created. Personally, I'd consider
>     that
>     adequate; I wouldn't write any additional tests for that code.
> 
> 
>  I created the models by running "inspectdb". I see that as a (logical)
> link between the models and the tables. Perhaps not the standard link,
> but they are related. That is what I meant by "the models are created
> from the production database".

I see, that makes sense.

> Now your suggestion is to create some tables from scratch. By hand. This
> is what I mean by "not an homogeneous approach", because I don't see a
> logical link between the models and the testing database. The testing
> database is created by me. (Or by Django, then I take control to create
> the tables, then I return control to Django -- if this is what you suggest).

Sorry, I didn't fully explain this part of my suggestion. I would not
create the SQL for those tables "by hand" - I would do it via a dump of
the SQL schema from the actual production tables.

> But actually I think your solution makes a lot of sense. At the
> beginning I wanted Django to create the testing database along with the
> tables automatically. And you probably are right and the SQL code to
> create the tables is absolutely trivial, but for me it is not.
> So I tried also something slightly different. As the database already
> exists, I think it would make sense if I also the testing database
> exists prior to testing.
> What I just did was:
> I created the testing database simply with a command like
> 
> mysqldump -u user --password='xxx' -h localhost -d production_db | mysql
> -h localhost -u user --passwor='xxx' -Dtest_db

So this is close to my suggestion. But rather than creating the entire
DB (including managed models too), I would send the dump to a SQL file
instead:

    mysqldump -u user --password='xxx' -h localhost -d production_db >
schema.sql

And then edit schema.sql to remove any tables for normal managed models,
leaving only the table definitions for the unmanaged (legacy) tables.
(You might also add `--no-data`, depending whether you want your legacy
tables to also be prepopulated with data for your tests).

Then you can allow Django to create its test database normally, and run
migrations to create tables for your managed models; you just have to
additionally run `schema.sql` to add in the un-managed tables.

(It's possible that your approach of pre-creating the entire test DB
could just work, with no need to subclass DiscoverRunner at all, by
using the --keepdb option to manage.py test; but that option only exists
in the Django development version, so you probably don't have it.)

> Again, I must subclassing DiscoverRunner to have a chance to succeed
> (need to by-pass db creation), and actually Django complains if I don't
> do that.
> So, I subclassed the DiscoverRunner like this
> 
> class SkipDBCreationDiscoverRunner(DiscoverRunner):
>     def setup_databases(self, **kwargs):
>         return
> 
>     def teardown_databases(self, old_config, **kwargs):
>         pass

Rather than bypassing database setup and teardown entirely (which will
cause Django to just use the production database, as you noticed), I
would override only setup_databases, and still call the super method,
but just add code after it to run your SQL file and add the table
definitions for the legacy tables. Something more like this (untested):

from django.db import connection

class MyDiscoverRunner(DiscoverRunner):
    def setup_databases(self, *a, **kw):
        ret = super(MyDiscoverRunner, self).setup_databases(*a, **kw)
        cur = connection.cursor()
        cur.execute(open('schema.sql').read())
        return ret

> and enabled this new thing to run instead of the default in settings.py:
> 
> TEST_RUNNER="tests.nodb_runner.SkipDBCreationDiscoverRunner"
> 
> I created a "TEST" entry in the DATABASES dictionary with the proper db
> name:
>         DATABASES = {
>             'default': {
>                 'ENGINE': 'mysql.connector.django',
>                 'NAME': 'production_db',
>                 'USER': 'user',
>                 'PASSWORD': 'xxx',
>                 'HOST': 'localhost',
>                 'OPTIONS': {
>                     'autocommit': True,
>                     },
>                     },
>            
>             'TEST': {
>                 'ENGINE': 'mysql.connector.django',
>                 'NAME': 'test_db',
>                 'USER': 'user',
>                 'PASSWORD': 'xxx',
>                 'HOST': 'localhost',
>                 'OPTIONS': {
>                     'autocommit': True,
>                     },
>                     },
>         }

This is not the right format for configurating a test database. What
you've configured here is an ordinary non-test database that happens to
be named "TEST" - Django won't do anything special with that. To
configure a test version of a particular database, you use a 'TEST'
sub-key, like this (and you don't have to repeat any configuration that
is the same):

    DATABASES = {
        'default': {
            'ENGINE': 'mysql.connector.django',
            'NAME': 'production_db',
            'USER': 'user',
            'PASSWORD': 'xxx',
            'HOST': 'localhost',
            'OPTIONS': {
                'autocommit': True,
                },
            'TEST': {
                'NAME': 'test_db',
                },
            },
        }

> BUT, Django is using the production database! I don't know what I'm
> missing. Probably something stupid...
> 
> 
>     > I'm having serious doubts on how friendly Django-1.7 is with
>     respect to
>     > TDD...
> 
>     That seems an unfair conclusion, since your problems here mostly arise
>     from using legacy tables un-managed by Django. That's not the typical
>     situation for a Django project, and it's naturally one that will
>     require
>     some manual work on your part for the corresponding testing setup.
> 
>     Carl
> 
>  
> Sorry if that sounded rude or disrespectful. It was not my intention. I
> thought that using Django to work with existing databases was a common
> case. For me, up to now it has been a bit painful.

This raises the question of whether you really need to be using
un-managed models at all. The other option is to use normal managed
models, but just fake the initial (table-creating) migration for those
models on your production database. Then testing will just work normally.

Carl

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to