This week I really went through a lot of codebases, docs and Python books to learn about unittest. It was really a difficult task to learn it because we need to think of our application in a different way. We need to think about possible use cases of different methods, verify their functionality and logic and check for exceptions. All this becomes difficult and tricky when we need to create unittests for tkinter application.
The main difficulty in tkinter application is that we can’t just normally check it’s functionality. The call to root.mainloop() is a blocking call. Once we call root.mainloop() in setUpclass() method of unittest.TestCase object it blocks the further execution of tests which is not desired.
Ok, then as a normal person you will try to run root.mainloop() in a different thread other than the main thread in which the unittests are made. This trick also fails as neither tkinter is very handy nor unittest module when it comes to multithreading. root.mainloop() can only be run in main thread, therefore the unittests fail when we attempt to run root.mainloop() in secondary thread.
Therefore, finally we can do one thing. Actually root.mainloop() is nothing but just a loop running which periodically checks for changes in GUI elements. We can simulate the functionality of root.mainloop() ourselves by calling root.update() method whenever we change the GUI element programatically. Yeah, one more thing any GUI event can be only injected into tkinter GUI through invoke() or generate_event() methods. They work exactly similar to user input.
We can have an alternate philosophy of testing our GUI applications. It can be applied to each and every GUI application. We can test Tkinter application without using Tkinter library. Basically, remove all the non-Tkinter code from the classes
that handle the GUI and shunt that to another class. This way, we can easily test the logic that is being implemented without actually using Tkinter.
I have planned to use both methods for testing as they represent different perspectives.