On Thu, Sep 29, 2016 at 09:24:51PM -0500, boB Stepp wrote: > Testing output of print functions (Py 3). First off, is it worth it to do so?
Unless you are writing tests for the Python language itself, you can assume that print() itself is working. You should test functions that call print: call the function (or method) and see that it does print what you expect. But, in general, you should not intermingle *calculation* and *output*. There may be a few examples, but functions should do one, or the other, not both. This makes it easy to reason about, re-use, and test, both functions. For example, suppose you have a function that takes a single string, formats it in some way, and then displays it in a dialog box. You should split that into two: - take a string and format it; - take a formatted string and display it. Same applies to print, writing to log files, or writing output to any other file. > Second, it seems that prints are often intermingled with the main > logic of a function and only serve to pass on a message to the user. Yeah, you normally shouldn't do that. Imagine if every time you called len(something), the len function was chatty and decided to print something. It would make it really hard to print anything where len() is involved as part of the calculation. Say I want to print a formatted table: -------- -------- -------- COLUMN 1 COLUMN 2 COLUMN 3 -------- -------- -------- alpha second gamma letter -------- -------- -------- but got something like: hi this is len I just wanted to let you know I'm working hard -------- hi this is len I just wanted to let you know I'm working hard -------- hi this is len I just wanted to let you know I'm working hard -------- hi this is len I just wanted to let you know I'm working hard COLUMN 1 hi this is len oops something went wrong but that's okay I fixed it COLUMN 2 hi this is len I just wanted to let you know I'm working really hard you ought to be grateful okay COLUMN 3 hi this is len I just wanted to let you know I'm working hard -------- hi this is len ... etc. Chatty functions are *the worst*, unless they are specifically intended for reporting and output. Don't mix calculation and output. Or rather, its okay to mix them, provided you have *at least* two separate functions: (1) function that does the calculation; (2) function that calls (1) and then does the output and preferably three: (1) function that does the calculation; (2) function that does the output; (3) function that calls (1) and then (2) If (1) and (2) are well-designed, then (3) is so trivial it needs no tests: def main(): x = calculate(stuff) report(x) but of course it's not always that simple. Nevertheless, that's the ideal you should aim for. [...] > def right_justify(a_string): > '''This fucntion will take the string, "a_string", and right justify it by > padding it with spaces until its last character falls in column 70 of the > display. The padded string will be returned.''' > > if len(a_string) <= 70: > num_pad_spcs = 70 - len(a_string) > return (' ' * num_pad_spcs) + a_string > else: > print("The string has too many characters (> 70)!") > print("Only a partial, 70 character line will be returned.") > return a_string[:70] Too chatty! It mixed output and calculation. Instead, you should just document what the function does ("pads or truncates the string to exactly 70 characters") and leave it at that, or if you must report on what it is doing, consider: - print warning messages to stderr instead of stdout; - write warnings to a log file; - use the warnings module: import warnings warnings.warn("unable to pad string, as it is too long; truncating instead") - raise an exception and stop processing. [...] > So (Even though this is a simple > exercise.) should I test the prints? If you don't test it, how do you know it works? > Anyway, it would seem that the only way to capture the output of a > print is to redirect the stdout to something I can capture and compare > against. Googling brings up some people doing something with mock > objects, some redirecting to a string buffer, some to a file, some to > other things. What, in your opinion(s), is the cleanest way to handle > this? I find that using stringIO is the simplest and most obvious way to do it, although I don't have a lot of experience with the mock objects. -- Steve _______________________________________________ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor