Testing GUI code: should I use a mocking library?

Recently I've been experimenting with TDD while developing a GUI application in Python. I find it very reassuring to have tests that verify the functionality of my code, but it's been tricky to follow some of the recommened practices of TDD. Namely, writing tests first has been hard. And I'm finding it difficult to make my tests readable (due to extensive use of a mocking library).

I chose a mocking library called mocker. I use it a lot since much of the code I'm testing makes calls to (a) other methods in my application that depend on system state or (b) ObjC/Cocoa objects that cannot exist without an event loop, etc.

Anyway, I've got a lot of tests that look like this:

def test_current_window_controller():
    def test(config):
        ac = AppController()
        m = Mocker()
        ac.iter_window_controllers = iwc = m.replace(ac.iter_window_controllers)
        with m:
            result = ac.current_window_controller()
            assert result == (config[0] if config else None)
    yield test, []
    yield test, [0]
    yield test, [1, 0]

Notice that this is actually three tests; all use the same parameterized test function. Here's the code that is being tested:

def current_window_controller(self):
        # iter_window_controllers() iterates in z-order starting
        # with the controller of the top-most window
        # assumption: the top-most window is the "current" one
        wc = self.iter_window_controllers().next()
    except StopIteration:
        return None
    return wc

One of the things I've noticed with using mocker is that it's easier to write the application code first and then go back and write the tests second, since most of the time I'm mocking many method calls and the syntax to write the mocked calls is much more verbose (thus harder to write) than the application code. It's easier to write the app code and then model the test code off of that.

I find that with this testing method (and a bit of discipline) I can easily write code with 100% test coverage.

I'm wondering if these tests are good tests? Will I regret doing it this way down the road when I finally discover the secret to writing good tests?

Am I violating the core principles of TDD so much that my testing is in vain?

Asked by: John337 | Posted: 28-01-2022

Answer 1

If you are writing your tests after you've written your code and making them pass, you are not doing TDD (nor are you getting any benefits of Test-First or Test-Driven development.. check out SO questions for definitive books on TDD)

One of the things I've noticed with using mocker is that it's easier to write the application code first and then go back and write the tests second, since most of the time I'm mocking many method calls and the syntax to write the mocked calls is much more verbose (thus harder to write) than the application code. It's easier to write the app code and then model the test code off of that.

Of course, its easier because you are just testing that the sky is orange after you made it orange by painting it with a specific kind of brush. This is retrofitting tests (for self-assurance). Mocks are good but you should know how and when to use them - Like the saying goes 'When you have a hammer everything looks like a nail' It's also easy to write a whole load of unreadable and not-as-helpful-as-can-be tests. The time spent understanding what the test is about is time lost that can be used to fix broken ones.

And the point is:

  • Read Mocks aren't stubs - Martin Fowler if you haven't already. Google out some documented instances of good ModelViewPresenter patterned GUIs (Fake/Mock out the UIs if necessary).
  • Study your options and choose wisely. I'll play the guy with the halo on your left shoulder in white saying 'Don't do it.' Read this question as to my reasons - St. Justin is on your right shoulder. I believe he has also something to say:)

Answered by: Dominik660 | Posted: 01-03-2022

Answer 2

Unit tests are really useful when you refactor your code (ie. completely rewrite or move a module). As long as you have unit tests before you do the big changes, you'll have confidence that you havent forgotten to move or include something when you finish.

Answered by: Vanessa899 | Posted: 01-03-2022

Answer 3

Please remember that TDD is not a panaceum. It's hard, it's supposed to be hard, and it's especially hard to write mocking tests "in advance".

So I would say - do what works for you. Even it's not "certified TDD". I do basically the same thing.

You may want to provide your own API for GUI that would sit between controller code and GUI library code. That could be easier to mock, or you can even add some testing hooks to it.

Last but not least, your code doesn't look too unreadable to me. Code using mocks is generally harder to understand. Fortunately in Python mocking is much easier and cleaner than i n other languages.

Answered by: Kimberly432 | Posted: 01-03-2022

Similar questions

unit testing - Mocking return value of a nested call in Python mock library

Brand new to this library Here is the call stack of my mocked object [call(), call('test'), call().instance('test'), call().instance().database('test'), call().instance().database().snapshot(), call().instance().database().snapshot().__enter__(), call().instance().database().snapshot().__enter__().execute_sql('SELECT * FROM users'), call().instance().database().snapshot().__exit__(None, Non...

unit testing - Mocking objects in Python

I'm new to Unit testing and mocking objects in Python. I have a function that I need to create a unit test for. def BuildBall(self, material): """Create a Ball from material.""" result = {} for b in xrange(material.ball_size()): ball = material.ball(b) result[ball.name()] = (ball.name(), ball.description()) return result I want to create a dummy object(material) and pass it...

unit testing - Mocking the super class calls on python

I am doing some unit testing and at some point I need to mock a super call to throw an error, for example: @classmethod def myfunc(cls, *args, **kwargs) try: super(MyClass, cls).my_function(args, kwargs) except MyException as e: #... I am using the mocker library to mock...

unit testing - Mocking a HTTP server in Python

I'm writing a REST client and I need to mock a HTTP server in my tests. What would be the most appropriate library to do that? It would be great if I could create expected HTTP requests and compare them to actual.

unit testing - Mocking modules from boto in python

I am trying to write a unit test for a class that looks like below. import boto class ToBeTested: def location(self, eb): return eb.create_storage_location() def some_method(self): eb = boto.beanstalk.connect_to_region(region, access_key, secret_key) location(eb) Is there a way to mock boto.beanstalk.connect_to_region return value and fin...

unit testing - python mocking third party modules

im trying to test some classes that process tweets. Im using sixohsix twitter to deal with Twitter API. I have a class that acts as a facade for the Twitter classes, and my idea was to mock the actual sixohsix classes to simulate the arrival of tweets, by randomly generate new tweets or retrieving them from a database. My facade looks something like: from twitter import TwitterStream class Twitte...

unit testing - Python mock() not mocking the return value

I'm having some trouble with Python mock() and I'm not familiar enough to figure out what's going on with it. I have an abstract async task class that looks something like: class AsyncTask(object): @classmethod def enqueue(cls): .... task_ent = cls.createAsyncTask(body, delayed=will_delay) .... I'd like to patch the createAsyncTask method for a speci...

unit testing - Mocking zipfile in python

I'm trying to use Python mock library to mock few methods for zipfile module. Example Source which I want to test: def zipStuff(listOfPathToFiles): with ZipFile(fName, 'w') as archive: for each in listOfPathToFiles: archive.write(each, strippedfName) return archive The "archive" above will be ignored for normal execution, but will be list of files durin...

unit testing - "Mocking where it's defined" in python mock?

I want to test an evolving SQLite database application, which is in parallel used "productively". In fact I am investigating a pile of large text files by importing them to the database and fiddling around with it. I am used to develop test-driven, and I do not want to drop that for this investigation. But running tests against the "production" database feels somewhat strange. So my objective is to run the tests a...

unit testing - Python mocking delete

I practice TDD but I have not used mocking before. Suppose I want to build a function that should create a folder, but only if that folder does not already exist. As part of my TDD cycle I first want to create a test to see that my function won’t delete an already existing folder. As my function will probably use os.rm, I gather I could use mocking to see whether os.rm has been called or not. But this isn...

unit testing - To Kill A Mocking Object: A Python Story

I have been having trouble with Python mock and have been going crazy. I've held off on this question due to fear of down voting for not enough research. I have a cumulative 24 hours over the last week trying to figure out how to get this work and cannot. I have read numerous examples and have created this one from those. I know mock objects are supposed to be easy to use, but this has taken too long. Now I am out ...

python - Unit testing with nose: tests at compile time?

Is it possible for the nose unit testing framework to perform tests during the compilation phase of a module? In fact, I'd like to test something with the following structure: x = 123 # [x is used here...] def test_x(): assert (x == 123) del x # Deleted because I don't want to clutter the module with unnecessary attributes nosetests tells me that x is undefined, as it apparently...

python - Unit testing for D-Bus and HAL?

How does one test a method that does some interactions with the local D-Bus (accessing a HAL object)? Results of tests will differ depending on the system that the test is run on, so I don't know how to provide the method reliable input. I'm working in Python, by the way.

python - PyQT GUI Testing

Does anyone know of a automated GUI testing package for that works with PyQT besides Squish? Nothing against Squish I am just looking for other packages. It would be cool if there were an open source package. I am doing my testing under Linux.

testing - Online IDE for Python

Closed. This question does not meet Stack Overflow guid...

Unit testing file write in Python

I am writing a wrapper for the ConfigParser in Python to provide an easy interface for storing and retrieving application settings. The wrapper has two methods, read and write, and a set of properties for the different application settings. The write method is just a wrapper for the ConfigParser's write method with the addition of...

testing - Library like fakeweb for Python

I really like the way fakeweb in Ruby can be used to fake http requests when testing. Is there a similar library or an alternative for Python?

Testing python methods that call class methods

I have a very simple method: Class Team(models.Model): def sides(self): return SideNames.objects.filter(team=self) SideNames is another model defined in the same file as Team, Which when I try and test: self.assertEquals(len(t.sides()), 2) I get the following error: return SideNames.objects.filter(team=self) ...

Unit testing in python?

Testing sample code in python modules

I'm in the process of writing a python module that includes some samples. These samples aren't unit-tests, and they are too long and complex to be doctests. I'm interested in best practices for automatically checking that these samples run. My current project layout is pretty standard, except that there is an extra top level makefile that has build, install, unittest, coverage and profile targets, that delegate res...

unit testing - Is TDD broken in Python?

Assume we have a class UserService with attribute current_user. Suppose it is used in AppService class. We have AppService covered with tests. In test setup we stub out current_user with some mock value: UserService.current_user = 'TestUser' Assume we decide to rename current_user to active_user

Still can't find your answer? Check out these communities...

PySlackers | Full Stack Python | NHS Python | Pythonist Cafe | Hacker Earth | Discord Python