I'm really bad at Python and I want to get better, so I've chosen this book by Brian P. Hogan as a way to do that. Exercises for Programmers: 57 Challenges to Develop Your Coding Skills.
Create a program that prompts for your name and prints a greeting using your name.
Example Output
What is your name? Brian Hello, Brian, nice to meet you!
From previous tinkerings with Python I know that it's a scripted language as well as Object Oriented, so I'm
going to start with a script because that's what I know. I created file
hello.py
containing the following:
name = input("What is your name? ")
print("Hello, " + name + ", nice to meet you!")
And run it with this:
$ python3 hello.py
What is your name? Tim
Hello, Tim, nice to meet you!
Happy days!
Next up I want to learn how to write and run unit tests. A quick Google for 'python unit testing'
informed me of two seemingly popular options, namely unittest
and pytest. Since unittest is part of the Python library I
went with that, figured out the syntax, created file test_hello.py
, and wrote the following failing test:
import unittest
import hello
class TestHello(unittest.TestCase):
def test_givenValidName_returnsExpectedString(self):
self.assertEqual(hello.sayhello('Tim'), 'Hello, Tim, nice to meet you!')
I've made an assumption with my test here that I will extract the greeting generation code into its own
function called sayhello
that takes a single 'name' argument, and returns the appropriate string.
I know the function doesn't exist yet and I expect the test to fail, but let's see what command I need to
run the test.
$ python3 -m unittest
What is your name? Tim
Hello, Tim, nice to meet you!
E
======================================================================
ERROR: test_givenValidName_returnsExpectedString (test_hello.TestHello)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/tim/Development/github/57-exercises-python/01-saying-hello/test_hello.py", line 8, in test_givenValidName_returnsExpectedString
self.assertEqual(hello.sayhello('Tim'), 'Hello, Tim, nice to meet you!')
AttributeError: module 'hello' has no attribute 'sayhello'
----------------------------------------------------------------------
Ran 1 test in 0.001s
FAILED (errors=1)
Well that was not what I expected at all. I expected the test to fail but not in this way. What's going on:
hello.py
file is running as a script and prompting me for keyboard input, which is not what
I want from automated tests.sayhello
function, which is fair enough because it doesn't exist yet but the
error message is rather cryptic with AttributeError: module 'hello' has no attribute 'sayhello'
.
Perhaps that'll make more sense one day.Let's address problem 1. I want to see if I can stop the unit test running the file as a script. Again with a little searching I have discovered that there is a Top-level script environment which provides the following template to run certain code only when run as a script.
if __name__ == "__main__":
# execute only if run as a script
Now, if I extract the greeting generation into its own function and put the keyboard input and terminal output code
in the __main__
function I have this
def sayhello(name):
return "Hello, " + name + ", nice to meet you!"
if __name__ == "__main__":
print(sayhello(input("What is your name? ")))
And passing tests
$ python3 -m unittest
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
input("Prompt text: ")
, and terminal output is printed
with print("Printed text")
.hello.py
has module 'hello'. Other
files use that module with import hello
.import unittest
and subclass unittest.TestCase
.test_hello.py
.test_givenValidName_returnsExpectedString(self)
self
argument in the previous point refers to TestCase
.