Hi,When creating self.client in TestCase, it would be very useful if the testcase instance was passed to the client.I'm using a replacement client class that does various validation checks, so wants to use assert* functions on TestCase, thus takes a testcase instance as a parameter at creation time. However this means it can't be used as the client_class attribute on TestCase, as this is instantiated with no parameters (https://github.com/django/django/blob/master/django/test/testcases.py#L475)There are work-arounds, but it feels to me like a reasonably generic requirement that a test client may want to refer to the test case it's being used with. I think the change can be made largely backwardly compatible by changing to:self.client = self.client_class(testcase=self)which would only break an existing replacement client class that had an __init__ method without **kwargs.I'm happy to code this up, but wanted to check for any objections first.
On Thu, Jan 3, 2013 at 1:56 AM, Malcolm Box <mal...@tellybug.com> wrote:Hi,When creating self.client in TestCase, it would be very useful if the testcase instance was passed to the client.I'm using a replacement client class that does various validation checks, so wants to use assert* functions on TestCase, thus takes a testcase instance as a parameter at creation time. However this means it can't be used as the client_class attribute on TestCase, as this is instantiated with no parameters (https://github.com/django/django/blob/master/django/test/testcases.py#L475)There are work-arounds, but it feels to me like a reasonably generic requirement that a test client may want to refer to the test case it's being used with. I think the change can be made largely backwardly compatible by changing to:self.client = self.client_class(testcase=self)which would only break an existing replacement client class that had an __init__ method without **kwargs.I'm happy to code this up, but wanted to check for any objections first.Personally, I'm suspicious of any "A owns B, but B knows about A" relationships. There are certainly occasions when they're required, but whenever they pop up, it's generally an indication of a set of interfaces that are closely coupled.
In this case, I'm not sure I see why this coupling is required. A test case is a test case. A test client is a test client. Their concerns are completely separate (evidenced by the fact that you can have a test case without any client usage, and vice versa). I very much see the test client as a utility tool for the test case -- really not much more than a convenient factory for requests -- not an integral part of a test case.
Your feature request seems to be stem entirely from the fact that you want to invoke assertions in the test client code itself -- something that you're doing because you've got a bunch of extensions in your test client. I'll leave it up to you to determine if this is the right approach for your own project, but I'm not convinced it's a general requirement that warrants binding the test client to the test case.
On Friday 04 January 2013, Malcolm Box wrote:
>
> The general pattern I want to implement is have a test client that makes
> assertions about all the requests made during a set of tests. For example,
> it could check that every get() returned cache headers, or that
> content_type is always specified in responses. Or that the response has
> certain HTML, uses certain templates etc - ie all of the assertion testing
> goodness in django.test.TestCase.
>No, you're mixing concerns.
> def test():
> r = self.client.get(...)
> self.check_response(r)
>
> but this is error prone, verbose etc etc.
>
> The right thing is that within a test suite, the get()/post() etc to do the
> checks for me - and so it should be possible to create a testclient that
> does this, and be able to use this testclient in various test suites.
>
class MyTestCase(TestCase):
> Is there a simple, clean way to solve this that I'm missing?
>
def checked_get(self, *args, **kw):
def check_response(self, response):
self.assertContains(response, ....)
r = self.client.get(*args, **kw)
self.check_response(r)
return r
class SpecificTest(MyTestCase):
def test():
r = self.checked_get(...)
...
That's how I would do it.