On 6/13/2013 12:42 PM, Todd V. Rovito wrote:
On Jun 13, 2013, at 1:32 AM, Terry Reedy <[email protected]> wrote:
For instance,
configSectionNameDialog.GetCfgSectionNameDialog.name_ok (altered
spelling) checks user input and returns the stripped version. It
gets the input from a StringVar and displays error messages with
tkMessageBox.showerror. A messagebox is obvious a gui element, but
so are Variable subclass instances, because they require a Tk
master object. (Since Variables are not visible widgets, this
surprised me).
Module mock_tk, used in test_name_dialog, has replacements for
Variables and messageboxes. See the patch for issue 18130 or the
new files in idle_test. Since tkMessageBox is a
configSectionNameDialog global name (bound to a module), it is
replaced in the module itself (for the duration of the test) by a
mock messagebox, whose instances simply record the inputs for later
examination. (This is colloquially called monkeypatching.) The fact
that module functions and class methods can be accessed and called
the same way means the module can be replaced by a class.
This test module is based on both thought and experiment. Here is the
thought part. A method uses three namespaces: local, attribute, and
module global. A different procedure is needed for each to affect what
the method reads (setup) and read what the method does (test).
We affect the local namespace by passing arguments but do not directly
change bindings in the body; we then look at the return.
We can control the part of the attribute namespace that a method reads
by embedding the method in a customized dummy (or mock) version of its
class. (Because Python methods are functions, this is trivial. For 2.7,
'.im_func' must be added.) We can similarly read attributes to see what
change the method made.
Because func.__globals__ is read-only, we can only change what the
method sees by patching the module in which it is defined. But we
generally only need to replace imported gui objects, like
tkinter.messagebox (tkMessageBox).
I looked at issue 18130 closely and it mostly makes sense to me
I hope the above explains it even better.
but I was surprised you didn't use unittest.mock in mock_tk.
Given how easy it was to do what I laid out above, I did not see any
need to re-investigate mock at the time that I wrote that test. "Do the
minimun needed to make the test pass." The next test, test_grep, has not
required anything new.
Before mock was added, I read both the doc chapter and the howto. What I
remember is that it is a pretty heavy-duty module for heavy-duty
problems and too much to absorb and master in an afternoon. I have never
used it.
> Does that mean I can assume for other unit tests that we shouldn't
> use unittest.mock
No. It means that if I apply a patch, I would like there to be a reason
to use it beyond the fact that it exists: like readability or
performance increase.
Analogy: itertools is a great module, but I do not necessarily use it
every time I possibly could. And I am more comfortable using builtin and
itertools iterators after having written and run some myself, so I
understand their operation.
> and monkey patching without mock is ok?
It is ok with me. Why not?
I was cognizant of the need to restore the module before exiting the
test. While probably not needed for this module for the test suite,
restoration *is* needed to run the human gui-visible test after the
automated test. (And if a test were to patch a module such as Editor
that is used in many tests, restoration would be needed even for testing.)
The regrtest test runner treats test modules as the unit for test order
randomization and parallelization with multiple processses. If
Test_class.test_method were the unit for such, then a with statement
wrapping the body of a method would be better than what I did.
Using mock in the past seems like it would give us more options than monkey
patching.
I imagine it does ;-). If you want, suggest improvements based on your
experience.
--
Terry Jan Reedy
_______________________________________________
IDLE-dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/idle-dev