On Tue, Jun 21, 2011 at 7:30 AM, Nan <ringe...@gmail.com> wrote:

>
>
> > 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.
>
> I'd be a little confused as to how to factor that out.  I mean, in the
> actual app that call is refactored behind a function that wraps the
> third-party API, and I could theoretically monkey-patch something over
> that function call for unit testing.  But the view still has to return
> an HttpResponse, and a blank one.
>

You're right, the view does need to return an HttpResponse; there's nothing
you can do about that. My point about tight coupling was that your view has
also been made responsible for instantiating the API wrapper that it thinks
it needs, and there's no way to tell it not to. In other frameworks, I would
immediately suggest using dependency injection -- the view depends on an API
wrapper instance, so it shouldn't be creating that instance; that should be
provided to it:

def my_view(request, api):
    ...
    result = api.call(msg)

because then you could call my_view(request, theAPI()) in most
circumstances, but my_view(request, fake_api) in test code. Unfortunately,
the view is almost always called directly by Django, and you don't have much
control over its parameters.


> > 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.
>
> Yes, it is very complex: it has to assess about 30 different potential
> states via nested conditionals.  It's actually broken down into a
> number of sub-functions that each deal with a few sub-states; and
> while refactoring might be a good idea, I wouldn't want to even
> attempt that before having some good unit tests in place!
>
> I think what you're suggesting (correct me if I'm wrong) is to have
> the top-level view function be the only place the API is called, and
> to use only a single call; every other sub-function that reaches an
> exit state should instead return a string containing the message to
> send?
>

That's what I was suggesting; that way the view becomes simple enough that
anyone looking at it can be assured of its correctness, without a host of
unit tests. Those tests can be applied to the functions that actually
construct the messages. But, see below -- I didn't realise that this effort
was to aid in refactoring the code.


>
> Thinking aloud, my concern then becomes that some of the sub-functions
> must actually make multiple API calls.  So we'd have to be returning
> tuples or something instead.
>
> > 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.
>
> Oh!  Thank you!  I didn't understand before how a mock API might make
> that possible -- it makes a lot more sense now.  That soudns like the
> perfect way to do it.
>
> At least until we've got enough tests to make sure the refactoring is
> correct, I need to be able to create the tests without touching the
> actual view logic, so testing what the API receives makes the most
> sense to me.
>

If this is all for a refactoring, then you're probably on the right track
there -- instrument the existing object for testing, rather than
restructuring the view first. Get the code into a state where you can trust
it, and then you can start restructuring it to make it more easily testable
in the future.

Good luck! :)


-- 
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