On 2/3/07, Allen Bierbaum <[EMAIL PROTECTED]> wrote: > > This works for creating the table structure, and that is important, > but for me I think the actual data in the database is just was > important if not more so. What are people using to populate the > database with test data to use in the tests?
if you feel adventurous, I've been working to implement SQLAlchemy in the fixture module : http://code.google.com/p/fixture/ It's not too difficult to run insert statements at the top of your tests, or inject an SQL file. But when you want to make assertions using that data things get tricky, which is why I created the fixture module. To give you a very rough example of how this works (since the docs are very lacking at the moment), you have 1) DataSet objects to define data and 2) a Fixture object that knows how to load that data. In fact, special for you--!--and because I've been meaning to do so, I just checked in this example, to illustrate the point (if formatting goes funny, it is here: http://fixture.googlecode.com/svn/trunk/fixture/examples/db/sqlalchemy_examples.py ). Before I get to it, I want to quickly address the point you made about having a gigabyte database but only needing a sample of it for testing. I actually find the simplest way to work with fixtures is to use existing data. So the module also includes a command line that can generate fixture code from a data source, given an object that knows how to select. I.E. $ fixture path.to.a.table.widgets --dsn=postgres://[EMAIL PROTECTED]/db --query="widget_id=2" will build fixture code (including all foreign key refs) by creating a select statement using the widgets table. This command isn't implemented fully and may be rough around the edges but it works for something like above. Now ... that example: SequencedSet Fixtures with SQLAlchemy and nose ---------------------------------------------- Create your tables:: >>> from sqlalchemy import * >>> from sqlalchemy.ext.sessioncontext import SessionContext >>> from sqlalchemy.ext.assignmapper import assign_mapper >>> meta = BoundMetaData("sqlite:///:memory:") >>> session_context = SessionContext( ... lambda: create_session(bind_to=meta.engine)) ... >>> affiliates = Table('affiliates', meta, ... Column('id', INT, primary_key=True), ... Column('name', String),) ... >>> class Affiliate(object): pass >>> m = assign_mapper(session_context, Affiliate, affiliates) >>> events = Table('events', meta, ... Column('id', INT, primary_key=True), ... Column('type', String), ... Column('affiliate_id', INT, ... ForeignKey('affiliates.id')),) ... >>> class Event(object): pass >>> m = assign_mapper(session_context, Event, events, properties = { ... 'affiliate': relation(Affiliate), }) Note that using mappers above is not necessary. The fixture module also supports interacting with mapper classes, however. Next you build the DataSet objects that you want to load, in this case they inherit from SequencedSet, an optional DataSet enhancement that simulates auto-incrementing IDs. The IDs values can be overridden for any row and the column name is configurable, but defaults to 'id':: >>> from fixture import SequencedSet >>> class affiliates_data(SequencedSet): ... class joe: ... name="Joe, The Affiliate" ... >>> class events_data(SequencedSet): ... class joes_click: ... affiliate_id = affiliates_data.joe.ref('id') ... type="click" ... class joes_submit(joes_click): ... type="submit" ... class joes_activation(joes_click): ... type="activation" ... Note how joes_submit inherits from joes_click. Inheritance is a natural way to share common column values (in this case, all events belong to the same affiliate). Next you need a module-level Fixture instance that knows how to load the above DataSet object(s). We are also going to tell it to derive SQLAlchemy table names by looking in the global scope and chopping off "_data" from the DataSet class name (there are other ways to do this more or less explicitly). We are going to pass it a session_context to create connections with, but again there are alternatives to this:: >>> from fixture.style import TrimmedNameStyle >>> from fixture import SQLAlchemyFixture >>> db = SQLAlchemyFixture( env=globals(), session_context=session_context, ... style=TrimmedNameStyle(suffix="_data")) ... Now we are ready to write a test that uses the fixtures. The following is just one way you could write a test function runnable by nose_ :: >>> def setup_data(): ... meta.create_all() ... >>> def teardown_data(): ... meta.drop_all() ... clear_mappers() ... # and do whatever else ... ... >>> @db.with_data(events_data, setup=setup_data, teardown=teardown_data) ... def test_event_something(data): ... joe = Affiliate.get(data.affiliates_data.joe.id) ... click = Event.get(data.events_data.joes_click.id) ... assert click.affiliate is joe ... assert click.type == data.events_data.joes_click.type ... The rest will be done for you automatically by nose_:: >>> import nose, unittest >>> result = unittest.TestResult() >>> case = nose.case.FunctionTestCase(test_event_something) >>> case(result) >>> result.testsRun 1 >>> result.errors [] >>> result.failures [] Here are some things to note. @db.with_data() takes an arbitrary number of DataSet classes as an argument and passes an instance of Fixture.Data to the test function. Because of the reference to affiliates_data, you don't have to specify that set since it will be discovered by reference. Also note that there are other ways to load data. Say, if you want to work with unittest.TestCase classes you could create the data instance you see above manually in a setUp() def, like data = db.data(events_data) .. _nose: http://somethingaboutorange.com/mrl/projects/nose/ --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~----------~----~----~----~------~----~------~--~---