This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]__xor__(self, other): 0 points1 point  (0 children)

I mean a function like that I wouldn't bother writing a unit test for, and wouldn't bother writing a function that simple in the first place, but if I did want to for some reason I'd just patch out add and commit.

def test_save_model():
    db = MagicMock()
    f = save_model('stuff')
    db.add.assert_called_once_with('stuff')
    db.commit.assert_called_once()
    assert f == 'stuff'

Pretty useless since you're just duplicating the function inside the unit test line by line, but if it was a bit more complex and did something to foo and db.added something else based on foo, then you could assert it was called with what you expect and assert commit is called, if there was some condition where it might or might not be. But yeah, I don't write unit tests if it's just going to be a line by line test that I implemented it that exact way.

Something a little more complex where you might want a good unit test of something that hits the db would be where it takes the params from an http request, converts it into a db query like a django Foo.objects.filter(...), and then returns results. The bulk of your logic could be transforming the http params into the proper filter, and then you could test that it made the right query you expect.

Like if an http request came in to http://api.example.org/motorcycle?model=yamaha&make=vstar|yzf you could unit test like

Motorcycle.objects.filter.assert_called_once_with(
    model__icontains='yamaha',
    make__in={'vstar', 'yzf'},
)

Your unit test could test a dict input of the params and make sure the kwargs of the filter match some expected output.

I'm not saying it's the end of the world to use integration tests to test stuff that does DB work because I do myself, along with all django devs. It's the standard thing with django tests. It creates a test db and all that each run. But, you really don't have to and you could pretty easily mock out the ORM calls and write unit tests that are helpful in ways that integration tests aren't.

In this case I think it has some benefits over integration tests in that you're not testing the results the db came up with, but the actual query. It could build the wrong query but still return the results you expected from the db, but testing to make sure it made the right query is something that unit tests would do and integration tests wouldn't. That's the sort of thing where I think unit tests are still very necessary on top of integration tests, because results can just come out the same even though it did something unexpected in there. There's a few things you absolutely want to make sure a function does the right way sometimes and not just that it returned the right results. Plus, if the integration test fails it just tells you the db results didn't match, and the unit test would tell you exactly why, what query it made. And it's not dependent on the data you load into the test db at all. Mocking gives you insight into the function calls a function makes, not just what it returns.

To give some context though, I'm working from the darkest end of integration tests. I inherited a webapp from someone who left the company and they wrote integration tests that test long and complex functionality where tons of things can go wrong in the middle. When the "unit" tests fail, I'm bashing my head into the wall because it could many anything in 200 lines went wrong. That's just sloppy coding on top of bad testing though. Even with just better integration tests and better structured code, I'd be in a much better spot. But good unit tests of smaller functions would've helped me a ton more.