Tim Cooke

Exercises for Programmers (Python): 4 of 57 - Printing Quotes

10th August 2020

Exercise 4 in book Exercises for Programmers: 57 Challenges to Develop Your Coding Skills by Brian P. Hogan.

Create a simple mad-lib program that promts for a noun, a verb, and adverb, and an adjective and injects those into a story that you create.

Example Output

Enter a noun: dog
Enter a verb: walk
Enter an adjective: blue
Enter an adverb: quickly
Do you walk your blue dog quickly? That's hilarious!

Starting with a test, I'm making assumptions about the structure of the code and expecting a module called madlib and a function called story() that takes 4 strings and returns the story as a string also.

import unittest
import madlib

class TestQuotes(unittest.TestCase):

    def test_givenNounVerbAdjectiveAdverb_returnStory(self):
        self.assertEqual(madlib.story('dog', 'walk', 'blue', 'quickly'),
                         "Do you walk your blue dog quickly? That's hilarious!")

As is typical when working in a TDD style I expect this test to fail because I haven't written anything else yet so let's get to it.

def story(noun, verb, adjective, adverb):
    return "Do you " + verb + " your " + adjective + " " + noun + " " + adverb + "? That's hilarious!"

if __name__ == "__main__":
    noun = input("Enter a noun: ")
    verb = input("Enter a verb: ")
    adjective = input("Enter an adjective: ")
    adverb = input("Enter n adverb: ")
    print(story(noun, verb, adjective, adverb))

That was pretty straight forward so I'm going to take this opportunity to look a little closer at unittest and see how I can run all the tests I've written all at once. At the moment if I run python3 -m unittest at the top level it runs no tests.

$ python3 -m unittest

Ran 0 tests in 0.000s


Some research suggests that I need to organise my code into packages in order to be able to trigger the running of tests from the top level directory and for the test modules to be able to import other modules correctly. Packages are defined by adding an empty __init__.py file to each directory that you want to become a package. The name of the directory becomes the name of the package, and the import statements of the tests need to be updated too.

$ tree
└── exercises
    ├── Ex01_saying_hello
    │   ├── hello.py
    │   ├── helloscript.py
    │   ├── __init__.py
    │   └── test_hello.py
    ├── Ex02_counting_the_number_of_characters
    │   ├── counting.py
    │   ├── __init__.py
    │   └── test_counting.py
    ├── Ex03_printing_quotes
    │   ├── __init__.py
    │   ├── quotes.py
    │   └── test_quotes.py
    ├── Ex04_mad_lib
    │   ├── __init__.py
    │   ├── madlib.py
    │   └── test_madlib.py
    └── __init__.py

And the import statements in the tests (just the one shown here but you get the idea)

import unittest
from exercises.Ex01_saying_hello import hello

Now running the tests from the top level directory runs all tests.

$ python3 -m unittest
Ran 8 tests in 0.000s


Learning review