django-nose
django-nose copied to clipboard
Wrapping django-nose tests leads to getting them run twice
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
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: sorry, reformatted.
@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?
@jwhitlock: ping
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: 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, 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: 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...
Also, thanks for pointing me to the plugin @jwhitlock, I'll try it out.
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.
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.