I'm trying to test my implementation of ports-and-adaptors for tkinter.
Assume I have a tkinter Entry
declared like so:
entry = tk.Entry(container)
entry.value = tk.StringVar()
entry.configure(textvariable=entry.value)
In module ports.py I have a simple function to set the value:
def set_widget_value(widget, value):
widget.value.set(value)
In module adaptors.py I have a class that provides domain specific method to set the value:
from myapp.gui.ports import set_widget_value
class EntryAdaptor(object):
"""Wraps a Tkinter Entry widget."""
def __init__(self, entry):
self._entry = entry
def set_value(self, value):
set_widget_value(self._entry, value)
To test my adaptor layer I have come up with two options.
Option A
import unittest
import unittest.mock as mock
from myapp.gui.adaptors import EntryAdaptor
class EntryAdaptorTests(unittest.TestCase):
def test_should_set_value_of_entry(self):
entry = mock.Mock()
adaptor = EntryAdaptor(entry)
text = 'some user-typed text'
adaptor.set_value(text)
entry.value.set.\
assert_called_once_with(text)
Option B
import unittest
import unittest.mock as mock
class EntryAdaptorTests(unittest.TestCase):
def test_should_set_value_of_entry(self):
entry = mock.Mock()
with mock.patch('myapp.gui.ports.set_widget_value') as set_widget_value:
from myapp.gui.adaptors import EntryAdaptor
adaptor = EntryAdaptor(entry)
text = 'some user-typed text'
adaptor.set_value(text)
set_widget_value.assert_called_once_with(entry, text)
In Option A, I'm looking at the mocked tkinter.Entry
object and checking if it was called as expected; this has the disadvantage of mocking the external tkinter API.
In Option B, I mock my set_widget_value()
function and check if it was called as expected; this has the disadvantage of performing the import of EntryAdaptor
within the test_should_set_value_of_entry()
method because of the dependency of adaptors.py to ports.py.
Which is the best way to perform the test: A, B or something completely different?