Unit testing is an important part of an overall testing−centric development strategy. If you write unit tests, it is
important to write them early (preferably before writing the code that they test), and to keep them updated as code and
requirements change. Unit testing is not a replacement for higher−level functional or system testing, but it is important
in all phases of development:
• Before writing code, it forces you to detail your requirements in a useful fashion.
• While writing code, it keeps you from over−coding. When all the test cases pass, the function is complete.
• When refactoring code, it assures you that the new version behaves the same way as the old version.
• When maintaining code, it helps you cover your ass when someone comes screaming that your latest change
broke their old code. ("But sir, all the unit tests passed when I checked it in...")
• When writing code in a team, it increases confidence that the code you're about to commit isn't going to break
other peoples' code, because you can run their unittests first. (I've seen this sort of thing in code sprints. A
team breaks up the assignment, everybody takes the specs for their task, writes unit tests for it, then shares
their unit tests with the rest of the team. That way, nobody goes off too far into developing code that won't
play well with others.)
Coding this way does not make fixing bugs any easier. Simple bugs (like this one) require simple test cases; complex
bugs will require complex test cases. In a testing−centric environment, it may seem like it takes longer to fix a bug,
since you need to articulate in code exactly what the bug is (to write the test case), then fix the bug itself. Then if the
test case doesn't pass right away, you need to figure out whether the fix was wrong, or whether the test case itself has a
bug in it. However, in the long run, this back−and−forth between test code and code tested pays for itself, because it
makes it more likely that bugs are fixed correctly the first time. Also, since you can easily re−run all the test cases
along with your new one, you are much less likely to break old code when fixing new code. Today's unit test is
tomorrow's regression test.
Unit testing is a powerful concept which, if properly implemented, can both reduce maintenance costs and increase
flexibility in any long−term project. It is also important to understand that unit testing is not a panacea, a Magic
Problem Solver, or a silver bullet. Writing good test cases is hard, and keeping them up to date takes discipline
(especially when customers are screaming for critical bug fixes). Unit testing is not a replacement for other forms of
testing, including functional testing, integration testing, and user acceptance testing. But it is feasible, and it does
work, and once you've seen it work, you'll wonder how you ever got along without it.
This chapter covered a lot of ground, and much of it wasn't even Python−specific. There are unit testing frameworks
for many languages, all of which require you to understand the same basic concepts:
• Designing test cases that are specific, automated, and independent
• Writing test cases before the code they are testing
• Writing tests that test good input and check for proper results
• Writing tests that test bad input and check for proper failures
• Writing and updating test cases to illustrate bugs or reflect new requirements
• Refactoring mercilessly to improve performance, scalability, readability, maintainability, or whatever other
−ility you're lacking
Additionally, you should be comfortable doing all of the following Python−specific things:
• Subclassing unittest.TestCase and writing methods for individual test cases
• Using assertEqual to check that a function returns a known value
• Using assertRaises to check that a function raises a known exception
• Calling unittest.main() in your if __name__ clause to run all your test cases at once
• Running unit tests in verbose or regular mode
Comments
Post a Comment
https://gengwg.blogspot.com/