Python Unittest Modularity vs Readability - python

I have a Python unittest, with some tests having the same type object tested. The basic outline in one test-class is:
class TestClass(unittest.TestCase):
def setup(self):
...
def checkObjects(self, obj):
for i in [...values...]:
self.assertEqual(starttags(i,obj), endtags(i,obj))
def testOne(self):
#Get object one.
checkObjects(objone)
def testAnother(self):
#Access another object.
checkObjects(another)
... various tests for similar objects.
Although it's modular, I noticed that any failures will give an error like AssertionError: number != anothernumber, and the line of code generating the error, self.assertEqual(starttags(i,obj), endtags(i,obj)). If I had listed the tests out instead of placing in a for loop, I would have something like:
self.assertEqual(starttags(value1,obj), endtags(value1,obj))
self.assertEqual(starttags(value2,obj), endtags(value2,obj))
Which shows exactly which case causes the error, but is copy-paste code, which I thought was generally not recommended. I noticed the problem recently when a contributor reworked a more clean unit-test, that unfortunately would give little debug-info on assertion failures. So, what is the best-practice in these cases? Something like a list of tuples, fed into a for-loop with assertEquals is "cleaner", but copy-paste with different values on different lines gives useful stack traces.

If by cleaner you mean less code, then this kind of cleaner code is not always more readable code. In fact, it usually is less readable (especially when you come back to it). You can always go with fancy refactorings but you need to know when to stop. In longer run, it's always better to use more obvious, simple code than trying to squeeze one less line of code for artificial gains - not just in terms of unit testing.
Unit tests go with their own rules. For example they usually allow different naming conventions than what your regular code standards say, you hardly ever document it - they're kind of special part of your codebase. Also, having repeated code is not that uncommon. Actually, it's rather typical to have many similar looking, small tests.
Design your tests (code) with simplicity in mind
And at the moment, your tests are confusing even at the stage of writing them - imagine coming back to that code in 3 months from now. Imagine one of those tests breaking as a result of somebody else doing some change in some other place. It won't get any better.
Design your tests in such a way, that when one of them breaks, you immediately know why it did so and where. Not only that - design them in such a way, that you can tell what they are doing in a blink of an eye. Having for loops, ifs and basically any other kind of control flow mechanism (or too extensive refactoring) in test code, usually results in one question springing to your mind - What are we doing here? This is the kind of question you don't want to find yourself asking.
To summarize this longish post with words of people smarter than myself:
Any fool can write code that a computer can understand. Good programmers write code that humans can understand.
-Martin Fowler et al, Refactoring: Improving the Design of Existing Code, 1999
Do yourself a favor and stick to that rule.

Use nosetests, it makes your tests so much cleaner:
#!/usr/bin/python
def test_one():
for i in [...]:
assert xxx(i) == yyy
def test_two():
...

Related

Big exception handler or lots of try...except clauses

I have a question which is about code design in python.
I'm working on a certain project and I can see that there is a certain amount of different types of errors that I have to handle often, which results in lots of places where there is a try...execept clause that repeats itself.
Now the question is, will it be more preferred to create one exception handler (a decorator) and decorate with it all those functions that have those repeating errors.
The trade off here is that if I create this exception handler decorator it will become quite a big of a class/function which will then make the person reading the code to try and understand another piece of complicated (maybe) logic to understand how the error is handled, where if I don't use the decorator, its pretty clear to the reader how is it handled.
Another option is to create multiple decorators for each of the types of the errors.
Or maybe just leave all those try...except clauses even though they are being repeated.
Any opinions on the matter and maybe other solutions? Thanks!
A lot of this is subjective, but I personally think it's better for exception handling code to be close to where the error is occurring, for the sake of readability and debugging ease. So:
The trade off here is that if I create this exception handler decorator it will become quite a big of a class/function
I would recommend against the Mr. Fixit class. When an error occurs and the debugger drops you into the Mr. Fixit, you then have to walk back quite a bit before you can figure out why the error happened, and what needs to be fixed to make it go away. Likewise, an unfamiliar developer reading your code loses the ability to understand just one small snippet pertaining to a particular error, and now has to work through a large class. As an added issue, a lot of what's in the Mr. Fixit is irrelevant to the one error they're looking at, and the place where the error handling occurs is in an entirely different place. With decorators especially, I feel like you are sacrificing readability (especially for someone less familiar with decorators than you) while gaining not much.
If written with some care, try/catch blocks are not very performance intensive and do not clutter up code too much. I would suggest erring on the side of more try/catches, with every try/catch close to what it's handling, so that you can tell at a glance how errors are handled for any given piece of code (without having to go to a different file).
If you are repeating code a lot, you can either refactor by making the code inside the catch a method that can be repeatedly called, or by making the code inside the try its own method that does its error handling inside its body. When in doubt, keep it simple.
Also, I hate being a close/off-topic Nazi so I won't flag, but I do think this question is more suited to Programmers#SE (being an abstract philosophy/conceptual question) and you might get better responses on that site.

What to test when using TDD and asserts

First, I'm a newbie at both TDD and Python. I don't code for a living, but I do write a ton of code.
I'm in the process of moving a large project from Matlab to Python. 1) because the language has been limiting, and 2) when analyzing edge cases and debugging, I was starting to break as much as I was fixing. So I decided I'll start from scratch, with TDD this time.
I get the TDD cycle (red, green, refractor). The question is, -what- does one test? For an individual unit/function, how many tests do you write? In this case, I already have the whole project in my head, even though there will be a few library, and structural, changes between the languages.
Also, I've heard ad nauseam to use asserts everywhere, so I am. But sometimes it seems I'm writing tests to verify my asserts. And it seems like a waste of time to write a valid input type test for every argument, one function at a time.
You've ran into the very common realisation across programmers who try to embrace testing (good for you!) - that unit testing, for most part, sucks. Or at the very least is a wrong tool for what you are trying to do.
And this is why I recommend for you to drop the heresy of unit testing and embrace the elegance and beauty of behaviour testing. There even is a fantastic library for it: behave.
This not only allows you to re-use your code, but also forces you to describe logic of your application in plain English (which, when done right, is equivalent to proper documentation) which helps to narrow logic holes and other design non-senses that may arise. It also removes the problem of "what to test", as with BDD you should test every way the application can behave.
In your specific case you will definitely also be interested in the scenario outline functionality, where you can write the testing code once, and then just write long list of examples to run by this code.

Wondering whether I should just bail on using properties in python

I have been trying to use properties instead of specific setters and getters in my app. They seem more pythonic and generally make my code more readable.
More readable except for one issue: Typos.
consider the following simple example (note, my properties actually do some processing even though the examples here just set or return a simple variable)
class GotNoClass(object):
def __init__(self):
object.__init__(self)
self.__a = None
def __set_a(self, a):
self.__a = a
def __get_a(self):
return self.__a
paramName = property(__get_a, __set_a)
if __name__ == "__main__":
classy = GotNoClass()
classy.paramName = 100
print classy.paramName
classy.paranName = 200
print classy.paramName
#oops! Typo above! as seen by this line:
print classy.paranName
The output, as anyone who reads a little closely will see, is:
100
100
200
Oops. Shouldn't have been except for the fact that I made a typo - I wrote paranName (two n's) instead of paramName.
This is easy to debug in this simple example, but it has been hurting me in my larger project. Since python happily creates a new variable when I accidentally meant to use a property, I get subtle errors in my code. Errors that I am finding hard to track down at times. Even worse, I once used the same typo twice (once as I was setting and later once as I was getting) so my code appeared to be working but much later, when a different branch of code finally tried to access this property (correctly) I got the wrong value - but it took me several days before I realized that my results were just a bit off.
Now that I know that this is an issue, I am spending more time closely reading my code, but ideally I would have a way to catch this situation automatically - if I miss just one I can introduce an error that does not show up until a fair bit of time has passed...
So I am wondering, should I just switch to using good old setters and getters? Or is there some neat way to avoid this situation? Do people just rely on themselves to catch these errors manually? Alas I am not a professional programmer, just someone trying to get some stuff done here at work and I don't really know the best way to approach this.
Thanks.
P.S.
I understand that this is also one of the benefits of Python and I am not complaining about that. Just wondering whether I would be better off using explicit setters and getters.
Have you tried a static analysis tool? Here is a great thread about them.
Depending on how your code works, you could try using slots. You'll get an AttributeError exception thrown when you try to assign something that's not in slots then, which will make such typo's more obvious.
There are times when compile-time checking really saves time. You seem to have identified one such case. By accident rather than careful choice I use getters and setters, and am happy ;-)

Catching typos in scripting languages

If your scripting language of choice doesn't have something like Perl's strict mode, how are you catching typos? Are you unit testing everything? Every constructor, every method? Is this the only way to go about it?
Really-thorough unit tests are the most important technique (yes, I do always aim for 100% coverage), as they also catch many other typos (e.g. where I write + and meant -), off-by-one issues, etc. Integration and load tests exercising every feature are the second line of defense against all kinds of errors (mostly, though, deeper and harder ones;-).
Next are tools such as pylint and pychecker and colorizing editors (I don't use real IDEs, but they would also help similarly to how my trusty gvim editor does;-).
Techniques such as mandatory code reviews (e.g., cfr a video of an interview of mine on the subject here), while crucial, should focus on other issues -- issues that automated tools just won't catch, such as completeness and correctness of comments/docstrings, choice of good/speedy algorithms, and the like (see here for a summary of the talk I gave on the subject at the same conference as I got that interview at, and a link to the slides' PDF).
There are errors other than "typos". If you don't test something, knowing that something's found misspelled variable names won't assure you of much anyway.
Some editors (for example, NetBeans) analyse your code and underline "suspicious" parts, for example unused variables, which may be sign of a typo. NB also highlights the identifier above the cursor elsewhere on the screen, which also helps.
Of course, no clever IDE trick can replace proper testing.
In ruby, a misspelled local variable would cause the program to die horribly, which is fine.
A misspelled instance variable doesn't cause the program to die horribly, which is bad. To detect such cases, use warnings. Unfortunately, you can't easily tell ruby to treat warnings as errors.
TDD -- write your tests first, then the simplest code to pass the test. That way you can be more sure that you don't have any untested code. This will help make sure you have fewer typos or other errors in your code.
Pair programming/code reviews -- two pairs of eyes are better than one pair.
IDE with intellisense -- not a panacea, but a great help in not making typos. If you use intellisense, you typically get substitution errors, not typos. These shouldn't be hard to find with tests.
In my case, I use unit testing extensively (developing in Python). Because there are many lightweight testing frameworks well integrated into the language (or IDE if you prefer), using them cause you almost no pain ;)
Look at this example:
def unpack_args(func):
def deco_func(*args):
if isinstance(args, tuple):
args = args[0]
return func(*args)
return deco_func
def func1(*args):
"""
>>> func1(1,2,3)
(1, 2, 3)
>>> func1(*func2(1,2,3))
(1, 2, 3)
>>> func1(func2(1,2,3))
((1, 2, 3),)
"""
return args
def func2(*args):
"""
>>> func2(1,2,3)
(1, 2, 3)
"""
return args
#unpack_args
def func3(*args):
return args
def test():
"""
>>> func3(func2(1,2,3))
(1, 2, 3)
"""
import doctest
doctest.testmod(verbose=True)
test()
-----------------------------
Results:
Trying:
func1(1,2,3)
Expecting:
(1, 2, 3)
ok
Trying:
func1(*func2(1,2,3))
Expecting:
(1, 2, 3)
ok
Trying:
func1(func2(1,2,3))
Expecting:
((1, 2, 3),)
ok
Trying:
func2(1,2,3)
Expecting:
(1, 2, 3)
ok
Trying:
func3(func2(1,2,3))
Expecting:
(1, 2, 3)
ok
3 items had no tests:
__main__
__main__.func3
__main__.unpack_args
3 items passed all tests:
3 tests in __main__.func1
1 tests in __main__.func2
1 tests in __main__.test
5 tests in 6 items.
5 passed and 0 failed.
Test passed.
I presume by 'typo' you mean mistyping variable/function/class names. This is less of an issue in Python than in Perl, since Perl (and I believe Ruby) by default will automatically create a variable and initialise it to zero or "" on its first use. Python does not do this since it is an error to use a variable that has not been explicitly created, so in that sense it is already in 'strict' mode.
I use Vim with the pyflakes plugin, which underlines most kinds of typos as soon as you type them. I also use pylint and pychecker frequently since they can catch many other kinds of errors.
Another thing I do is make heavy use of Vim's auto completion - I only type a name in full once, then on subsequent uses of the name type the first few letters and use <ctrl-n> or <ctrl-p> to cycle through the matches.
I also use Test Driven Development with the aim of 100% unit test coverage.
I find that the combination of all these practices means that problems caused by typos are virtually non-existent.
Many unit test tools can show the percentage of lines they tested. The closer this percentage is to 100% the less likely variable name typo was done.
In Groovy, the abstract syntax tree (AST) that makes up a program is readily available. So tools can be written that inspect the AST and issue warnings for things that are probably errors.
For example, GroovyLint will warn you if you try to call a method that doesn't exist at compile-time, but is very close to one that does exist.
Example:
class Test{
static def foobar(){ return 5; }
}
Test.fooBar() //Here GroovyLint suggests calling foobar instead of fooBar.
I write all my Python code in eclipse IDE. As Mladen Jablanović has suggested, eclipse underlines suspicious parts.
Next step is to run the code. Now there are two kinds of errors that I am likely to face.
Errors that the interpreter catches and gives me a line number for: These are typically quite easy to debug, especially if you print all the variables in that line just before that line, to make sure that they contain the values that you'd expect.
Unexpected behavior: your code is fine and the interpreter doesn't complain, but your code doesn't behave the way you want it to. When this happens (rarely, because I usually design my modules quite well - a process that takes about 7 minutes - before I start coding) I start looking at modules/functions in the order in which they are called and try to execute the program in my head as the interpreter would see it. If that doesn't work, then I go on to explore the debugger. Usually, it doesn't come down to this, but if it does, it's a pretty big bug and it would take quite some time to fix. Unit tests help, but frankly, I think that as a computer scientist, I should be able to debug it from an algorithms analysis perspective, which is generally faster than unit testing (at least for me). Plus, choosing to do an algorithms analysis over unit testing exercises my brain so that I don't make such mistakes in the future, as opposed to unit testing which helps me fix the problem now, but doesn't do much in terms of helping me avoid making the same/similar mistake in the future.
Hope this helps

Encapsulation severely hurts performance?

I know this question is kind of stupid, maybe it's a just a part of writing code but it seems defining simple functions can really hurt performance severely... I've tried this simple test:
def make_legal_foo_string(x):
return "This is a foo string: " + str(x)
def sum_up_to(x):
return x*(x+1)/2
def foo(x):
return [make_legal_foo_string(x),sum_up_to(x),x+1]
def bar(x):
return ''.join([str(foo(x))," -- bar !! "])
it's very good style and makes code clear but it can be three times as slow as just writing it literally. It's inescapable for functions that can have side effects but it's actually almost trivial to define some functions that just should literally be replaced with lines of code every time they appear, translate the source code into that and only then compile. Same I think for magic numbers, it doesn't take a lot of time to read from memory but if they're not supposed to be changed then why not just replace every instance of 'magic' with a literal before the code compiles?
Function call overheads are not big; you won't normally notice them. You only see them in this case because your actual code (x*x) is itself so completely trivial. In any real program that does real work, the amount of time spent in function-calling overhead will be negligably small.
(Not that I'd really recommend using foo, identity and square in the example, in any case; they're so trivial it's just as readable to have them inline and they don't really encapsulate or abstract anything.)
if they're not supposed to be changed then why not just replace every instance of 'magic' with a literal before the code compiles?
Because programs are written for to be easy for you to read and maintain. You could replace constants with their literal values, but it'd make the program harder to work with, for a benefit that is so tiny you'll probably never even be able to measure it: the height of premature optimisation.
Encapsulation is about one thing and one thing only: Readability. If you're really so worried about performance that you're willing to start stripping out encapsulated logic, you may as well just start coding in assembly.
Encapsulation also assists in debugging and feature adding. Consider the following: lets say you have a simple game and need to add code that depletes the players health under some circumstances. Easy, yes?
def DamagePlayer(dmg):
player.health -= dmg;
This IS very trivial code, so it's very tempting to simply scatter "player.health -=" everywhere. But what if later you want to add a powerup that halves damage done to the player while active? If the logic is still encapsulated, it's easy:
def DamagePlayer(dmg):
if player.hasCoolPowerUp:
player.health -= dmg / 2
else
player.health -= dmg
Now, consider if you had neglected to encapulate that bit of logic because of it's simplicity. Now you're looking at coding the same logic into 50 different places, at least one of which you are almost certain to forget, which leads to weird bugs like: "When player has powerup all damage is halved except when hit by AlienSheep enemies..."
Do you want to have problems with Alien Sheep? I don't think so. :)
In all seriousness, the point I'm trying to make is that encapsulation is a very good thing in the right circumstances. Of course, it's also easy to over-encapsulate, which can be just as problematic. Also, there are situations where the speed really truly does matter (though they are rare), and that extra few clock cycles is worth it. About the only way to find the right balance is practice. Don't shun encapsulation because it's slower, though. The benefits usually far outweigh the costs.
I don't know how good python compilers are, but the answer to this question for many languages is that the compiler will optimize calls to small procedures / functions / methods by inlining them. In fact, in some language implementations you generally get better performance by NOT trying to "micro-optimize" the code yourself.
What you are talking about is the effect of inlining functions for gaining efficiency.
It is certainly true in your Python example, that encapsulation hurts performance. But there are some counter example to it:
In Java, defining getter&setter instead of defining public member variables does not result in performance degradation as the JIT inline the getters&setters.
sometimes calling a function repetedly may be better than performing inlining as the code executed may then fit in the cache. Inlining may cause code explosion...
Figuring out what to make into a function and what to just include inline is something of an art. Many factors (performance, readability, maintainability) feed into the equation.
I actually find your example kind of silly in many ways - a function that just returns it's argument? Unless it's an overload that's changing the rules, it's stupid. A function to square things? Again, why bother. Your function 'foo' should probably return a string, so that it can be used directly:
''.join(foo(x)," -- bar !! "])
That's probably a more correct level of encapsulation in this example.
As I say, it really depends on the circumstances. Unfortunately, this is the sort of thing that doesn't lend itself well to examples.
IMO, this is related to Function Call Costs. Which are negligible usually, but not zero. Splitting the code in a lot of very small functions may hurt. Especially in interpreted languages where full optimization is not available.
Inlining functions may improve performance but it may also deteriorate. See, for example, C++ FQA Lite for explanations (“Inlining can make code faster by eliminating function call overhead, or slower by generating too much code, causing instruction cache misses”). This is not C++ specific. Better leave optimizations for compiler/interpreter unless they are really necessary.
By the way, I don't see a huge difference between two versions:
$ python bench.py
fine-grained function decomposition: 5.46632194519
one-liner: 4.46827578545
$ python --version
Python 2.5.2
I think this result is acceptable. See bench.py in the pastebin.
There is a performance hit for using functions, since there is the overhead of jumping to a new address, pushing registers on the stack, and returning at the end. This overhead is very small, however, and even in peformance critial systems worrying about such overhead is most likely premature optimization.
Many languages avoid these issues in small frequenty called functions by using inlining, which is essentially what you do above.
Python does not do inlining. The closest thing you can do is use macros to replace the function calls.
This sort of performance issue is better served by another language, if you need the sort of speed gained by inlining (mostly marginal, and sometimes detremental) then you need to consider not using python for whatever you are working on.
There is a good technical reason why what you suggested is impossible. In Python, functions, constants, and everything else are accessible at runtime and can be changed at any time if necessary; they could also be changed by outside modules. This is an explicit promise of Python and one would need some extremely important reasons to break it.
For example, here's the common logging idiom:
# beginning of the file xxx.py
log = lambda *x: None
def something():
...
log(...)
...
(here log does nothing), and then at some other module or at the interactive prompt:
import xxx
xxx.log = print
xxx.something()
As you see, here log is modified by completely different module --- or by the user --- so that logging now works. That would be impossible if log was optimized away.
Similarly, if an exception was to happen in make_legal_foo_string (this is possible, e.g. if x.__str__() is broken and returns None) you'd be hit with a source quote from a wrong line and even perhaps from a wrong file in your scenario.
There are some tools that in fact apply some optimizations to Python code, but I don't think of the kind you suggested.

Categories

Resources