[Tutor] Questions as to how to run the same unit test multiple times on varying input data.

boB Stepp robertvstepp at gmail.com
Sat Sep 24 01:55:28 EDT 2016


After another long layoff from studying Python due to "that's life", I
am back at it again.  I am trying to combine learning unit testing and
TDD with working through the text, "Think Python 2" by Allen Downey.
I am currently in chapter 3 which is an introduction to functions.  In
trying to apply TDD to exercise 3.1, which is:

"Write a function named right_justify that takes a string named s as a
parameter and prints the string with enough leading spaces so that the
last letter of the string is in column 70 of the display.  Hint:  Use
concatenation and repetition..."

The problem is pretty easy, but the point is for me is to practice the
steps of TDD and learn how to use unit testing, and I figure using
easy problems as I go through the book will make learning TDD and
testing easier.  After a couple of iterations I have this program,
right_justify.py:

#!/usr/bin/env python3

'''Exerise 3.1 from "Think Python 2" by Allen Downey.

This module will take a string and right justify it so that the last character
of the line will fall in column 70 of the display.  This is accomplished by
padding the line with spaces.'''

def right_justify(a_string):
    '''This fucntion will take the string, "a_string", and left justify it by
    padding it with spaces until its last character falls in column 70 of the
    display.  The padded string will be returned.'''

    return ' ' * 58 + a_string

Of course, this code passed its test when the string was "Monty
Python", so I next wanted to run the same test with different strings
each time, so that my code would fail in these more general cases.
However, I struggled to find a way to repeat the same test with
varying data, eventually crying "Uncle!" and consulted the
documentation.  This led me to this version of test_right_justify.py:

#!/usr/bin/env python3

'''This module contains unit tests for the function,
"right_justify(a_string)", located in the module, "right_justify".'''

import unittest

import right_justify

class TestRightJustify(unittest.TestCase):
    '''Tests for the function, "right_justify(a_string)", in the "right_justify
    module".'''

    def setUp(self):
        '''Define variables needed to run this class' tests.'''

        self.test_strings = [
                "Monty Python",
                "She's a witch!",
                "Beware of the rabbit!!!  She is a vicious beast who will rip"
                " your throat out!"]

    def test_returned_len_is_70(self):
        '''Check that the string returned by "right_justify(a_string)" is the
        length of the entire line, i.e., 70 columns.'''

        for test_string in self.test_strings:
            with self.subTest(test_string = test_string):
                length_of_returned_string = (
                    len(right_justify.right_justify(test_string)))
                print('The current test string is: ', test_string)
                self.assertEqual(length_of_returned_string, 70)

if __name__ == '__main__':
    unittest.main()

I know that I need more tests (or a better single one) to fully test
this function.  But I am taking baby steps here, checking the most
obvious stuff first.  Refinement will come as I learn and move along.

Anyway, running the tests gave me this result:

c:\thinkpython2\ch3\ex_3-1>py -m unittest
The current test string is:  Monty Python
The current test string is:  She's a witch!
The current test string is:  Beware of the rabbit!!!  She is a vicious
beast who will rip your throat out!

======================================================================
FAIL: test_returned_len_is_70 (test_right_justify.TestRightJustify)
(test_string="She's a witch!")
Check that the string returned by "right_justify(a_string)" is the
----------------------------------------------------------------------
Traceback (most recent call last):
  File "c:\thinkpython2\ch3\ex_3-1\test_right_justify.py", line 32, in
test_returned_len_is_70
    self.assertEqual(length_of_returned_string, 70)
AssertionError: 72 != 70

======================================================================
FAIL: test_returned_len_is_70 (test_right_justify.TestRightJustify)
(test_string='Beware of the rabbit!!!  She is a vicious beast who will
rip your throat out!')
Check that the string returned by "right_justify(a_string)" is the
----------------------------------------------------------------------
Traceback (most recent call last):
  File "c:\thinkpython2\ch3\ex_3-1\test_right_justify.py", line 32, in
test_returned_len_is_70
    self.assertEqual(length_of_returned_string, 70)
AssertionError: 135 != 70

----------------------------------------------------------------------
Ran 1 test in 0.009s

FAILED (failures=2)

Question #1:  Why is the test output NOT showing the first, passed
test?  The one where the string is "Monty Python"?

Question #2:  Before I hit the docs to learn about subTest, I tried a
bunch of different ways to make that for loop to work inside the
class, but I guess my current poor knowledge of OOP did me in.  But I
KNOW there has to be a way to accomplish this WITHOUT using subTest.
After all, subTest was not introduced until Python 3.4.  So how should
I go about this without using subTest?

Question #3:  In "with self.subTest(test_string = test_string):" why
is "test_string = test_string" necessary?  Is it that using "with"
sets up a new local namespace within this context manager?

I think with these long Python layoffs I am losing knowledge faster
than I am gaining it!

Cheers!
-- 
boB


More information about the Tutor mailing list