[Tutor] How to write tests for main() function that does not return anything

Steven D'Aprano steve at pearwood.info
Wed Feb 3 08:20:54 EST 2016


On Tue, Feb 02, 2016 at 10:46:04AM +0000, Pedro Miguel wrote:

> Hi guys, I'm trying to test the code in the main() but I'm a bit 
> unsure how to go about it since I'm not passing any arguments or even 
> returning anything other then logging. For the purposes of the example 
> I've shortened the tree statements in the function.. Can anyone point 
> me in the right direction on how to test the logic below? 

That's a great question!

I think the right answer is that testing main() is *not* a unit test, 
it's an integration test. You're testing that the application as a whole 
works the way you expect, rather than testing individual units of the 
application (functions, class, methods, modules).

Nevertheless, you could use unittest to test this. Suppose you have a 
script which reads some files as input, and then writes some files as 
output. You could use the unittest library to give you this integration 
test:



import unittest

class MainTest(unittest.TestCase):
    def setUp(self):
        # set up the environment needed for the test

    def test_main(self):
        result = os.system("python myscript.py")
        self.assertEqual(result, 0)
        # now check that the script's output is what you expect

    def tearDown(self):
        # clean up after the test



But I wouldn't include it in your unit testing module, I would write it 
as a separate test file, and probably wouldn't bother using the unittest 
library since it doesn't give you any real benefit here:

# myscript_integration_test.py

setup()
result = os.system("python myscript.py")
if result:
    print "Integration test failed!"
check_output()
teardown()



Of course, a real test will be more complex. It would need to test each 
of the applications command line options, test whether it works 
correctly with any environment variables it uses. Test whether it logs 
as expected, whether it handles bad input as expected, etc. It will 
probably be quite slow, so you don't want to run it as often as your 
unit tests and regression tests.

In my opinion, your unit tests should limit themselves to checking that 
main() actually exists. You shouldn't assume that 

from myscript import main
main()


will work correctly. For example, a lot of scripts or applications 
perform setup in the module, like this:

if __name__ == '__main__':
    import sys
    args = sys.argv[1:]
    process(args)
    setup_logging()
    sys.exit(main(args))


which is hard to unit test. (You could, I guess, use a strict rule that 
"main() is the only thing that appears inside the `if __name__...` 
block", and if that rule works for you, great, but for me it feels a bit 
too restrictive.


Hope this helps,



-- 
Steve


More information about the Tutor mailing list