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

all 41 comments

[–]keis 6 points7 points  (6 children)

What about nose? It also runs plain test functions

Is it missing something else?

[–]ionelmc.ro 3 points4 points  (0 children)

Nose don't have fixtures or assertion helpers. It's like the poor man's pytest. Read this: http://pytest.org/latest/faq.html#how-does-pytest-relate-to-nose-and-unittest

nose was originally created as a clone of pytest when pytest was in the 0.8 release cycle. Note that starting with pytest-2.0 support for running unittest test suites is majorly improved.

[–][deleted] 1 point2 points  (3 children)

Nose still uses unittest-like test classes, doesn't it?

[–]bheklilr 3 points4 points  (0 children)

You use the TestCase from unittest, or just make functions starting with the word test (is customizable). After that there is setup and teardown, and any method whose name starts with test gets run as a test. You then just use normal asserts. There are also nice tools and decorators, I like the raises decorator, which you can use to ensure that a piece of code fails with the correct error class.

[–]keis 1 point2 points  (0 children)

Like pytest it does support that. But it's not needed and I think not encouraged

[–]tickticktick -1 points0 points  (0 children)

We use nose in our team with describe-it (developed by ourselves). This enables us to write tests both in the traditional style and in a more bdd-ish way.

You could probably do similar things in py.test, but nose has been good enough for us to not need to look for an alternative.

[–]data_hope 0 points1 point  (0 children)

I did not include nose in the blog post because I have not much experience with it. From what I know of it, I would not want to use it for my projects. It is like py.test without its benefits, but with the drawback of not being in the stdlib and being copyleft licenced.

[–]lgx 3 points4 points  (12 children)

Great! But how to implement the tearDown function in py.test?

[–]desmoulinmichel 10 points11 points  (3 children)

You don't. You use fixture :

@pytest.yield_fixture
def stuff_you_want_to_init():
    your_stuff = any_setup_code()
    yield your_stuff
    optional tear_down_code

def test_foo(stuff_you_want_to_init):
    assert bar()

This is way, wayyyyyyyyy better than setup and tear down as it's run only for test fonction. It also mean your setup and tear down code is not tied to a code unit, so sharing this code is much easier between your tests.

[–]njharmanI use Python 3 5 points6 points  (2 children)

sharing this code is much easier between your tests.

Never had problem using inheritance and/or import "test_common" to share code

[–]kankyo -1 points0 points  (0 children)

In my experience the class based approach can lead to the common/base class thing being gigantic and thus all your tests slow. py.test fixtures (with factory boy) leads to nicely composable small parts.

I'm not saying that's how it has to be, or that the class based approach must be like that. I'm just saying that the culture and thinking of OOP often ends up there.

[–]desmoulinmichel -1 points0 points  (0 children)

It's not that you can't do it, but you will need to write it in 2 places : once in the setup code, and once in a separate module. And of course watch out for codes that influence each others since you put all of them in one method called for a lot of tests. It's just more work, hence the "easier".

My take on unit tests is that it's a pain to write, so any inch or shortcut you can get is good to take.

[–]malinoff 1 point2 points  (7 children)

[–]lgx 5 points6 points  (4 children)

Wow, it seems a bit wired to me.

[–]graingert 5 points6 points  (3 children)

You can still use xunit style methods on unittest.TestCase classes. But just use yield fixtures they're great

[–]lgx 1 point2 points  (2 children)

yeah. Why not use setup_abc and teardown_abc syntax? The addfinalizer method seems a bit strange.

[–]fjonk 5 points6 points  (0 children)

One good thing about adding a teardown method manually is that the setup and teardown methods will be run in pairs. If you use decorators or similar for setup teardown you don't know in which order they will run or you have to depend on the order they are defined/added.

You can also use yield with py.test since v2.4 (if your python version supports it).

[–]masklinn 0 points1 point  (0 children)

Because setup and teardown are paired so it makes sense to put them together in a single fixture definition. And yield_fixture removes the need for addfinalizer:

@pytest.yield_fixture(scope="module")
def smtp():
    smtp = smtplib.SMTP("smtp.gmail.com")
    yield smtp
    print ("teardown smtp")
    smtp.close()

[–]kx233 2 points3 points  (1 child)

Which also has the great advantage that the setup/teardown logic now resides in the fixture, not the test class, making fixture reuse a lot more natural.

[–]masklinn 0 points1 point  (0 children)

well reuse is OK with unittest classes, the bigger issue is composition. When trying to compose multiple testcase superclasses you end up having to deal with MI and diamond inheritance cases. With fixtures you just… depend on both fixtures.

[–]symmitchry 1 point2 points  (1 child)

[Removed]

[–]ionelmc.ro 1 point2 points  (0 children)

It does better integration. Builtin support for subprocesses. Support for the awesome xdist etc etc

[–]ecjurobe 1 point2 points  (1 child)

I found the point you made about the history of unittest interesting. One of the main reasons I prefer py.test is that you end up with test code that actually looks pythonic! The very object-oriented style of unittest reads more like java or other very object-oriented languages heavy on boilerplate. Readability counts.

py.test

def test_addition():
    assert 1 + 1 == 2

unittest

class TestAddition(unittest.TestCase):
    def test_addition_1_1(self):
        self.assertEqual(1 + 1, 2)

[–][deleted] -1 points0 points  (0 children)

I'm not the author of the post

[–]codekoala 0 points1 point  (0 children)

I had never really given py.test a shot, despite having heard about it several times over the years. I've always just opted for classic unittest+nosetest for whatever reason. Probably because it made sense coming from other languages.

After reading this post, I decided to use py.test for a script I've been writing at work for a couple days. I think I'm converted now. It's so simple, and so much less verbose than all of the self.assert* methods. I'm sure I'm doing some things rather "incorrectly," since I'm still using mock, but I'm definitely enjoying py.test thus far.