2
\$\begingroup\$

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?

\$\endgroup\$
1
\$\begingroup\$

I prefer Option A over Option B. While you do then end up resting both the port and the adapter in one go, the port and adapter together constitute the unit you are trying to test: the piece of code that allows you to manipulate the widget in question.

Option B, in my opinion, is perhaps a tad too granular.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.