Learning notes of Python: Programming: from introduction to practice_ Chapter 11 test code

Chapter 11 test code

11.1 test function

name_function.py(File name, not code) 
def get_formatted_name(first, last): 
 	"""Generate a neatly formatted full name.""" 
 	full_name = first + ' ' + last 
 	return full_name.title()

Program names Py allows users to enter first and last names and display neat full names:

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("\tNeatly formatted name: " + formatted_name + '.') 

This program starts from name_ function. Import get from PY_ formatted_ name(). The user can enter a series of first and last names and see the fully formatted first name:

Enter 'q' at any time to quit. 

Please give me a first name: janis 
Please give me a last name: joplin 
 	Neatly formatted name: Janis Joplin. 

Please give me a first name: bob 
Please give me a last name: dylan 
 	Neatly formatted name: Bob Dylan. 

Please give me a first name: q

11.1.1 unit test and test cases

The module unittest in Python standard library provides code testing tools. Unit tests are used to verify that there is no problem with one aspect of the function; A test case is a set of unit tests that work together to verify that the behavior of the function meets the requirements in various situations. Good test cases take into account the various inputs that the function may receive, including tests for all these situations. Full coverage test cases include a complete set of unit tests, covering various possible function use modes. For large projects, it may be difficult to achieve full coverage. Usually, at first, you only need to write tests for the important behavior of the code, and then consider full coverage when the project is widely used.

11.1.2 acceptable tests

To write test cases for functions, you can first import the module unittest and the functions to be tested, and then create an inherited unittest Testcase class, and write a series of methods to test different aspects of function behavior.

import unittest 
from name_function import get_formatted_name 
class NamesTestCase(unittest.TestCase): 
 	"""test name_function.py""" 
 
 	def test_first_last_name(self): 
 	"""Be able to handle images correctly Janis Joplin Such a name?""" 
		formatted_name = get_formatted_name('janis', 'joplin') 
		self.assertEqual(formatted_name, 'Janis Joplin') 
		
unittest.main()

This class must inherit unittest Testcase class, so that Python knows how to run the test you write.

We run test_name_function.py, all are marked with test_ The first methods will run automatically.

We used one of the most useful features of the unittest class: an assertion method. The assertion method is used to verify whether the results obtained are consistent with the expected results. Here, we know_ formatted_ name() should return a name whose first and last names are capitalized with a space between them, so we expect formatted_ The value of name is Janis Joplin. To check whether this is true, we call the method of unittest, assertEqual(), and pass it formatted_ name and 'Janis Joplin'. Code line self Assert equal (formatted_name, 'Janis Joplin') means: "compare the value of formatted_name with the string 'Janis Joplin'. If they are equal, everything will be fine. If they are not equal, tell me!"

The code line unittest Main () lets Python run the tests in this file. Run test_name_function.py, the output is as follows:

. 
---------------------------------------------------------------------- 
Ran 1 test in 0.000s 

OK

The period in line 1 indicates that one test has passed. The next line indicates that Python ran a test that took less than 0.001 seconds. The final OK indicates that all unit tests in the test case have passed.

11.1.3 failed tests

The following is the function get_ formatted_ The new version of name(), which requires the middle name to be specified through an argument:

name_ function.py(File name, not code) 
def get_formatted_name(first, middle, last): 
 	"""Generate neat names"""
 	full_name = first + ' ' + middle + ' ' + last 
 	return full_name.title()

This version should be able to handle names with middle names correctly, but when we tested it, we found that it can no longer be used
Correctly handle names with only first and last names. Run the program test this time_ name_ function. Py, the output is as follows:

E 
====================================================================== 
ERROR: test_first_last_name (__main__.NamesTestCase) 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
   File "test_name_function.py", line 8, in test_first_last_name 
     formatted_name = get_formatted_name('janis', 'joplin') 
TypeError: get_formatted_name() missing 1 required positional argument: 'last' 
---------------------------------------------------------------------- 
Ran 1 test in 0.000s 

FAILED (errors=1) 

The output of line 1 has only one letter E, which indicates that a unit test in the test case caused an error. Next, we see test in NamesTestCase_ first_ last_ Name() caused an error. When a test case contains many unit tests, it is important to know which test failed. We see a standard traceback that indicates the function call get_formatted_name('janis', 'joplin') has a problem because it lacks an essential location argument. We also saw a unit test run. Finally, you see a message indicating that the entire test case failed because an error occurred while running the test case.

11.1.4 what to do if the test fails

What if the test fails? If the conditions you check are correct, passing the test means that the behavior of the function is correct, and failing the test means that the new code you write is wrong. Therefore, when the test fails, do not modify the test, but repair the code that causes the test to fail: check the modification just made to the function to find out the modification that causes the function behavior not to meet the expectations.

11.1.5 add new test

11.2 testing

11.2.1 various assertion methods

Python in unittest Many assertion methods are provided in the testcase class. As mentioned earlier, the assertion method checks whether the conditions you think should be met are indeed met. If this condition is indeed met, your assumption of program behavior is confirmed, and you can be sure that there is no error in it. If the condition you think should be met is not actually met, python will throw an exception.

The following table describes six common assertion methods. Use these methods to verify that the returned value is equal to or not equal to the expected value, that the returned value is True or False, and that the returned value is in or not in the list. You can only inherit unittest Use these methods in testcase's class,

11.2.2 a class to be tested

survey.py(File name, not code) 
class AnonymousSurvey(): 
	"""Collect answers to anonymous questionnaires""" 
 
	def __init__(self, question): 
 		"""Store a question and prepare for storing an answer""" 
 		self.question = question 
 		self.responses = [] 
 
	def show_question(self): 
 		"""Display questionnaire""" 
 		print(question) 
 
	def store_response(self, new_response): 
 		"""Storage of individual survey responses""" 
 		self.responses.append(new_response) 
 
	def show_results(self): 
 		"""Display all collected answers""" 
 		print("Survey results:") 
 		for response in responses: 
 			print('- ' + response) 

To prove that the AnonymousSurvey class works correctly, let's write a program that uses it:

from survey import AnonymousSurvey 

#Define a question and create an anonymous survey object that represents the survey
question = "What language did you first learn to speak?" 
my_survey = AnonymousSurvey(question) 

#Display questions and store answers
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) 

# Display survey results
print("\nThank you to everyone who participated in the survey!") 
my_survey.show_results() 

When the user enters all the answers (after entering q to exit), call show_. Results() to print the survey results:

What language did you first learn to speak? 
Enter 'q' at any time to quit. 

Language: English 
Language: Spanish
Language: English 
Language: Mandarin 
Language: q 

Thank you to everyone who participated in the survey! 
Survey results: 
- English 
- Spanish 
- English 
- Mandarin 

11.2.3 testing anonymous survey

import unittest 
from survey import AnonymousSurvey 

class TestAnonmyousSurvey(unittest.TestCase): 
 	"""in the light of AnonymousSurvey Class testing""" 
 
	def test_store_single_response(self): 
 		"""Test individual answers will be 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) 
	
unittest.main()

When we run test_survey.py, the test passed:

. 
---------------------------------------------------------------------- 
Ran 1 test in 0.001s 
OK 

That's good, but surveys that collect only one answer are of little use. Let's verify that when the user provides three answers, they will also be properly stored. To do this, we add another method in TestAnonymousSurvey:

import unittest 
from survey import AnonymousSurvey 

class TestAnonymousSurvey(unittest.TestCase): 
 """in the light of AnonymousSurvey Class testing""" 
 
 	def test_store_single_response(self): 
 		"""Test individual answers will be stored properly""" 
 		--snip-- 
 
 	def test_store_three_responses(self): 
 		"""The three answers to the test will be stored properly""" 
 		question = "What language did you first learn to speak?" 
 		my_survey = AnonymousSurvey(question) 
		responses = ['English', 'Spanish', 'Mandarin'] 
 		for response in responses: 
 			my_survey.store_response(response) 
 
		for response in responses: 
 		self.assertIn(response, my_survey.responses) 
 		
unittest.main()

We run test again_ survey. When you pass the test for both answers (py) and (py):

.. 
---------------------------------------------------------------------- 
Ran 2 tests in 0.000s 
OK 

11.2.4 method setUp()

unittest. The TestCase class contains the method setUp(), which allows us to create these objects only once and use them in each test method. If you include the method setUp() in the TestCase class, Python will run it first, and then run each to test_ The way to start. In this way, the object created in method setUp() can be used in every test method you write

import unittest 
from survey import AnonymousSurvey 

class TestAnonymousSurvey(unittest.TestCase): 
 	"""in the light of AnonymousSurvey Class testing""" 
 
 	def setUp(self): 
 		""" 
 		Create a survey object and a set of answers for the test method used
 		""" 
 		question = "What language did you first learn to speak?" 
		self.my_survey = AnonymousSurvey(question) 
		self.responses = ['English', 'Spanish', 'Mandarin'] 
 
 	def test_store_single_response(self): 
 		"""Test individual answers will be stored properly""" 
 		self.my_survey.store_response(self.responses[0]) 
 		self.assertIn(self.responses[0], self.my_survey.responses) 
 
 	def test_store_three_responses(self): 
 		"""The three answers to the test will be stored properly""" 
 		for response in self.responses: 
 			self.my_survey.store_response(response) 
 		for response in self.responses: 
 			self.assertIn(response, self.my_survey.responses) 

unittest.main() 

The method setUp() does two things: create a survey object; Create a list of answers. The variable names that store these two things contain the prefix self (that is, stored in attributes), so they can be used anywhere in this class. This makes both test methods easier because they don't have to create respondents and answers.

Note: when running test cases, Python prints a character every time a unit test is completed: a period is printed when the test passes; Print an E when the test causes an error; Print an F when the test causes the assertion to fail. That's why when you run a test case, you see different numbers of periods and characters in the first line of output. If the test case contains many unit tests and needs to run for a long time, you can know how many tests have passed by observing these results.

11.3 summary

In this chapter, you learned how to use the tools in the module unittest to write tests for functions and classes; How to write inheritance unittest Testcase classes and how to write test methods to verify that the behavior of functions and classes meets expectations; How to use the method setUp() to efficiently create instances and set their properties based on the class so that they can be used in all test methods of the class.

Added by pbeerman on Sat, 29 Jan 2022 22:54:09 +0200