From: Maximilian Friedersdorff Date: Wed, 13 Mar 2019 20:11:35 +0000 (+0000) Subject: Add README that outlines unittesting X-Git-Url: https://git.friedersdorff.com/?a=commitdiff_plain;p=max%2Fpython_unittesting.git Add README that outlines unittesting --- diff --git a/README.pdf b/README.pdf new file mode 100644 index 0000000..e59d404 --- /dev/null +++ b/README.pdf @@ -0,0 +1,727 @@ +%PDF-1.4 +%“Œ‹ž ReportLab Generated PDF document http://www.reportlab.com +1 0 obj +<< +/F1 2 0 R /F2 3 0 R /F3 4 0 R /F4 5 0 R /F5 6 0 R /F6 9 0 R +>> +endobj +2 0 obj +<< +/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font +>> +endobj +3 0 obj +<< +/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font +>> +endobj +4 0 obj +<< +/BaseFont /Courier-Bold /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font +>> +endobj +5 0 obj +<< +/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F4 /Subtype /Type1 /Type /Font +>> +endobj +6 0 obj +<< +/BaseFont /Courier-Oblique /Encoding /WinAnsiEncoding /Name /F5 /Subtype /Type1 /Type /Font +>> +endobj +7 0 obj +<< +/Contents 19 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 18 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +8 0 obj +<< +/A << +/S /URI /Type /Action /URI (https://projecteuler.net/project/resources/p102_triangles.txt) +>> /Border [ 0 0 0 ] /Rect [ 62.69291 717.0236 209.4129 729.0236 ] /Subtype /Link /Type /Annot +>> +endobj +9 0 obj +<< +/BaseFont /Helvetica-Oblique /Encoding /WinAnsiEncoding /Name /F6 /Subtype /Type1 /Type /Font +>> +endobj +10 0 obj +<< +/Annots [ 8 0 R ] /Contents 20 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 18 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 + /Trans << + +>> /Type /Page +>> +endobj +11 0 obj +<< +/Outlines 13 0 R /PageLabels 21 0 R /PageMode /UseNone /Pages 18 0 R /Type /Catalog +>> +endobj +12 0 obj +<< +/Author () /CreationDate (D:20190313201115+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20190313201115+00'00') /Producer (ReportLab PDF Library - www.reportlab.com) + /Subject (\(unspecified\)) /Title (Unit testing) /Trapped /False +>> +endobj +13 0 obj +<< +/Count 4 /First 14 0 R /Last 17 0 R /Type /Outlines +>> +endobj +14 0 obj +<< +/Dest [ 7 0 R /XYZ 62.69291 439.8236 0 ] /Next 15 0 R /Parent 13 0 R /Title (Why) +>> +endobj +15 0 obj +<< +/Dest [ 7 0 R /XYZ 62.69291 292.8236 0 ] /Next 16 0 R /Parent 13 0 R /Prev 14 0 R /Title (How) +>> +endobj +16 0 obj +<< +/Dest [ 7 0 R /XYZ 62.69291 187.8236 0 ] /Next 17 0 R /Parent 13 0 R /Prev 15 0 R /Title (What) +>> +endobj +17 0 obj +<< +/Dest [ 10 0 R /XYZ 62.69291 705.0236 0 ] /Parent 13 0 R /Prev 16 0 R /Title (Test driven development) +>> +endobj +18 0 obj +<< +/Count 2 /Kids [ 7 0 R 10 0 R ] /Type /Pages +>> +endobj +19 0 obj +<< +/Length 10422 +>> +stream +1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET +q +1 0 0 1 62.69291 741.0236 cm +q +BT 1 0 0 1 0 4 Tm 179.9449 0 Td 24 TL /F2 20 Tf 0 0 0 rg (Unit testing) Tj T* -179.9449 0 Td ET +Q +Q +q +1 0 0 1 62.69291 695.0236 cm +q +BT 1 0 0 1 0 26 Tm 3.17248 Tw 12 TL /F1 10 Tf 0 0 0 rg (Unit testing means testing small portions \(individual functions, modules, classes\) of your program,) Tj T* 0 Tw .411654 Tw (independently of the rest, in an automated fashion. The tests usually consist of a set of functions that are) Tj T* 0 Tw (distributed along with the rest of the source code.) Tj T* ET +Q +Q +q +1 0 0 1 62.69291 641.0236 cm +q +0 0 0 rg +BT 1 0 0 1 0 38 Tm /F1 10 Tf 12 TL 2.051654 Tw (Each test will call part of the main source code, usually with some dummy data, and verify that the) Tj T* 0 Tw -0.101512 Tw (behaviour of the code is as expected. It is typical to test a few edge cases and boundary conditions in such) Tj T* 0 Tw .848735 Tw (a way. A primitive attempt to test a python function, that implements a mathematical function might look) Tj T* 0 Tw (like this:) Tj T* ET +Q +Q +q +1 0 0 1 62.69291 451.8236 cm +q +q +1 0 0 1 0 0 cm +q +1 0 0 1 6.6 6.6 cm +q +.662745 .662745 .662745 RG +.5 w +.960784 .960784 .862745 rg +n -6 -6 468.6898 180 re B* +Q +q +.960784 .960784 .862745 rg +n 0 156 18 12 re f* +.960784 .960784 .862745 rg +n 24 156 72 12 re f* +.960784 .960784 .862745 rg +n 96 156 6 12 re f* +.960784 .960784 .862745 rg +n 102 156 6 12 re f* +.960784 .960784 .862745 rg +n 108 156 12 12 re f* +.960784 .960784 .862745 rg +n 18 144 432 12 re f* +.960784 .960784 .862745 rg +n 0 132 306 12 re f* +.960784 .960784 .862745 rg +n 18 120 24 12 re f* +.960784 .960784 .862745 rg +n 48 120 24 12 re f* +.960784 .960784 .862745 rg +n 78 120 36 12 re f* +.960784 .960784 .862745 rg +n 120 120 12 12 re f* +.960784 .960784 .862745 rg +n 132 120 6 12 re f* +.960784 .960784 .862745 rg +n 138 120 18 12 re f* +.960784 .960784 .862745 rg +n 18 108 36 12 re f* +.960784 .960784 .862745 rg +n 60 108 18 12 re f* +.960784 .960784 .862745 rg +n 78 108 6 12 re f* +.960784 .960784 .862745 rg +n 84 108 6 12 re f* +.960784 .960784 .862745 rg +n 90 108 6 12 re f* +.960784 .960784 .862745 rg +n 96 108 6 12 re f* +.960784 .960784 .862745 rg +n 102 108 12 12 re f* +.960784 .960784 .862745 rg +n 114 108 6 12 re f* +.960784 .960784 .862745 rg +n 120 108 18 12 re f* +.960784 .960784 .862745 rg +n 138 108 12 12 re f* +.960784 .960784 .862745 rg +n 0 84 18 12 re f* +.960784 .960784 .862745 rg +n 24 84 96 12 re f* +.960784 .960784 .862745 rg +n 120 84 18 12 re f* +.960784 .960784 .862745 rg +n 18 72 36 12 re f* +.960784 .960784 .862745 rg +n 60 72 72 12 re f* +.960784 .960784 .862745 rg +n 132 72 6 12 re f* +.960784 .960784 .862745 rg +n 138 72 12 12 re f* +.960784 .960784 .862745 rg +n 150 72 6 12 re f* +.960784 .960784 .862745 rg +n 162 72 12 12 re f* +.960784 .960784 .862745 rg +n 180 72 6 12 re f* +.960784 .960784 .862745 rg +n 0 48 18 12 re f* +.960784 .960784 .862745 rg +n 24 48 90 12 re f* +.960784 .960784 .862745 rg +n 114 48 18 12 re f* +.960784 .960784 .862745 rg +n 18 36 36 12 re f* +.960784 .960784 .862745 rg +n 60 36 72 12 re f* +.960784 .960784 .862745 rg +n 132 36 6 12 re f* +.960784 .960784 .862745 rg +n 138 36 6 12 re f* +.960784 .960784 .862745 rg +n 144 36 6 12 re f* +.960784 .960784 .862745 rg +n 156 36 12 12 re f* +.960784 .960784 .862745 rg +n 174 36 6 12 re f* +.960784 .960784 .862745 rg +n 0 12 18 12 re f* +.960784 .960784 .862745 rg +n 24 12 150 12 re f* +.960784 .960784 .862745 rg +n 174 12 18 12 re f* +.960784 .960784 .862745 rg +n 18 0 36 12 re f* +.960784 .960784 .862745 rg +n 60 0 72 12 re f* +.960784 .960784 .862745 rg +n 132 0 6 12 re f* +.960784 .960784 .862745 rg +n 138 0 18 12 re f* +.960784 .960784 .862745 rg +n 156 0 6 12 re f* +.960784 .960784 .862745 rg +n 168 0 12 12 re f* +.960784 .960784 .862745 rg +n 186 0 6 12 re f* +.960784 .960784 .862745 rg +n 198 0 6 12 re f* +.960784 .960784 .862745 rg +n 204 0 6 12 re f* +.960784 .960784 .862745 rg +n 216 0 72 12 re f* +.960784 .960784 .862745 rg +n 288 0 6 12 re f* +.960784 .960784 .862745 rg +n 294 0 18 12 re f* +.960784 .960784 .862745 rg +n 312 0 6 12 re f* +.960784 .960784 .862745 rg +n 324 0 12 12 re f* +.960784 .960784 .862745 rg +n 342 0 6 12 re f* +BT 1 0 0 1 0 158 Tm 12 TL /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (calc_deg_sin) Tj 0 0 0 rg (\() Tj 0 0 0 rg (x) Tj 0 0 0 rg (\):) Tj 0 0 0 rg T* ( ) Tj /F5 10 Tf .729412 .129412 .129412 rg ("""This is an elaborate python function that calculates the mathematical) Tj T* ( function f\(x\)=sin\(x\), where x is in degrees. """) Tj /F4 10 Tf 0 0 0 rg T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (from) Tj /F4 10 Tf 0 0 0 rg ( ) Tj /F3 10 Tf 0 0 1 rg (math) Tj /F4 10 Tf 0 0 0 rg ( ) Tj /F3 10 Tf 0 .501961 0 rg (import) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (pi) Tj 0 0 0 rg (,) Tj 0 0 0 rg (sin) Tj 0 0 0 rg T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (return) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (sin) Tj 0 0 0 rg (\() Tj 0 0 0 rg (x) Tj .4 .4 .4 rg (*) Tj 0 0 0 rg (\() Tj 0 0 0 rg (pi) Tj .4 .4 .4 rg (/) Tj .4 .4 .4 rg (189) Tj 0 0 0 rg (\)\)) Tj 0 0 0 rg T* T* /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (test_sin_90_is_1) Tj 0 0 0 rg (\(\):) Tj 0 0 0 rg T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (assert) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (calc_deg_sin) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (90) Tj 0 0 0 rg (\)) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (==) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (1) Tj 0 0 0 rg T* T* /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (test_sin_0_is_0) Tj 0 0 0 rg (\(\):) Tj 0 0 0 rg T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (assert) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (calc_deg_sin) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (0) Tj 0 0 0 rg (\)) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (==) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (0) Tj 0 0 0 rg T* T* /F3 10 Tf 0 .501961 0 rg (def) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 1 rg (test_sin_180_and_360_is_0) Tj 0 0 0 rg (\(\):) Tj 0 0 0 rg T* ( ) Tj /F3 10 Tf 0 .501961 0 rg (assert) Tj /F4 10 Tf 0 0 0 rg ( ) Tj 0 0 0 rg (calc_deg_sin) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (180) Tj 0 0 0 rg (\)) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (==) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (0) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (&) Tj (&) Tj 0 0 0 rg ( ) Tj 0 0 0 rg (calc_deg_sin) Tj 0 0 0 rg (\() Tj .4 .4 .4 rg (360) Tj 0 0 0 rg (\)) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (==) Tj 0 0 0 rg ( ) Tj .4 .4 .4 rg (0) Tj T* ET +Q +Q +Q +Q +Q +q +1 0 0 1 62.69291 418.8236 cm +q +BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Why) Tj T* ET +Q +Q +q +1 0 0 1 62.69291 400.8236 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Unit testing is a useful thing to do for a number of reasons, including \(in no particular order\):) Tj T* ET +Q +Q +q +1 0 0 1 62.69291 394.8236 cm +Q +q +1 0 0 1 62.69291 394.8236 cm +Q +q +1 0 0 1 62.69291 382.8236 cm +0 0 0 rg +BT /F1 10 Tf 12 TL ET +q +1 0 0 1 6 -3 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL 10.5 0 Td (\177) Tj T* -10.5 0 Td ET +Q +Q +q +1 0 0 1 23 -3 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Unit tests document the expected behaviour of your program.) Tj T* ET +Q +Q +q +Q +Q +q +1 0 0 1 62.69291 376.8236 cm +Q +q +1 0 0 1 62.69291 352.8236 cm +0 0 0 rg +BT /F1 10 Tf 12 TL ET +q +1 0 0 1 6 9 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL 10.5 0 Td (\177) Tj T* -10.5 0 Td ET +Q +Q +q +1 0 0 1 23 -3 cm +q +0 0 0 rg +BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL 1.40528 Tw (Unit tests allow you to verify that you did not make unintended changes to the behaviour of your) Tj T* 0 Tw (program when you add features, or change the implementation.) Tj T* ET +Q +Q +q +Q +Q +q +1 0 0 1 62.69291 346.8236 cm +Q +q +1 0 0 1 62.69291 322.8236 cm +0 0 0 rg +BT /F1 10 Tf 12 TL ET +q +1 0 0 1 6 9 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL 10.5 0 Td (\177) Tj T* -10.5 0 Td ET +Q +Q +q +1 0 0 1 23 -3 cm +q +0 0 0 rg +BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL .753516 Tw (Unit tests catch many bugs before your program runs for real \(before you submit the job that takes) Tj T* 0 Tw (multiple days, but crashes right before it prints out the result\).) Tj T* ET +Q +Q +q +Q +Q +q +1 0 0 1 62.69291 316.8236 cm +Q +q +1 0 0 1 62.69291 304.8236 cm +0 0 0 rg +BT /F1 10 Tf 12 TL ET +q +1 0 0 1 6 -3 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL 10.5 0 Td (\177) Tj T* -10.5 0 Td ET +Q +Q +q +1 0 0 1 23 -3 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Unit tests allow you to conveniently play with unfamiliar libraries/apis/modules language features.) Tj T* ET +Q +Q +q +Q +Q +q +1 0 0 1 62.69291 304.8236 cm +Q +q +1 0 0 1 62.69291 271.8236 cm +q +BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (How) Tj T* ET +Q +Q +q +1 0 0 1 62.69291 229.8236 cm +q +0 0 0 rg +BT 1 0 0 1 0 26 Tm /F1 10 Tf 12 TL -0.135662 Tw (Use a test runner. A test runner will find all functions in a file or module that are defined to be tests, and run) Tj T* 0 Tw .754431 Tw (them. It will also give you a convenient output of the result, and some basic statistics. Test runners vary) Tj T* 0 Tw (greatly in their ease of use, flexibility and the usefulness of their output.) Tj T* ET +Q +Q +q +1 0 0 1 62.69291 199.8236 cm +q +BT 1 0 0 1 0 14 Tm .386488 Tw 12 TL /F1 10 Tf 0 0 0 rg (In this case I am using ) Tj /F4 10 Tf 0 0 0 rg (pytest) Tj /F1 10 Tf 0 0 0 rg (. ) Tj /F4 10 Tf 0 0 0 rg (pytest) Tj /F1 10 Tf 0 0 0 rg ( will execute all top level functions in a file that start with ) Tj /F4 10 Tf 0 0 0 rg (test_) Tj /F1 10 Tf 0 0 0 rg (.) Tj T* 0 Tw (You run the tests in a file with ) Tj /F4 10 Tf 0 0 0 rg (pytest) Tj ( ) Tj (FILE) Tj ( ) Tj ([FILE]) Tj ( ) Tj ([FILE]...) Tj /F1 10 Tf 0 0 0 rg (.) Tj T* ET +Q +Q +q +1 0 0 1 62.69291 166.8236 cm +q +BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (What) Tj T* ET +Q +Q +q +1 0 0 1 62.69291 148.8236 cm +q +BT 1 0 0 1 0 2 Tm 12 TL /F1 10 Tf 0 0 0 rg (Look at the examples in this directory. The files staring with ) Tj /F4 10 Tf 0 0 0 rg (<) Tj (somenumber) Tj (>) Tj (_) Tj /F1 10 Tf 0 0 0 rg ( contain tests.) Tj T* ET +Q +Q +q +1 0 0 1 62.69291 130.8236 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (The first file contains some basic tests. Some will fail, some will pass.) Tj T* ET +Q +Q +q +1 0 0 1 62.69291 88.82362 cm +q +BT 1 0 0 1 0 26 Tm 1.282126 Tw 12 TL /F1 10 Tf 0 0 0 rg (The second file contains tests that check if a function called ) Tj /F4 10 Tf 0 0 0 rg (incorrect_ackermann) Tj /F1 10 Tf 0 0 0 rg ( will produce the) Tj T* 0 Tw 2.160542 Tw (expected values for a number of different inputs \(hint: it won't\). Fix any problems that turn up \( the) Tj T* 0 Tw (definition of the ackermann function is at the very bottom of the file that implements it\).) Tj T* ET +Q +Q + +endstream +endobj +20 0 obj +<< +/Length 4562 +>> +stream +1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET +q +1 0 0 1 62.69291 717.0236 cm +q +BT 1 0 0 1 0 38 Tm .472126 Tw 12 TL /F1 10 Tf 0 0 0 rg (The third file contains tests for two functions, ) Tj /F4 10 Tf 0 0 0 rg (collatz) Tj /F1 10 Tf 0 0 0 rg ( and ) Tj /F4 10 Tf 0 0 0 rg (longest_collatz) Tj /F1 10 Tf 0 0 0 rg (. These return the length) Tj T* 0 Tw .959986 Tw (of the collatz sequence for a particular integer, and the integer with the longest collatz sequence that is) Tj T* 0 Tw .25832 Tw (smaller than the input integer. Implement these functions so that they pass the tests. This is based on the) Tj T* 0 Tw 0 0 .501961 rg (Euler Project problem number 14) Tj T* ET +Q +Q +q +1 0 0 1 62.69291 684.0236 cm +q +BT 1 0 0 1 0 3.5 Tm 21 TL /F2 17.5 Tf 0 0 0 rg (Test driven development) Tj T* ET +Q +Q +q +1 0 0 1 62.69291 630.0236 cm +q +0 0 0 rg +BT 1 0 0 1 0 38 Tm /F1 10 Tf 12 TL 1.961235 Tw (Test driven development is a practice, whereby one first writes the tests that fully describe a certain) Tj T* 0 Tw 1.87881 Tw (feature \(or test for a particular bug\). These tests should all initially fail. Then one writes the simplest) Tj T* 0 Tw .537045 Tw (implementation that will make these tests pass. Doing things in this order forces one to be very thorough) Tj T* 0 Tw (with writing tests. It is a lot of work however.) Tj T* ET +Q +Q +q +1 0 0 1 62.69291 588.0236 cm +q +BT 1 0 0 1 0 26 Tm .04881 Tw 12 TL /F1 10 Tf 0 0 0 rg (Pick your favourite algorithm \(ideally one ) Tj /F6 10 Tf (you) Tj /F1 10 Tf ( can implement in python\). Write some tests for a function \(or) Tj T* 0 Tw 1.864983 Tw (functions\) that implements that algorithm, then implement that algorithm to pass the tests that you've) Tj T* 0 Tw (written.) Tj T* ET +Q +Q +q +1 0 0 1 62.69291 570.0236 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Some good algorithms to tests with might be:) Tj T* ET +Q +Q +q +1 0 0 1 62.69291 564.0236 cm +Q +q +1 0 0 1 62.69291 564.0236 cm +Q +q +1 0 0 1 62.69291 552.0236 cm +0 0 0 rg +BT /F1 10 Tf 12 TL ET +q +1 0 0 1 6 -3 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL 10.5 0 Td (\177) Tj T* -10.5 0 Td ET +Q +Q +q +1 0 0 1 23 -3 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Binary search) Tj T* ET +Q +Q +q +Q +Q +q +1 0 0 1 62.69291 546.0236 cm +Q +q +1 0 0 1 62.69291 534.0236 cm +0 0 0 rg +BT /F1 10 Tf 12 TL ET +q +1 0 0 1 6 -3 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL 10.5 0 Td (\177) Tj T* -10.5 0 Td ET +Q +Q +q +1 0 0 1 23 -3 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Your favourite sorting algorithm) Tj T* ET +Q +Q +q +Q +Q +q +1 0 0 1 62.69291 528.0236 cm +Q +q +1 0 0 1 62.69291 516.0236 cm +0 0 0 rg +BT /F1 10 Tf 12 TL ET +q +1 0 0 1 6 -3 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL 10.5 0 Td (\177) Tj T* -10.5 0 Td ET +Q +Q +q +1 0 0 1 23 -3 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (DFS/BFS) Tj T* ET +Q +Q +q +Q +Q +q +1 0 0 1 62.69291 510.0236 cm +Q +q +1 0 0 1 62.69291 498.0236 cm +0 0 0 rg +BT /F1 10 Tf 12 TL ET +q +1 0 0 1 6 -3 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL 10.5 0 Td (\177) Tj T* -10.5 0 Td ET +Q +Q +q +1 0 0 1 23 -3 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Calculating the edit distance between two strings) Tj T* ET +Q +Q +q +Q +Q +q +1 0 0 1 62.69291 492.0236 cm +Q +q +1 0 0 1 62.69291 480.0236 cm +0 0 0 rg +BT /F1 10 Tf 12 TL ET +q +1 0 0 1 6 -3 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL 10.5 0 Td (\177) Tj T* -10.5 0 Td ET +Q +Q +q +1 0 0 1 23 -3 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Kernel convolution) Tj T* ET +Q +Q +q +Q +Q +q +1 0 0 1 62.69291 474.0236 cm +Q +q +1 0 0 1 62.69291 462.0236 cm +0 0 0 rg +BT /F1 10 Tf 12 TL ET +q +1 0 0 1 6 -3 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL 10.5 0 Td (\177) Tj T* -10.5 0 Td ET +Q +Q +q +1 0 0 1 23 -3 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Maximum parsimony) Tj T* ET +Q +Q +q +Q +Q +q +1 0 0 1 62.69291 456.0236 cm +Q +q +1 0 0 1 62.69291 444.0236 cm +0 0 0 rg +BT /F1 10 Tf 12 TL ET +q +1 0 0 1 6 -3 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL 10.5 0 Td (\177) Tj T* -10.5 0 Td ET +Q +Q +q +1 0 0 1 23 -3 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Calculate the Levenshtein or edit distance between two strings) Tj T* ET +Q +Q +q +Q +Q +q +1 0 0 1 62.69291 438.0236 cm +Q +q +1 0 0 1 62.69291 414.0236 cm +0 0 0 rg +BT /F1 10 Tf 12 TL ET +q +1 0 0 1 6 9 cm +q +0 0 0 rg +BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL 10.5 0 Td (\177) Tj T* -10.5 0 Td ET +Q +Q +q +1 0 0 1 23 -3 cm +q +0 0 0 rg +BT 1 0 0 1 0 14 Tm /F1 10 Tf 12 TL 1.266098 Tw (Calculating the value of the fibonacci sequence, the sum of integers up to n, the first n primes or) Tj T* 0 Tw (some other such mathematical function) Tj T* ET +Q +Q +q +Q +Q +q +1 0 0 1 62.69291 414.0236 cm +Q + +endstream +endobj +21 0 obj +<< +/Nums [ 0 22 0 R 1 23 0 R ] +>> +endobj +22 0 obj +<< +/S /D /St 1 +>> +endobj +23 0 obj +<< +/S /D /St 2 +>> +endobj +xref +0 24 +0000000000 65535 f +0000000073 00000 n +0000000154 00000 n +0000000261 00000 n +0000000373 00000 n +0000000483 00000 n +0000000588 00000 n +0000000701 00000 n +0000000906 00000 n +0000001119 00000 n +0000001234 00000 n +0000001458 00000 n +0000001564 00000 n +0000001834 00000 n +0000001908 00000 n +0000002012 00000 n +0000002129 00000 n +0000002247 00000 n +0000002372 00000 n +0000002439 00000 n +0000012914 00000 n +0000017528 00000 n +0000017578 00000 n +0000017612 00000 n +trailer +<< +/ID +[<0e78adeec461ba0fa6ed6f6f883a9461><0e78adeec461ba0fa6ed6f6f883a9461>] +% ReportLab generated PDF document -- digest (http://www.reportlab.com) + +/Info 12 0 R +/Root 11 0 R +/Size 24 +>> +startxref +17646 +%%EOF diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..5c5c8ea --- /dev/null +++ b/README.rst @@ -0,0 +1,111 @@ +Unit testing +============ + +Unit testing means testing small portions (individual functions, modules, +classes) of your program, independently of the rest, in an automated fashion. +The tests usually consist of a set of functions that are distributed along with +the rest of the source code. + +Each test will call part of the main source code, usually with some dummy data, +and verify that the behaviour of the code is as expected. It is typical to test +a few edge cases and boundary conditions in such a way. A primitive attempt +to test a python function, that implements a mathematical function might look +like this: + +.. code-block:: python + + def calc_deg_sin(x): + """This is an elaborate python function that calculates the mathematical + function f(x)=sin(x), where x is in degrees. """ + from math import pi,sin + return sin(x*(pi/189)) + + def test_sin_90_is_1(): + assert calc_deg_sin(90) == 1 + + def test_sin_0_is_0(): + assert calc_deg_sin(0) == 0 + + def test_sin_180_and_360_is_0(): + assert calc_deg_sin(180) == 0 && calc_deg_sin(360) == 0 + +Why +--- + +Unit testing is a useful thing to do for a number of reasons, including (in no +particular order): + +- Unit tests document the expected behaviour of your program. +- Unit tests allow you to verify that you did not make unintended changes to the + behaviour of your program when you add features, or change the implementation. +- Unit tests catch many bugs before your program runs for real (before you submit + the job that takes multiple days, but crashes right before it prints out the + result). +- Unit tests allow you to conveniently play with unfamiliar libraries/apis/modules + language features. + +How +--- + +Use a test runner. A test runner will find all functions in a file or module +that are defined to be tests, and run them. It will also give you a convenient +output of the result, and some basic statistics. Test runners vary greatly in +their ease of use, flexibility and the usefulness of their output. + +In this case I am using ``pytest``. ``pytest`` will execute all top level +functions in a file that start with ``test_``. You run the tests in a file with +``pytest FILE [FILE] [FILE]...``. + +What +---- +Look at the examples in this directory. The files staring with +``_`` contain tests. + +The first file contains some basic tests. +Some will fail, some will pass. + +The second file contains tests that check if +a function called ``incorrect_ackermann`` will produce the expected values for +a number of different inputs (hint: it won't). Fix any problems that turn up ( +the definition of the ackermann function is at the very bottom of the file that +implements it). + +The third file contains tests for two functions, ``collatz`` and ``longest_collatz``. +These return the length of the collatz sequence for a particular integer, and the +integer with the longest collatz sequence that is smaller than the input integer. +Implement these functions so that they pass the tests. This is based on the +`Euler Project problem number 14`_ + +Test driven development +----------------------- + +Test driven development is a practice, whereby one first writes the tests that +fully describe a certain feature (or test for a particular bug). These tests +should all initially fail. Then one writes the simplest implementation that will +make these tests pass. Doing things in this order forces one to be very thorough +with writing tests. It is a lot of work however. + +Pick your favourite algorithm (ideally one *you* can implement in python). Write +some tests for a function (or functions) that implements that algorithm, then +implement that algorithm to pass the tests that you've written. + +Some good algorithms to tests with might be: + +- Binary search +- Your favourite sorting algorithm +- DFS/BFS +- Calculating the edit distance between two strings +- Kernel convolution +- Maximum parsimony +- Calculate the Levenshtein or edit distance between two strings +- Calculating the value of the fibonacci sequence, the sum of integers up to n, + the first n primes or some other such mathematical function + + + + + + + + +.. _Euler Project problem number 14: https://projecteuler.net/project/resources/p102_triangles.txt