#24965 closed Cleanup/optimization (fixed)
Make LiveServerTestCase.live_server_url accessible from class
| Reported by: | Moritz Sichert | Owned by: | Moritz Sichert |
|---|---|---|---|
| Component: | Testing framework | Version: | dev |
| Severity: | Normal | Keywords: | selenium tests live server test case url |
| Cc: | Triage Stage: | Accepted | |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
Consider following test:
class MySeleniumTest(LiveServerTestCase):
@classmethod
def setUpClass(cls):
super(MySeleniumTest, cls).setUpClass()
# initialize selenium driver
cls.selenium = WebDriver()
# initialize browser state, live_server_url is needed here
cls.selenium.get(cls.live_server_url)
# [...]
Right now this doesn't work, because live_server_url is a property even though it only consists of class attributes.
Since class properties are a bit more complicated I suggest adding a get_live_server_url classmethod and keeping the live_server_url.
An alternative is to deprecate live_server_url but I don't think that's really necessary.
Change History (12)
comment:1 by , 10 years ago
| Owner: | set to |
|---|---|
| Status: | new → assigned |
comment:2 by , 10 years ago
| Has patch: | set |
|---|
comment:3 by , 10 years ago
comment:4 by , 10 years ago
Yes that would be better and I thought about it, but I didn't want to add a new decorator just for one property.
Should the classproperty go into some utils module then?
I don't see were else it would make sense to use, so I guess that's ok.
comment:5 by , 10 years ago
| Patch needs improvement: | set |
|---|---|
| Triage Stage: | Unreviewed → Accepted |
django.utils.decorators seems like a good candidate.
comment:6 by , 10 years ago
| Patch needs improvement: | unset |
|---|
Updated PR.
Is some additional documentation needed?
comment:7 by , 10 years ago
I don't think so. A simple test for live_server_url being accessible as a class property might be useful if it's easy.
comment:8 by , 10 years ago
How should I do that?
I could do something like
class TestLiveServerTestCase(LiveServerTestCase):
@classmethod
def setUpClass(cls):
super(TestLiveServerTestCase, cls).setUpClass()
if isinstance(cls.live_server_url, str):
cls._test_worked = True
else:
cls._test_worked = False
def test_worked(self):
self.assertTrue(self._test_worked)
But that feels really hackish.
And instanciating LiveServerTestCase inside a SimpleTestCase isn't that trivial, I think.
comment:9 by , 10 years ago
Right, I was thinking something like this:
-
tests/servers/tests.py
diff --git a/tests/servers/tests.py b/tests/servers/tests.py index e84b878..0636a13 100644
a b import socket 9 9 10 10 from django.core.exceptions import ImproperlyConfigured 11 11 from django.test import LiveServerTestCase, override_settings 12 from django.utils import six 12 13 from django.utils._os import upath 13 14 from django.utils.http import urlencode 14 15 from django.utils.six.moves.urllib.error import HTTPError … … class LiveServerAddress(LiveServerBase): 71 72 else: 72 73 del os.environ['DJANGO_LIVE_TEST_SERVER_ADDRESS'] 73 74 75 cls.live_server_url_type = type(cls.live_server_url) 76 74 77 @classmethod 75 78 def tearDownClass(cls): 76 79 # skip it, as setUpClass doesn't call its parent either … … class LiveServerAddress(LiveServerBase): 92 95 # test runner and the overridden setUpClass() method is executed. 93 96 pass 94 97 98 def test_live_server_url_is_class_property(self): 99 self.assertTrue(issubclass(self.live_server_url_type, six.text_type)) 100 95 101 96 102 class LiveServerViews(LiveServerBase): 97 103 def test_404(self):
Would an approach like this be better than adding a method?
diff --git a/django/test/testcases.py b/django/test/testcases.py index b17b392..22ab3c1 100644 --- a/django/test/testcases.py +++ b/django/test/testcases.py @@ -1245,6 +1245,13 @@ class LiveServerThread(threading.Thread): self.httpd.server_close() +class classproperty(object): + def __init__(self, f): + self.f = f + def __get__(self, obj, owner): + return self.f(owner) + + class LiveServerTestCase(TransactionTestCase): """ Does basically the same as TransactionTestCase but also launches a live @@ -1259,7 +1266,7 @@ class LiveServerTestCase(TransactionTestCase): static_handler = _StaticFilesHandler - @property + @classproperty def live_server_url(self): return 'http://%s:%s' % ( self.server_thread.host, self.server_thread.port)Is it okay for the attribute to fail when not using
setUpClass? For example:>>> from django.test.testcases import LiveServerTestCase >>> LiveServerTestCase.live_server_url Traceback (most recent call last): File "<console>", line 1, in <module> File "/home/tim/code/django/django/test/testcases.py", line 1252, in __get__ return self.f(owner) File "/home/tim/code/django/django/test/testcases.py", line 1272, in live_server_url self.server_thread.host, self.server_thread.port) AttributeError: type object 'LiveServerTestCase' has no attribute 'server_thread'