current position：Home>Untested Python code is not far from crashing
Untested Python code is not far from crashing
2022-01-31 07:51:16 【Nuggets translation program】
My first mentor was incredibly . He showed me the code 、 logging 、 Best practices and benefits of documentation . But there's one thing he couldn't instill in me , That's the test . His way of testing code is complicated , Including writing the test program first , And then coding implementation ！ His way is opposite to my coding style , It makes me feel ：" If I write the test before I write the function , Then I might as well not write a test .”…… It makes me feel much better .
But the problem is ： Your code needs to be tested . Because all the code , Even good code , Both with bug There is only a thin line between them . For starters ：bug Is an unexpected function or error in the code . You may know your code and its limitations very well , But new teammates ？ perhaps , In a year , You want to add a feature to a project you've largely forgotten , What should I do ？ The test is like a bumper on a bowling alley , So that you can be confident that the submitted code will get full marks every time .
This article will reuse my Python In the learning series The first 3 part Code for , And use me in here To introduce the
Makefile. If you are Python Novice , Why don't you take a look first The first 1 part and The first 2 part ？ Besides , If you don't have your own Python The work environment , Please be there. here Check out the tutorials you need .
Topics discussed ：
- unit testing
- Mocking and patch
- When to test ？
Because this requires some code , I've created a Github Project To help us start this topic . The easiest way to get it is through Github Desktop Clone it , Or download it as ZIP file . The folder contains
Makefile And a
Pipfile, One more
Solutions Folder , But let's ignore it for the time being .
Create a file called
tests Of Python package . So how to create ？ It's a little complicated —— First, create a folder , Create a file named
__init__.py Empty file . Yes , That's it . And then in the new
tests In the folder , Create another one called
test_order_up.py The file of . Now we can start . Be careful ：unittest（ and pytest） According to “test” The beginning of the file determines the test code , So avoid this when naming non test files ！
What is the test ？
In short , The test answered “ Whether the execution results of the program meet our expectations ？” This problem . To answer this question , We can run a function by using preselected input and check whether the output meets our expectations . You can run a function and verify the output , Make sure it doesn't throw errors , Or make sure it exactly Throw an error , To ensure that the code has been fully tested . A good set of tests should include normal use cases 、 Edge use cases and creative use cases . You don't just have to make sure your code runs as it is , And make sure your The test will capture any stupid behavior you or others will do in the future .
Unittest yes Python Built in test framework , So we'll start here . Put this code into your test file ：
import unittest import order_up class TestOrderUp(unittest.TestCase): def test_get_order_one_item(self): order = ["fries"] result = order_up.get_order(order) self.assertEqual(order, result) Copy code
First , We
import unittest, It is a tool for testing code Python Built in bag , And then we import
order_up.py file （ Notice that we have omitted
.py Extension ）.
notes ： If you're using PyCharm And in
order_upSee the red underline below , This means that the package cannot be found . You can go back to Github Open the project under the root directory of the project or right-click the project folder and select “Mark Directory as” -> “Sources Root” To solve this problem .
Next , Let's create a name
TestOrderUp Class , Its name matches our file name , This makes it easier to find failed tests . Oh , But there's something in parentheses ,
unittest.TestCase, This means that our class inherits
TestCase class .
Inheritance means that a class receives functions and variables from its parent class . In our case , We from
TestCase It inherits rich functions to facilitate our testing work . What functions and variables are inherited ？ We'll discuss this later .
Create a test
Under our class is a class named
test_output_order_one_item Function of , It should roughly explain what we do in the test . We will use it to test
get_order() Function and check whether the output meets our expectations . Let's run it , See what happens ！ You can execute... In the terminal
python -m unittest, Or click PyCharm The green arrow next to the function in . You can also choose to perform
make unit-test, Let the code run in a virtual environment ( We will mention later
Makefile）. Look at the results ：
unittest.TestCase Functions inherited in include assertions , It ensures that the result of the function is within our expectations . stay Pycharm in , Input
self.assert, The code completion function will display all the different options . There are a lot of them , But I mainly use
self.assertEqual, It checks whether the two objects are the same , as well as
self.assertFalse, The function is self-evident .
order_up The main function of is to get orders , Delete items that are not on the menu , And allow duplicate items . therefore , Let's add tests to make sure we keep these functions in our code .
# Make sure these functions are indented in the class . def test_get_order_duplicate_in_list(self): order = ["fries", "fries", "fries", "burger"] result = order_up.get_order(order) self.assertEqual(order, result) def test_get_order_not_on_menu(self): order = ["banana", "cereal", "cookie"] expected_result = ["cookie"] result = order_up.get_order(order) self.assertEqual(expected_result, result) Copy code
Now we are checking whether our function can handle duplicate items and items not on the menu . Run these tests and make sure they pass ！ sidenote ： It's best to write a test with a line between the executed code and the verified code . such , You and your teammates can easily tell which is which .
I have to admit ： I did a little cheating . If you will The first 3 part The code in is the same as the current
order_up.py Compare , You will notice that I added a function to accommodate a new variable ：
test_order. With this new variable , We can bypass the introduction of
input(), In this way, we won't let the program ask the user for input every time we run the test . But now we have mastered the basic knowledge of testing , We can start trying to use mock.Mock Can imitate and create functions / object , So that our tests can focus on logic . under these circumstances , We will “ Mend ”
input() function , Or rewrite it temporarily , To simply return the output we want . have a look ：
def test_is_order_complete_yes(self, input_patch): self.assertEqual(builtins.input, input_patch) result = order_up.is_order_complete() self.assertFalse(result) Copy code
First , Add... At the beginning of the test file
from unittest.mock import patch. In limine , We are mending
builtins.input() Function and tell it to return “yes”. then , We execute assertions to check whether the parameters obtained from the patch are consistent with
input It's exactly the same ！ be aware
builtins.input Are there no parentheses ？ We can reference the signature of the function to verify , Instead of executing functions . after , Let's go back to the normal test protocol ： Operation function , To get the results , And assert the result . under these circumstances , Because of our
input() The return value is “yes”, We expect
False. Add it to your test class , Click Run , Get red OK Or green check mark , Let's move on ！
Now we've learned patch, We can solve
get_output() The input problem in ！ Um. , almost . First , We need to understand
side_effect, When we need to provide different return values for the same function , It is our Savior . stay
get_output() in , adopt
input(), We were asked “ What do you want ？” and “ Have you finished? ？”. therefore , We need to get
input() Not just one but multiple outputs are returned to accommodate each situation . have a look ：
def test_get_order_valid(self, input_patch): self.assertEqual(builtins.input, input_patch) expected_result = ["cookie", "fries"] result = order_up.get_order() self.assertEqual(expected_result, result) Copy code
So , We don't know
return_value, It's for
side_effect Assign a list .
remarks ： You can also assign values in the test function
side_effect Will get each item in the list , And in every call patch Function is provided separately . Add the code and click the test button / command ！ The last thing ： stay “banana” and “cookie” None of them is / no , Because if
MENU The item does not exist in ,
get_order() Don't ask “ Would you like to order more ？”. If you want to play with this list yourself , Please remember this thing .
Having finished the basics of testing , Let's take a look
Makefile. I won't copy / Paste the code here , Because you can see it in the project . The main method is
venv To execute , According to our
Pipfile Configure and start a virtual environment . Pay attention to
unit-test At the end of , We did
python3 -m pipenv run python3 -m unittest;, This is where testing magic takes place , Even if you forget how to run tests , You can also find it there ！
When to write tests ？
So when to write a test ？ It doesn't matter . The point is that the test written can cover most of the code and the potential use cases it may encounter . If you can't test your code correctly or need to 8 A different test to cover a function , Then you probably need to refactor your code . This doesn't make you a bad programmer , It's just a programming process / Part of the experience .
Test-driven development （TDD）
Let me talk about test driven development （TDD） The question of .TDD Is a development practice , Write the failed test program first, and then write the function to pass it . Story time ： I joined a startup , The startup will Robert C. Martin（《 Clean code 》 And the authors of other books ） Of TDD And the concept of negative patterns , Or bad coding practices to avoid , As a faith . There is a , We held a meeting on TDD And its benefits of meetings to encourage the team to think more “ It works ” The way to code . Unfortunately , Spend most of your time arguing TDD On the definition and correct usage of . The organizer of the meeting , A senior engineer , Think we “ Coding too fast ”, Not by writing " smart " Tests or functions that exceed the functions tested to correctly implement TDD Principles .
I left the meeting with an idea ： Let your philosophical debate from my work disappear .
The point of this article is ： Find a suitable way to include testing in the project . I didn't give a specific way to implement them or when , As long as they can prevent your code from entering the drain after the next submission . bye ！
If there are errors in the translation or other areas that need to be improved , Welcome to Nuggets translation plan Revise the translation and PR, You can also get bonus points . At the beginning of the article Permanent link to this article That's what this article is about GitHub Upper MarkDown link .
Nuggets translation plan It is a community that translates high-quality Internet technology articles , The source of the article is Nuggets Share articles in English on . Content coverage Android、iOS、 front end 、 Back end 、 Blockchain 、 product 、 Design 、 Artificial intelligence Other fields , If you want to see more excellent translations, please keep your eyes on Nuggets translation plan 、 Official micro-blog 、 Know about columns .
author[Nuggets translation program],Please bring the original link to reprint, thank you.
The sidebar is recommended
- Django ORM details - fields, attributes, operations
- Python web crawler - crawling cloud music review (3)
- Stroke list in python (bottom)
- What cat is the most popular? Python crawls the whole network of cat pictures. Which one is your favorite
- [algorithm learning] LCP 06 Take coins (Java / C / C + + / Python / go / trust)
- Python shows the progress of downloading files from requests
- Solve the problem that Django celery beat prompts that the database is incorrectly configured and does not support multiple databases
- Bamboolib: this will be one of the most useful Python libraries you've ever seen
- Python quantitative data warehouse construction 3: data drop library code encapsulation
- The source code and implementation of Django CSRF Middleware
guess what you like
Python hashlib module
The cover of Python 3 web crawler development (Second Edition) has been determined!
The introduction method of executing Python source code or Python source code file (novice, please enter the old bird and turn left)
[Python basics] explain Python basic functions in detail, including teaching and learning
Python web crawler - crawling cloud music review (4)
The first step of scientific research: create Python virtual environment on Linux server
Writing nmap scanning tool in Python -- multithreaded version
leetcode 2057. Smallest Index With Equal Value（python）
Bamboolib: this will be one of the most useful Python libraries you've ever seen
Python crawler actual combat, requests module, python realizes capturing a video barrage
- [algorithm learning] 1108 IP address invalidation (Java / C / C + + / Python / go / trust)
- Test platform series (71) Python timed task scheme
- Java AES / ECB / pkcs5padding encryption conversion Python 3
- Loguru: the ultimate Python log solution
- Blurring and anonymizing faces using OpenCV and python
- How fast Python sync and async execute
- Python interface automation test framework (basic) -- common data types list & set ()
- Python crawler actual combat, requests module, python realizes capturing video barrage comments of station B
- Python: several implementation methods of multi process
- Sword finger offer II 054 Sum of all values greater than or equal to nodes ｜ 538 ｜ 1038 (Java / C / C + + / Python / go / trust)
- How IOS developers learn python programming 3-operator 2
- How IOS developers learn python programming 2-operator 1
- [Python applet] 8 lines of code to realize file de duplication
- Python uses the pynvml tool to obtain the working status of GPU
- Data mining: Python actual combat multi factor analysis
- Manually compile opencv on MacOS and Linux and add it to Python / C + + / Java as a dependency
- Use Python VTK to batch read 2D slices and display 3D models
- Complete image cutting using Python version VTK
- Python interface automation test framework (basic) -- common data types Dict
- Django (make an epidemic data report)
- Python specific text extraction in actual combat challenges the first step of efficient office
- Daily python, Part 8 - if statement
- Django model class 1
- The same Python code draws many different cherry trees. Which one do you like?
- Python code reading (Chapter 54): Fibonacci sequence
- Django model class 2
- Python crawler Basics
- Mapping 3D model surface distances using Python VTK
- How to implement encrypted message signature and verification in Python -- HMAC
- leetcode 1945. Sum of Digits of String After Convert（python）
- leetcode 2062. Count Vowel Substrings of a String（python）
- Analysis of Matplotlib module of Python visualization
- Django permission management
- Python integrated programming -- visual hot search list and new epidemic situation map
- [Python data collection] scripy realizes picture download
- Python interface automation test framework (basic part) -- loop statement of process control for & while
- Daily python, Chapter 9, while loop
- Van * Python | save the crawled data with docx and PDF
- Five life saving Python tips
- Django frequency control