On Mon, Jun 20, 2011 at 4:25 PM, Nan <ringe...@gmail.com> wrote:

>
> Hm, I'm not worried about receiving a valid response from the third-
> party API, just about testing the value of the "msg" parameter that's
> passed into it.  I need to test the msg parameter because it is in
> turn essentially a proxy for which state was reached in my_view.
>
> my_view is actually a great deal more complex than in the example, and
> is indeed broken into many smaller function calls.  I need to unit
> test to make sure that the logic is correct -- and since all those
> function calls return empty HttpResponse objects, I can't use their
> return values to test the correctness of their logic.
>

Your view function may indeed be too complex to test properly, and it sounds
like it is too tightly coupled with with the API call -- there is no way to
call the view without having it call the actual 3rd-party API as imported at
the top of the file.

There are a couple of ways out of this -- one is to use mocks, as suggested
before. Coupled with the dependency injection pattern, you would normally do
something to have the testing framework pass the mock API to the view, and
then you would query the mock at the end of the test to see what was passed
to it. Since Django's test framework is based around end-to-end testing
(making requests through TestCase.client and examining the response
returned,) this can be difficult to achieve.

The other way is to make your view function as simple as possible -- simple
enough that it is obviously correct, without any unit tests. Take
*everything* that can affect the message which is passed to the API, and
abstract that into another function that the view can call. Then test *that*
function as a unit.


>
> Just brainstorming here, could there be a way around this by placing a
> logging call of some sort in theAPI.call() that would only be executed
> during unit testing, and then to test the contents of the log?
>

This sounds like turning your API wrapper into a mock object at test time --
it might be the easiest way to do it, if you go the mock route.

If theAPI is a class, then give it methods like setTestMode() and
resetTestMode(), and use them in your setUp and tearDown methods. Then, if
test mode is enabled, don't actually make the third party call, just store
the passed-in message in a module-level or class-level list and return
success. After your view returns, check the list to see that the message was
correct.

Depending on the tests you have, you may want to have a way to tell the API
to return success or various kinds of failure. Most mocking frameworks have
ways of telling the mock objects what to return before making the method
calls.

At some point, though, I would start to become wary of putting too much
testing code in the real classes. (I'm sure there's an unpleasant name for
that kind of pattern)


>
>
> On Jun 20, 6:20 pm, DrBloodmoney <drbloodmo...@gmail.com> wrote:
> > On Mon, Jun 20, 2011 at 3:52 PM, Nan <ringe...@gmail.com> wrote:
> > > I'm not testing the third-party service.  I need to test *what I send
> > > to them*.  I.e. that the output of my_view is correct.  The trouble is
> > > that neither my_view nor the API call actually returns the output that
> > > I need to check.
> >
> > > Does that make sense?
> >
> > Mock is one good solution. Here's what I've done in the past
> > (basically half-assed mock):
> >
> > 1. Have representative data sets that are good for the service (eg.
> > whatever you send to them, and whatever they send you in return).
> > 2. Monkey patch the call:
> >
> > def hackety_patch():
> >     from StringIO import StringIO
> >     data = StringIO(testdata_response_from_API)
> >     data.seek(0)
> >     return data.read()
> >
> > # in TestCase subclass
> > def setUp(self):
> >     third_party.api.urllib2.urlopen = hackety_patch
> >
> > def tearDown(self):
> >     third_party.api.urllib2.urlopen = urllib2.urlopen
> >
> > 3. Break up your API calling code into more testable units to truly
> > isolate your independent code from the API calling code. It'll be much
> > easier to catch problems in the API integration code.
>
> --
> You received this message because you are subscribed to the Google Groups
> "Django users" group.
> To post to this group, send email to django-users@googlegroups.com.
> To unsubscribe from this group, send email to
> django-users+unsubscr...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/django-users?hl=en.
>
>


-- 
Regards,
Ian Clelland
<clell...@gmail.com>

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to django-users@googlegroups.com.
To unsubscribe from this group, send email to 
django-users+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en.

Reply via email to