Hey Zeb,

On Sunday 15 January 2006 13:54, ZebZiggle wrote:
> Hi again,
>
> I'm messing around with my Model and my views and putting a 'unittest'
> jig around what I'm building. Certainly, I don't want to test at the
> view layer (passing in HttpRequests and getting back HttpResponses),
I looked into unit testing at this level with web unit but I dropped the idea 
as it just felt like too much hassle.  I'm interested to hear what other 
folks think about unit testing this close, or closer, to the ui.


> The unittesting framework only deals with the controller layer.
>
> I could have moved all this down into the model layer, but on initial
> create operations there is no model object to work with. This means I
> would have to use a static method on the class (not exactly trivial in
> python) and given the magic that occurs on the model objects I wonder
> if static methods would work and not break things.
>
> What are your thoughts on my approach to testing here (creating the
> controller layer) or my concerns about moving these methods into the
> model?
>
> I think ideally these methods belong in the model, but I'm worried that
> it's a lot of work to make it work elegantly. I suppose another
> alternative is to just put functions in the model, but then you lose
> your ability for inheritance (as you do in the model anyway).
My rule of thumb is to use my no_table patch (which I suspect will be rendered 
moot by the magic removal branch) in addition to mix-in classes to move 
almost all the logic into the model classes and out of the view functions.  
Then I test the logic methods like crazy.

Here's a typical scenario:

class ModelBase(meta.Model):
    """Fields common to all inheriting model classes"""
    created_on = meta.DateTimeField(...
    ...
    class META:
        # Explicitly set the no_table flag so that this class doesn't
        # result in a table being created.
        no_table = True
  

class MyMixIn:
    """Container of model logic methods, etc."""
    def some_useful_method(self):
        """These methods are the focus of my unit testing."""
        ...
    class META:
        # Explicitly set the no_table flag so that this class doesn't
        # result in a table being created.
        no_table = True


class MyModel(ModelBase, MyMixIn):
    """Define fields specific to this model, it also gets all the fields
    defined in ModelBase.  It has zero or very few logic methods, rather,
    it inherits them from MyMixIn class.  It is as close to a regular
    table definition as possible.  This is the model class that Django
    uses to define the db table.
    """
    foo_field = meta.CharField(maxlength=40)
    ...


My unit tests typically build sample records on which to test in the setUp() 
method, which are removed in the tearDown() method.  Each "test_foo" method 
exercises a method defined in the MyMixIn class.  The unit tests run nicely 
from the command line and are completely decoupled from the web ui (yay 
django orm!)

So far, I've found this approach sufficiently tests the logic I'm most 
concerned with.  It allows me to divide the logic from the table definitions 
in a fairly clean way.  It also keeps the view code focused almost entirely 
on request/response stuff.  I don't have to worry about controller code 
mucking up the view modules because my models have whatever methods are 
needed (like your 'attemptSaveUser()').  The approach isn't perfect as I'm 
not testing request/response code as I'd like.  I'd love to find an elegant 
way to perform such tests.  Moving most of the logic into my models makes the 
unit tests concise, easy to read and understand.  Keeping the views simple 
eases the pain of testing the web ui 'by hand'.

Eric.

Reply via email to