Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> Like, you do 'assert.equals(x,y)', and it doesn't even show you what the values of x and y are, let alone figure out that maybe "x!=y" would be an obvious thing to print.

That's why pytest is my buddy. You don't use any odd method, you just write `assert x == y` and if it fails it tells you that it fails, and what the operands were:

        def test_py():
            a = geta()
            b = getb()
    >       assert a == b
    E       assert 7 == 467
if you add an assertion message, it just gets added to the output:

        def test_py():
            a = geta()
            b = getb()
    >       assert a == b, "assertion message"
    E       AssertionError: assertion message
    E       assert 99 == 343


It also tends to show local variables and function arguments. It also has --pdb.

This makes debugging without --pdb pretty easy in most cases: http://i.imgur.com/IqRzKnG.png

pytest gets a lot of stuff right, though it also has many faults (like almost any piece of software).


pytest is great, but a just a bit too much magic for me. And I really don't like it when you pass a user defined failure message, you lose all this nice introspection.

With unittest, longMessage = True + my own failure message with the info I want gets me where I need to be. That being said, it is more work/boilerplate.

https://docs.python.org/2/library/unittest.html#unittest.Tes...

Python 3 has subtest, which gives you built in parameterized testing. I have no idea why this was not backported to 2.7, so you must used pytest or nose_parameterized or ddt.

https://docs.python.org/3/library/unittest.html#unittest.Tes...


> pytest is great, but a just a bit too much magic for me.

There isn't much magic there, just an import hook which rewrites the assertion during compilation.

> And I really don't like it when you pass a user defined failure message, you lose all this nice introspection.

Er… you don't, that's what the second snippet shows: if you have a custom assertion message, it just prints the message alongside everything else…


> Er… you don't, that's what the second snippet shows: if you have a custom assertion message, it just prints the message alongside everything else…

Is that a new addition to pytest? I do seem to remember the user defined message stomping over whatever pytest would normally spit out.


That seems to have been fixed in version 2.6.2 released in September 2014[0]:

> Implement issue549: user-provided assertion messages now no longer replace the py.test introspection message but are shown in addition to them.

[0] https://docs.pytest.org/en/latest/changelog.html#id228


cool, thanks for clearing that up for me.


This is because Python makes it excessively easy to analyze call stack. It may be the case for many other VM-based runtimes, like Ruby or JVM, but it's hardly feasible in Go.


> This is because Python makes it excessively easy to analyze call stack.

Wrong. Pytest uses AST rewriting to inject debugging information, introspection has not been the default mechanism for years[0], and was removed entirely in pytest 3.0 (released mid-2016).

> It may be the case for many other VM-based runtimes, like Ruby or JVM, but it's hardly feasible in Go.

Wrong again, see above, as long as you can statically inspect a function body and rewrite an assertion statement you can do what pytest does.

[0] I think rewriting was made the default as soon as it landed back in 2011 but am not actually certain


Wow... I am using Django's stock test runner and that makes me jealous. I've wished I could just write python asserts and have it print useful information.

Of course, this technique only works in dynamic languages. In Go I use testify assert and that is good enough for me.


> Of course, this technique only works in dynamic languages.

Actually, pytest does that by rewriting the AST[0], basically it rewrites the `assert` statement into a more complex form which extracts all the info it needs upon failure. In a statically typed language, you could do that with a compilation hook and some codegen.

There used to be a "reinterpret" mode where it would walk the stack frame and try to understand the expression involved at runtime, that was removed in Pytest 3.0, now the choices are assert-rewriting and plain assert (without any introspection).

[0] http://pybites.blogspot.be/2011/07/behind-scenes-of-pytests-...


> Of course, this technique only works in dynamic language

It can work in any language that supports reflection, dynamic or not.


Or macros, or just direct language (i.e. compiler) support.


Just switch to pytest + pytest-django. It can run Django tests.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: