###################################### Getting Started with Automated Testing ###################################### :Date: 2013-03-16 :Speaker: Carl Meyer :Slides: http://oddbird.net/start-testing-preso What is it? =========== + Untested code is legacy code + This guy LOVES to test! + Even the slides have tests! Whoa, man. Let's Make a Thing! =================== Git recommendations engine -------------------------- + gitrecs.py - similarity() - Return similarity score for two users + Testing things manually gets old fast. - Updating your tests with your revisions gets older faster. - Repetitive and boring... Therefore you skip them. - Not easily-reproducable - Error-prone + ... And you ship broken code because it's not fully tested Automate a test! ---------------- + test_gitrecs.py - from gitrecs import similarity + ``assert similarity(blah1, blah2) == expected_value`` + Got ZeroDivisionError - New test: ``assert similarity({}, {}) == 0.0`` + pytest - Test runner - Knows how to discover & run test (if name is ``test_foo.py`` Test runners ============ + py.test + Nose + unittest (stdlib) + twisted.trial + zope.testrunner Why Tests? ========== + So you knw when your code is broken. + Help later devs grok your code. + Improve the design of your code. + Testing things that rely on network information is hard - You must fake it! (Mock objects with boilerplated data?) - These tests are less clear + Testable code is maintainable - The less a function knows about the world... - The more robust it is against changes - See: Principal of Least Knowledge - Therefore: The less of the world you have to setup to test it Types of Tests ============== + Doctest is not recommended - Fragile - No isolation - Harder to maintain - Good for testing your documentation, but that's it! Unit Tests ---------- + Test one "unit" of code (func/method) + Small & fast + Focused: Informative failures + Con: Require more refactoring w/ changes:w Integration Tests ----------------- + Test that components talk to each other correctly + Slower, exercises more code. + "Black box" tests aka "system", "functional", or "acceptance" tests. Workflows for Testing ===================== + Make it a habit, not a chore. + Testing first is more fun (objective!) Adding a feature ---------------- + Write an end-to-end test describing the working feature. + Start implementation from the outside in. + Program by wish: "I wish I had a thing that did..." - Stub it. + For each stubbed func write tests describing how it *should* work. The "spike" workflow -------------------- + Write exploratory code to figure out a problem + Strict TDD says delete your spikes and rewrite them test-first... + Try it... It can be illuminating. Retrofitting workflow --------------------- + Codebase with out test? (*cough* `Trigger `_) - Probably not structured for tests. Oh, bother. + Start /w system tests. + Use code coverage as a metric for testable areas. - ``pip install coverage`` See Also ======== + tox - test your lib accross multiple Python versions/configs + mock - easily create fakes for testing (included in Python 3.3) + WebTest - request/response for WSGI apps + Selenium - browser automation + http://pytest.org Coding with Tests ================= + Fun and satisfying! + Replaces fear w/ moxy. + Results in better code.