Conworld Codex 2018-05-31

By Max Woerner Chase

In this post:

As of last week, I should be able to construct ORM instances for test purposes. One thing I do when coming to grips with a new library, is to write tests for really obvious things to test my understanding of the library.

Currently, a lot of my design rests on the assumption that ORM instances obtained from different calls will compare equal if they refer to the same row, and generally be in synch with each other.

I've got a test that appears to demonstrate this well enough. I put the test in a "dependencies" testing subdirectory, and moved the fixtures from last week to the top level so the tests would have access to them. Here's how it looks in the test proper.

"""Tests of the understanding of SQLAlchemy."""


def test_create_session(db_session, models):
    """Make sure I understand how this stuff works."""
    test_event = models.Event(name='test')
    query_result, = db_session.query(models.Event).filter_by(name='test').all()
    assert test_event == query_result
    assert hash(test_event) == hash(query_result)

Having basic tests like this is helpful for debugging, because it gives me a baseline for saying "okay, that assumption I made about how this works, is probably true".

The way SQLAlchemy works is definitely intriguing, after working with Django for so long. Instead of save methods and query managers on the model classes, everything gets routed through the session object, which has a straightforward interface, so far. Feels less template-y.

If you're one of the approximately seven billion people who haven't used my coverage runner library and plugin [1], "Divide and Cover", you're probably wondering what the deal is with the global dictionary up there. The basic idea of Divide and Cover is that each test module, with a few exceptions, should test a single source module, and vice versa. As a consequence of this idea (in other words, if you don't agree with the premise, that's a sign you shouldn't use the library), I wish that the coverage from a given test module should only count toward the associated source module. Divide and Cover delivers on this idea using a custom coverage runner and a pytest plugin [2], to create and switch between multiple coverage objects. For various reasons, a test writer might want to add coverage of multiple modules (straightforward generated code, for instance), or disable source module discovery (as here, where the test is essentially just an experiment about the behavior of a third-party library). This is implemented using a dictionary with named keys, because I wanted to avoid requiring an import, since it's supposed to be possible to run the tests without installing Divide and Cover.

Next week, now that I understand the basics of writing SQLAlchemy code, I start writing tests in the UI coordination... layer... thing.

[1]I'm not blaming anyone. There's no documentation, and the implementation has some shortcomings that I haven't gotten around to remedying.
[2]There shouldn't be a dependency on pytest itself; any sufficiently expressive test runner plugin framework should work.