Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Developing (a.k.a. Testing) in Python - Part 2

DZone's Guide to

Developing (a.k.a. Testing) in Python - Part 2

· Web Dev Zone
Free Resource

Get deep insight into Node.js applications with real-time metrics, CPU profiling, and heap snapshots with N|Solid from NodeSource. Learn more.

In part one I talked about testing as Python’s version of compile-time checking. Fully testing a project is tricky business. This is true across languages; even advanced testing frameworks can only alleviate some problems. One particular pain point is testing components that strongly rely on databases. To run test code involving databases, we need scripts/functions that recreate our testing environment and put in basic data to get things running. Suppose we’re using MySQL and we want to start our database fresh for each test. We can run a fixtures script before each test that might look something like:

DROP DATABASE fiesta_dev;
CREATE DATABASE fiesta_dev;

CREATE TABLE `users` (^C
...wait what is the syntax again?
USE fiesta;
SHOW CREATE TABLE users;
CREATE ^C
USE fiesta_dev;
CREATE TABLE `users` (`id` INT PRIMARY KEY AUTO_INCREMENT,
                      `name` VARCHAR(64),
                      `password` CHAR(32),
                      `email_address` VARCHAR(128));

User.new_user('Daniel Gottlieb', 'some password hash', 'dan@corp.fiesta.cc')


And things are good. Until one day we realize that our user data model needs to support linking multiple email addresses. Oops. We add a new `email_addresses` table to our database. It has an index on `user_id` and on `email_address`. There’s a foreign key constraint on `user_id` to the `users` table. We now update our production code to work with a list of strings for email addresses instead of a single one. And we’re done. Except that now our tests don’t work. We have to add in a new “create table” to our script. We also have to update the `users` table in the test script. This leaves us with:

...
CREATE TABLE `users` (`id` INT PRIMARY KEY AUTO_INCREMENT,
                      `name` VARCHAR(64),
                      `password` CHAR(32));

CREATE TABLE `email_addresses` (`user_id` INT,
                                `email_address` VARCHAR(128),
                                INDEX (`email_address`),
                                CONSTRAINT FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)
                                  ON DELETE CASCADE);

user_obj = User.new_user('Daniel Gottlieb', 'some password hash', 'dan@corp.fiesta.cc')
user_obj.add_email_address('dgottlieb@corp.fiesta.cc')


Let’s look at our fixture script if we use MongoDB (and pymongo) instead:

conn = pymongo.Connection()
conn.drop_database("fiesta_dev")

user_obj = User.new_user('Daniel Gottlieb', 'some password hash', 'dan@corp.fiesta.cc')


Now let’s add support for lists of emails and see how our fixtures script changes:

conn = pymongo.Connection()
conn.drop_database("fiesta_dev")

user_obj = User.new_user('Daniel Gottlieb', 'some password hash', 'dan@corp.fiesta.cc')
user_obj.add_email_address('dgottlieb@corp.fiesta.cc')


Admittedly, there is a little bit of “magic” here; particularly with generating indexes. The way Fiesta is setup, important sections of code will redundantly call create_index on a table. If the index is already created, MongoDB ignores the statement. This is similar to how MongoDB will silently create a new collection when its first document is inserted. Combined with the ability to add any field to any document in a collection, the fixtures script only needs to be aware of the database enough to clear all the data before the tests run.

I hope this offers some insight into why I think cleaner test code can be written with MongoDB than with a relational database. Feel free to ask questions or offer up your own tips in the comments below!

Party On,

Dan

 

source: http://blog.fiesta.cc/post/11668794861/developing-a-k-a-testing-in-python-part-two

Node.js application metrics sent directly to any statsd-compliant system. Get N|Solid

Topics:

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}