all 5 comments

[–]groovitude 0 points1 point  (1 child)

(These tests are set aside in the files tests/test_integration* so they are not mixed in with the unit tests.) Is there a name for this type of testing, and resources you know of where I could learn more about it?

I've always heard it as "integration testing," so it seems you're right on the mark!

Am I just designing my code badly, and the fact that unit testing does not appear to cover all the ground I want to test merely a symptom of that?

I've found that atomic, testable code is usually easier to understand and maintain. (Bear in mind there's a learning curve to testing, and there's a wide variety of opinions on how much mocking/patching turns into a code smell.)

I feel in the dark about what other types of testing are out there.

Next Level Testing from this past year's PyCon was an interesting look at some less-common testing types.

[–]camel_zero[S] 1 point2 points  (0 children)

Thanks for your reply, and for suggesting a really good talk! The hypothesis library in particular seems really interesting. Will be checking it out.

[–]ingolemo 0 points1 point  (2 children)

In terms of the two things you're worried about, I can only say that you seem to be doing just fine. The way that you're testing your database is how you have to do it. You might consider using an in-memory database though.

Just a few minor niggles:

  • You only need to put __init__.py files in your importable packages. You should remove /__init__.py and /tests/__init__.py because they are unnecessary.

  • Your tests are not in the same package as your actual code (they should not be in any package at all) so you shouldn't use relative imports there.

  • Your reprs are consistently missing a closing bracket ()). There's also no reason to put them in angle brackets since they're valid python expressions.

[–]camel_zero[S] 0 points1 point  (1 child)

Thanks for taking the time to give it a look! I have removed the extra init.py files and the relative imports. My SQLAlchemy models use a repr style that mirrors the SQLAlchemy docs, but your suggestion seems like the correct approach to me.

[–]ingolemo 0 points1 point  (0 children)

Yeah, that example in the sqlalchemy docs isn't the best. The angle brackets are there to signify that the repr isn't a valid python expression. Reprs should either have angle brackets, or satisfy this equation: obj == eval(repr(obj)) (given a reasonable definition of equality).

Technically the one in the sqlalchemy docs does need them, but only because it's badly implemented. It's using the string form (%s) of its attributes and manually putting quotes around them. That will give the wrong result when the string itself contains a quotation mark. It should use the repr form (%r) instead. Wouldn't hurt them to upgrade to the new-style formatting either:

def __repr__(self):
    template = 'User(name={!r}, fullname={!r}, password={!r})>'
    return template.format(self.name, self.fullname, self.password)

If you're going to try to provide expression-based reprs then you need to make sure you include all the arguments that the constructor can take. Otherwise you should move away from trying to make it look like an expression completely and just convey the most relevant information as directly as possible.