working on chap11

master
Jason Zhu 2020-09-09 21:45:09 +10:00
parent 584073500e
commit 5756668d9e
8 changed files with 259 additions and 1 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
.vscode
**__pycache__**

173
chap11_testing.md 100644
View File

@ -0,0 +1,173 @@
# Chapter 11. Testing Your Code
Learn how to test code using Python's `unittest` module.
## Testing a Function
Function to be tested as shown below.
```python
def get_formatted_name(first, last):
"""Generate a neatly formatted full name."""
full_name = f"{first} {last}"
return full_name.title()
```
A script that should use `get_formatted_name`
```python
from name_function import get_formatted_name
print("Enter 'q' at any time to quit.")
while True:
first = input("\nPlease give me a first name: ")
if first == 'q':
break
last = input("Please give me a last name: ")
if last == 'q':
break
formatted_name = get_formatted_name(first, last)
print(f"\tNeatly formatted name: {formatted_name}.")
```
To make sure `get_formatted_name` function properly, using `unittest` module of Python
```python
import unittest
from name_function import get_formatted_name
class NamesTestCase(unittest.TestCase):
"""Test for name_function.py"""
def test_first_last_name(self):
"""Do names like 'Janis Joplin' work?"""
formatted_name = get_formatted_name('janis', 'joplin')
self.assertEqual(formatted_name, 'Janis Joplin')
if __name__ == '__main__':
unittest.main()
```
Key points:
* Import `unittest` module as shown
* Import function to be tested
* Here, `unittest`'s most useful feature `assert` is used. `assertEqual` can compare two objects
* `__name__` is a **special variable**, which is set when the program is executed. If the file is being run as the main program, the value of `__name__` is set to `'__main__'`
Result of running this test:
```
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
```
* First dot represent the single test passed.
### A Failing Test
Failure case returns
```
F
======================================================================
FAIL: test_first_last_name (__main__.NamesTestCase)
Do names like 'Janis Joplin' work?
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_name_function.py", line 10, in test_first_last_name
self.assertEqual(formatted_name, 'Janis Joplins')
AssertionError: 'Janis Joplin' != 'Janis Joplins'
- Janis Joplin
+ Janis Joplins
? +
----------------------------------------------------------------------
Ran 1 test in 0.001s
FAILED (failures=1)
```
Highlight:
* `FAIL: test_first_last_name` tell's where the error coming from.
## Fix them
If employing TDD, we can first create test case, then develop code to be test against.
## Testing a Class
e.g. above shown how to write test case for single function, we also need to write test for class.
### A Variety of Assert Methods
Python `unittest` module provide various assert methods in `unittest.TestCase` class.
List of available assert methods
| Method | Use |
| ------------------------- | -------------------------------- |
| `assertEqual(a,b)` | Verify `a == b` |
| `assertNotEqual(a,b)` | Verify that `a != b` |
| `assertTrue(x)` | Verify that x is True |
| `assertFalse(x)` | Verify that x is False |
| `assertIn(item, list)` | Verify that item is in list |
| `assertNotIn(item, list)` | Verrify that item is not in list |
### A Class to Test
* class to be tested in *survey.py* have class `AnonymousSurvey`
```python
class AnonymousSurvey:
"""Collect anonymous answers to a survey questions"""
def __init__(self, question):
"""Store a question, and prepare to store response."""
self.question = question
self.responses = []
def show_question(self):
"""Show the survey question"""
print(self.question)
def store_response(self, new_response):
"""Store a single response to the survey"""
self.responses.append(new_response)
def show_results(self):
"""Show all the responses that have been given"""
print("Survey results:")
for response in self.responses:
print(f"- {response}")
```
* script to use `AnonymousSurvey` *language_survey.py*
```python
from survey import AnonymousSurvey
# Define a question, and make a survey.
question = "What language did you first learn to speak?"
my_survey = AnonymousSurvey(question)
# Show the questions, and store responses to the question
my_survey.show_question()
print("Enter 'q' at any time to quit.\n")
while True:
response = input("Language: ")
if response == 'q':
break
my_survey.store_response(response)
# Show the survey results
print("\nThank you to everyone who participate in the survey")
my_survey.show_results()
```
If we want to

View File

@ -0,0 +1,18 @@
from survey import AnonymousSurvey
# Define a question, and make a survey.
question = "What language did you first learn to speak?"
my_survey = AnonymousSurvey(question)
# Show the questions, and store responses to the question
my_survey.show_question()
print("Enter 'q' at any time to quit.\n")
while True:
response = input("Language: ")
if response == 'q':
break
my_survey.store_response(response)
# Show the survey results
print("\nThank you to everyone who participate in the survey")
my_survey.show_results()

View File

@ -0,0 +1,4 @@
def get_formatted_name(first, last):
"""Generate a neatly formatted full name"""
full_name = f"{first} {last}"
return full_name.title()

View File

@ -0,0 +1,13 @@
from name_function import get_formatted_name
print("Enter 'q' at any time to quit.")
while True:
first = input("\nPlease give me a first name: ")
if first == 'q':
break
last = input("Please give me a last name: ")
if last == 'q':
break
formatted_name = get_formatted_name(first, last)
print(f"\tNeatly formatted name: {formatted_name}.")

View File

@ -0,0 +1,21 @@
class AnonymousSurvey:
"""Collect anonymous answers to a survey questions"""
def __init__(self, question):
"""Store a question, and prepare to store response."""
self.question = question
self.responses = []
def show_question(self):
"""Show the survey question"""
print(self.question)
def store_response(self, new_response):
"""Store a single response to the survey"""
self.responses.append(new_response)
def show_results(self):
"""Show all the responses that have been given"""
print("Survey results:")
for response in self.responses:
print(f"- {response}")

View File

@ -0,0 +1,13 @@
import unittest
from name_function import get_formatted_name
class NamesTestCase(unittest.TestCase):
"""Test for name_function.py"""
def test_first_last_name(self):
"""Do names like 'Janis Joplin' work?"""
formatted_name = get_formatted_name('janis', 'joplin')
self.assertEqual(formatted_name, 'Janis Joplins')
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,15 @@
import unittest
from survey import AnonymousSurvey
class TestAnonymousSurvey(unittest.TestCase):
"""Tests for the class AnonymouseSurvey"""
def test_store_single_response(self):
"""Tests that a single response is stored properly"""
question = "What language did you first learn to speak?"
my_survey = AnonymousSurvey(question)
my_survey.store_response('English')
self.assertIn('English', my_survey.responses)
if __name__ == '__main__':
unittest.main()