[Tutor] Using unittest module for Test Driven Development
Steven D'Aprano
steve at pearwood.info
Mon Aug 25 03:57:17 CEST 2014
On Sun, Aug 24, 2014 at 05:23:35PM -0700, Alex Kleider wrote:
> Given
> $ cat compare.py
> #!/usr/bin/env python3
> import os
> import sys
>
> def get_args():
> try:
> args = sys.argv[1:]
> except IndexError:
> return
> return [arg for arg in args if os.path.isfile(arg)]
The try...except block is redundant, because you are taking a slice, not
an index, it cannot fail. If the bounds are outside of the actual list,
the empty list is returned:
py> [1, 2][100:1000]
[]
By the way, is there significance to the name "compare.py"? Because it's
not really doing any comparisons...
> if __name__ == "__main__":
> print(get_args())
>
> How can one unittest get_args()?
> It seems to me that 'unittest'ing only works to test functions and
> methods, not programs.
Well, technically "unit testing" refers to testing individual "units"
(that is, classes, functions, modules etc.) of a program, not the entire
program all at once. But it's also flexible enough to test the entire
program.
To test get_args() alone, I would do something like this:
import sys
import unittest
import compare
class Test_Get_Args(unittest.TestCase):
def setUp(self):
# Create some known files.
open('/tmp/aaa', 'w').close()
open('/tmp/bbb', 'w').close()
# Make sure another file doesn't exist.
if os.path.exists('/tmp/ccc'):
os.unlink('/tmp/ccc')
def tearDown(self):
# Clean up once we're done.
for file in ('/tmp/aaa', '/tmp/bbb'):
if os.path.exists(file):
os.unlink(file)
def test_existing_files(self):
sys.argv = ['testing', '/tmp/aaa', '/tmp/bbb']
result = compare.get_args()
self.assertEqual(result, ['/tmp/aaa', '/tmp/bbb'])
def test_nonexisting_files(self):
sys.argv = ['testing', '/tmp/ccc']
result = compare.get_args()
self.assertEqual(result, [])
def test_not_files(self):
sys.argv = ['testing', '/tmp', '/']
result = compare.get_args()
self.assertEqual(result, [])
The paths I used are suitable for Unix, Linux or Mac. You will need to
adapt them for Windows.
To avoid having to write to sys.argv, give your get_args function an
optional argument:
def get_args(args=None):
if args is None:
args = sys.argv[1:]
return [arg for arg in args if os.path.isfile(arg)]
then in your tests, just pass the list directly to the function.
> Here's my attempt at a testing module:
> $ cat testing.py
> #!/usr/bin/env python3
> import unittest
> import compare_sizes
What's compare_sizes ?
> class CompareTesting(unittest.TestCase):
>
> def setUp(self):
> pass
If you're not doing anything in setUp, just don't override the method.
The default method does nothing, so you don't need this.
> def test_nothing(self):
> self.assertEqual(not False, True)
What is the purpose of this test? How is it testing *your* code? That
would be necessary as a test of Python's built-ins.
> def test_get_file_param(self):
> self.assertTrue(compare_sizes.get_args() == ['file1', 'file2'])
You should use assertEqual(a, b) rather than assertTrue(a == b).
> if __name__ == '__main__':
> unittest.main()
>
> Is there a way that I can provide the file name command line parameters
> to compare.py so that its get_args function can be tested?
sys.argv is writeable, or better still, provide get_args() an optional
argument to use instead of sys.argv.
--
Steven
More information about the Tutor
mailing list