The Tale of trimZeros, or UI: Detail Counts

Continuing in a similar vein to my last post (Dragging Roads), another post on UI code. My CS professor has a few labs that we come back to and build on over the course of the year — one of these is an RPN calculator, which we built last semester (and which has become a coding kata for me in several languages), and which we are now developing GUIs for: first with Swing, and now on Android. (Spoilers: no, nothing in today’s post is actually related to Android UI in particular.)

Although the calculator code itself works on doubles, as you would expect, the UI stores the currently entered number as a String. This seems like a dirty hack (it is), but in order to support floating point entry and a backspace key, it’s the simplest means. The alternative, using exponentiation to place each digit in the right place on a double, has more nasty corner cases than are worth dealing with in the timeframe of a lab exercise. This String-backed UI has some consequences, namely that the user can input values that are either (a) invalid or (b) look wrong. Today’s post examines (b) — more specifically, removing unnecessary leading zeros.

Trimming zeros is easy, right?

private void trimZeros() {
    if (currentEntry.length() < 1) return;
    
    int i;

    for (i = 0; currentEntry.length() > i 
             && currentEntry.charAt(i) == '0'; ++i);

    currentEntry = currentEntry.substring(i);
}

(currentEntry is the String used to store the current entered number.)

This is somewhat more “clever” than it probably should be, but it’s still straightforward code — find the index of the first non-‘0’ character in the currentEntry string, then lop off the zeros all at once with a substring call.

However, it doesn’t quite preform how we want:

|  Input  |  Output  |
+---------+----------+
|  "0123" |   "123"  |
| "0.123" |  ".123"  |
|   "000" |      ""  |
|     "0" |      ""  |

Leading zeros on integers are trimmed properly, but zero values are reduced to empty strings, and decimal values lose the leading zero. With the exception of the empty strings, these are perfectly valid — feed them into #parseDouble and we’ll get the right double out, but we can do better.

private void trimZeros() {
    if (currentEntry.length() < 1) return;
    
    int i;
    int decimalPoint = currentEntry.indexOf('.');

    for (i = 0; currentEntry.length() - 1 > i 
             && currentEntry.charAt(i) == '0'; ++i) {

        if (i + 1 == decimalPoint) break;
    }

    currentEntry = currentEntry.substring(i);
}

Let’s check our table again:

|  Input  |  Output  |
+---------+----------+
|  "0123" |   "123"  |
| "0.123" | "0.123"  |
|   "000" |     "0"  |
|     "0" |     "0"  |

We’ve made two changes here: first, we never try to consume the last character in the string. Therefore, if we have an input of “00”, we only chop off the first ‘0’, leaving “0” — exactly what we want. Second, we look up the location of the decimal point (if there is one), and ensure we stop one character short of it, preserving a leading zero before the decimal point.

(An aside for those not well versed in Java: #indexOf returns -1 for a character not in the string. Because i starts at 0 and is only incremented, we can guarantee that i + 1 != -1 (overflow excepted — it’s not ever a problem here).)

Minor UI polish like this is not particularly difficult — the total diff between these two methods is 3 lines of code. However, issues like this exist in every system and piece of data that comes close to a user. It’s worth investing the time to hunt them down and fix them, though — users may not notice a well-behaved UI, but they will notice an awkward one.

Mocking for UI Controller Tests in PyQt4

What is Mocking?

Mocking is essentially taking a ‘heavy’ component — a UI element, database/file accessor — and swapping it out with a lighter component that only *pretends* to be the heavier component.  This is useful in cases where you don’t care about how the heavy component works, but need to test an object coupled tightly to it.  A unit test that does not require filesystem access or setting up a stack of GUI elements will run faster and possibly even give more relevant results.

UI Mocking

The main use for mocking is testing code coupled to the UI. This sometimes requires some design changes. For example, consider the following Qt4 window class:

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__(self)

        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.ui.actionLoad.triggered.connect(self.fileLoad)
        self.ui.actionSave.triggered.connect(self.fileSave)
        self.ui.actionExit.triggered.connect(self.fileExit)
        # Other triggers...
    # Logic code...

This class cannot easily be tested — any QtGui object requires that the entire application base be created first. This incurs serious overhead for very little gain — we’re interested in testing the logic code, not the rendering.

The solution is to break our logic out into a separate object. Similarly to the UI itself, both the window and the controller need to hold references to the other so that signals can be routed properly.

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__(self)

        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.controller = MainWindowController(self)
        self.ui.actionLoad.triggered.connect(self.controller.fileLoad)
        self.ui.actionSave.triggered.connect(self.controller.fileSave)
        self.ui.actionExit.triggered.connect(self.controller.fileExit)
    #...

class MainWindowController(object):
    def __init__(self, window):
        self.window = window

    def fileLoad(self):
        #....

The window can route signals from the UI through the controller reference, while the controller can manipulate the UI through the window.ui reference. Furthermore, we can now test the MainWindowController class by passing in a mock of the MainWindow class, eliminating the overhead of setting up the GUI.

So what do these mocks look like? Here are some examples from my current project:

class UiMock(object):

    def __init__(self):
        pass

class WindowMock(object):

    def __init__(self):
        super(WindowMock, self).__init__()
        self.ui = UiMock()

class ButtonGroupMock(object):

    def __init__(self, buttons):
        super(ButtonGroupMock, self).__init__()
        self.buttons = buttons

    def checkedButton(self):
        for button in self.buttons:
            if button.isChecked():
                return button
        else:
            return 0

class RadioButtonMock(object):

    def __init__(self):
        super(RadioButtonMock, self).__init__()
        self.checked = False

    def isChecked(self):
        return self.checked

These, obviously, don’t emulate the objects they’re mocking very deeply. This is intentional — in keeping with the spirit of TDD, we only need to mock the interfaces we actually use in our code. The ButtonGroupMock doesn’t worry about exclusivity, for example, as I’ve not needed it in my tests yet, and UiMock is just an empty namespace. The dynamic nature of Python means that I need only create enough interface to fool the calling code, and no more. (Mocking in static languages, such as Java, is much more involved.)

As a result, our test setup looks something like this:

class TestMainWindowController(unittest.TestCase):
    def setUp(self):
        win_mock = WindowMock()
        
        win_mock.ui.radio_button = RadioButtonMock()
        win_mock.ui.check_box = CheckboxMock()
        # etc...

Hopefully this makes testing UI just a little simpler