vendredi 29 juillet 2016

Pythonic approach to testing properties?

I've run into an issue writing unit tests for class attributes with the @property decorator. I am using the excellent py.test package for testing and would definitely prefer sticking with it because it's easy to set up fixtures. The code for which I'm writing unit tests looks something like this:

    class Foo(object):

        def __init__(self, fizz, buzz, (and many more...)):
            self.fizz = fizz
            self.buzz = buzz
            self.is_fizzing = #some function of fizz
            self.is_fizz_and_buzz = fizz and buzz
            ...

        @property
        def is_bar(self):
            return self.is_fizz_and_buzz and self.buzz > 5

        @property
        def foo_bar(self):
            # Note that this property uses the property above
            return self.is_bar + self.fizz

        # Long list of properties that call each other

The problem occurs when writing a unit test for a property which uses multiple other properties sometimes in long chains of up to four properties. For each unit test, I need to determine which inputs I need to set up and, even worse, it may be the case that those inputs are irrelevant for testing the functionality of that particular method. As a result, I end up testing many more cases than necessary for some of these "properties."

My intuition tells me that if these were actually "properties" they shouldn't have such long, involved calculations that need to be tested. Perhaps it would be better to separate out the actual methods (making them class methods) and write new properties which call these class methods.

Another issue with the current code--correct me if I'm wrong--is that every time a property is called (and most properties are called a lot) the attribute is recalculated. This seems terribly inefficient and could be fixed like this with new properties.

Does it even make sense to test properties? In other words, should an attribute itself be calculated in a property or should it only be set? Rewriting the code as I described above seems so unpythonic. Why even have properties in the first place? If properties are supposed to be so simple to not require testing, why not just define the attribute in the init?

Sorry if these are silly questions. I'm still fairly new to python.

Aucun commentaire:

Enregistrer un commentaire