django-nose icon indicating copy to clipboard operation
django-nose copied to clipboard

Wrapping django-nose tests leads to getting them run twice

Open d33tah opened this issue 9 years ago • 11 comments

I needed to create a wrapper that I could inject into all test_ methods of my Django app. I came up with this piece of code that works with unittest but doesn't with nose:

from django.contrib.staticfiles.testing import StaticLiveServerTestCase


class AdminTestCase(StaticLiveServerTestCase):

    def test_project_adding(self):
        pass


def __test_wrapper(func, testname):
    def func_wrapper(self):
        try:
            return func(self)
        except Exception, e:
            print("\nCaught %s, sleeping for 3 seconds." % repr(e))
            time.sleep(3)
            raise
    return func_wrapper
__test_wrapper.f_number = 0

__test_methods_names = [x for x in dir(AdminTestCase) if x.startswith('test_')]
for method_name in __test_methods_names:
    print('patching %s' % method_name)
    old_f = getattr(AdminTestCase, method_name)
    new_f = __test_wrapper(old_f, method_name)
    setattr(AdminTestCase, method_name, new_f)
    setattr(new_f, '__name__', old_f.__name__)
__test_wrapper.num_tests = len(__test_methods_names)

The problem is that the test from tests.py is ran twice - once as test_project_adding and once as app.tests.test_project_adding. How could I walk around this one?

Also, I filed a StackOverflow question about this one: https://stackoverflow.com/questions/37056858/wrapping-django-nose-tests-leads-to-getting-them-run-twice

d33tah avatar May 06 '16 11:05 d33tah

Could you try reformatting your post? It is a bit hard to follow.

https://guides.github.com/features/mastering-markdown/

The word "test" in a name is often used by nose to signal that a class or function should be tested. I sometimes have to add an attribute to a class to make it skip testing:

def test_network_connection():
    # Some magic to test the network

test_network_connection.__test__ = False

This can be avoided by not using the word "test" or "Test" in functions and classes that aren't unit tests. This is one of those nose features that does the right thing 95% of the time, and is annoying the other 5%.

jwhitlock avatar May 06 '16 16:05 jwhitlock

@jwhitlock: sorry, reformatted.

d33tah avatar May 06 '16 17:05 d33tah

@jwhitlock: thanks for your answer - I experimented with both removing __test from the names (kind of expected it to skip them based on the __), as well as setting __test__ and neither helped. Regardless of what I try, the test gets run twice in this sample. Do you have any more ideas?

d33tah avatar May 06 '16 18:05 d33tah

@jwhitlock: ping

d33tah avatar May 09 '16 10:05 d33tah

I think you may be fighting nose with your wrapper, and should try another way to your desired result. For example, you could create a derived class of TestResult that overrides addError to add the pause. You then pass your derived class to the test runner as resultclass.

You could try an upstream bug, although nose is also in maintenance mode.

jwhitlock avatar May 09 '16 19:05 jwhitlock

@jwhitlock: thanks, this sounds like something that could work. Not sure though how to make it work with django-nose. Where could I pass the resultclass there?

d33tah avatar May 11 '16 13:05 d33tah

@d33tah, I take it back. nose doesn't use unittest conventions, so this approach won't work. To do this with nose, I think you need to write a plugin. The Failure Detail plugin is pretty close to what you need, except that you want formatFailure to pause for 3 seconds.

I'm not sure if you invest this effort in nose. You may want to look at py.test.

By the way, why do you want tests to pause for 3 seconds on failures?

jwhitlock avatar May 11 '16 21:05 jwhitlock

@jwhitlock: basically because those are Selenium tests and I'd like to have time to inspect them. I could drop them into a debugger, but it'd be nice to have the same shell script work in both cases...

d33tah avatar May 12 '16 09:05 d33tah

Also, thanks for pointing me to the plugin @jwhitlock, I'll try it out.

d33tah avatar May 12 '16 09:05 d33tah

Ah Selenium debugging. It's been a while since I've had to do that., I will probably have to start myself later this year. I'm planning on py.test for that.

There was a selenium plugin written in 2010 that allows pausing on test failures:

http://blog.reallysimplethoughts.com/2010/11/15/the-power-debugger-plugin-v1-0-for-selenium-ide-released/

I think it doesn't work with current Firefox versions. But, you may find something in the Selenium docs or forums to do this with Selenium configuration rather than in the test suite.

jwhitlock avatar May 12 '16 14:05 jwhitlock

The problem is that I'd like to treat failed assertions as errors, which selenium can't know about. This is why I'm experimenting with django-nose.

d33tah avatar May 12 '16 14:05 d33tah