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
OK
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
OK
__init__.py
file to a directory makes that directory a module named as
the directory name. e.g: exercises/Ex04_mad_lib
.01hello
is invalid.01-hello
is invalid.-s
option for the
unittest discover
command. E.g. python3 -m unittest discover -s exercises/Ex01_saying_hello/