0x00 Preface
This article is more about Python Back end programmers . Let me share my understanding of writing tests .
In this issue, let's talk about testing .
The contents of this article are as follows :
▼ How to improve through testing Python The robustness of the code : section
0x00 Preface : section
▼ 0x01 Classification of tests : section
What tests does the back end mainly focus on : section
▼ 0x02 Why write tests : section
Let novices understand the code faster : section
Make the code release more confident : section
Make the program easier to refactor : section
Accelerate team development : section
▼ 0x03 Why not write tests : section
Problems that testing cannot solve : section
Why is inappropriate testing a burden : section
Not all places are easy to test : section
▼ 0x04 Write Python Some considerations for testing : section
Environmental isolation of the project : section
The basic environment for testing : section
Single measurement / Dynamometer / end-to-end : section
How to handle external services : section
other Pytest Tips : section
0xEE Reference resources : section
0x01 Classification of tests
There are many kinds of tests , According to the method of test design, it can be divided into :1. Black box 2. White box
According to the test purpose :
Code coverage as the name suggests , That is, the proportion of test cases covering running code .
What tests does the back end mainly focus on
0x02 Why write tests
Let's talk about the advantages of testing .
Why write tests to cover code .
It's not like not writing , Nor is it crazy to write . You may have some doubts here ? Writing tests also speeds up ?Are you kidding?
Explain one by one .
Take a simplified example ,『 Users to place the order 』 To 『 Customer receiving 』.
Let novices understand the code faster
The data in the test case , It is often the best test data set that can run through a piece of code .
If , A programmer wrote 『 Place an order - Pay online - Confirm receipt 』 Integration testing . As the person who just took over the code . In the shortest possible time , Understand the whole process by reading the test code .
Yes fixture, Novices can know in a very short time setup Basic data that can make the project run
Of course , If you write too many tests , It can also make reading difficult .
Make the code release more confident
Write tests , To verify that the code is working correctly .
A process , It usually contains several sub processes , The subprocess is right , The whole process is right .
If you don't write tests, you can fully cover some key processes , Will lead to
Modify or add a sub process , It is necessary to run a new process for human flesh test .
If the human flesh test is too cumbersome , The average programmer will skip this step and cause online problems .
Make the program easier to refactor
When you know that writing test code has so many advantages , Your first reaction is , I know that , however , Writing tests can also speed up development ?
Of course , You need to know , A valuable product that needs to be maintained , It is often necessary to constantly modify the process .
In limine ,PM Tell you that you only need to place an order to buy something , later , To add the full discount , Later, various types of coupons will be added , Then you have to connect with third-party services , Then you have to deal with all kinds of users who don't follow the process you set ….
Write tests , By constantly adding some tests , Realize the test automation of the whole process . Form a set of test code to test the project . The process is so long , You count on human flesh to test ?
Of course , Premise is
Accelerate team development
Although I say , What I write is to speed up the development of the team , But actually , It also applies to individuals .
Unless , You write rendered pages …. What you see is what you get . No testing required
0x03 Why not write tests
According to the software world famous 『 There is no silver bullet 』 theory , Having said the superiority of the test , Let's also talk about the limitations of testing , There are three main points :
Problems that testing cannot solve
Testing can ensure the running quality of the code , But you can't guarantee the quality of your code , There is no guarantee that the product design logic problems .
in other words
When you find it hard to write test code , You should consider refactoring your program .
Why is inappropriate testing a burden
What people have to get used to is :
Put it on the test , test , It can't be measured .
Wrote a IF ELSE , You need to test two groups , Wrote one more IF ELSE, You will test four groups . If it is a complicated process , Basically, it's hard to finish a comprehensive test .
My idea is :
Not all places are easy to test
Not all places are easy to test .
If this kind of business is done in depth , need Mock Lose a lot of logic .
0x04 Write Python Some considerations for testing
Environmental isolation of the project
From the perspective of the overall project , The environment in which the code runs should distinguish between Local/Test/Stage/Prod Four environments .
The reason for this distinction , It's because different environments have different priorities .
The basic environment for testing
Generally, there is one Docker-Compose file , To quickly initialize the test environment .
such as WebApp / Celery Worker / Celery Beats / Redis / RabbitMQ / MySQL Sure make start Start these services directly .
Single measurement / Dynamometer / end-to-end
I said before , The backend needs to pay attention to the following tests
Performance testing can generally monitor where the system has bottlenecks in advance . See the scene , Generally, observation and monitoring will make it easier to predict the bottleneck of the system , This is more about tuning , Let's put it later .
The framework assumes that we use Flask , Suppose there is such a BBS( I know you want to roast about why you use your blog /BBS For example , Too lazy to explain too much background knowledge about business scenarios , flee …)
organization Organization Released a Thread
user User In this Thread the Reply 『 Unregistered users can see 』
Administrators Admin Found out User It seems that some information should not be published . Delete Reply.『 Unregistered users cannot see / The owner is visible 』
Last User Make a complaint ,Admin I found that the things released were quite OK Of , Give through .『 Unregistered users can see 』
tests # Test file directory ├── init.py ├── conftest.py # Here are collections that may be referenced by subdirectories ├── e2e # 『 End to end testing 』 │ ├── init.py │ ├── test_viewer.py │ ├── test_user.py │ ├── test_admin.py │ └── test_organization.py ├── functional # 『 A functional test 』 │ ├── init.py │ ├── test_do_simple_reply.py │ ├── test_do_complex_reply.py │ └── test_helper.py ├── unit # 『 unit testing 』 | ├── init.py | ├── test_auth.py | └── test_calc_some_thing.py ├── test_auth_helper.py # Store the basic code used to switch identities ├── test_const.py └── test_factory_helper.py # It can be used to initialize data in batches
This process is not complicated , But enough to write a test .
The former is simpler , The latter is relatively closer to integration testing . Each have advantages and disadvantages . I usually do a few more pull-up tests on key processes .
But the pull-up test has one more problem to solve , namely , User login authentication . You call a Service When , As an anonymous user / User's identity / Admin / Org Called .
That is, when calling different Service When it comes to solving problems , You may need to switch identities quickly . After identity switching, speed switching back . therefore ,test auth helper Come out .helper There's a switch as function , Every time you need to switch identities , hold g The login snapshot in the variable g.user g.admin g.org push To LocalStack In the stack (from werkzeug.local import LocalStack), Call complete Service Again Pop come out .
Pull it up to test the effect is like this .
def test_complex_process(org, user, admin):
with switch_as_org(org) as org: # 1. organization Organization Released a Thread
thread = publish_thread_by_org()
with switch_as_user(user) as user: # 2. user User In this Thread the Reply
reply = reply_thread(thread)
assert reply
with switch_as_anonymous() as anonymous_user:
_thread = see_thread(thread)
assert reply in _thread.replies # 『 Unregistered users can see 』
with switch_as_admin() as admin: # 3. Administrators Admin Found out User It seems that some information should not be published . Delete Reply.
delete_reply(reply)
assert reply.deleled
with switch_as_anonymous() as anonymous_user:『 Unregistered users cannot see 』
_thread = see_thread(thread)
assert reply not in _thread.replies
# ad locum , My identity is still user
_thread = see_thread(thread)
assert reply in _thread.replies # 『Ower Users can see 』
# 4. Last User Make a complaint ,Admin I found that the things released were quite OK Of , Give through .『 Unregistered users can see 』
As a developer , You just need to make the test run smoothly and the basic development is completed . In the process , You can also better comb your code .
How to handle external services
When pulling it up for testing , If we have one more process , Users can pay appreciation through wechat reply, This has to rely on external services .
And when you pull it up for testing , There will be a very embarrassing problem , Because the interfaces above me are of large granularity , I appreciate the very small process in this process , You must go through wechat http request .
The solution is simple .mock Drop the function requesting wechat . Call the payment callback function manually , that will do .
Of course , about http request , You can also use responses This artifact is used to quickly mock Artifact requests Of response
The general usage is as follows
def mock_success_pay():
def request_callback(request):
headers = {}
dispatch_callback(data=data)
return 200, headers, resp_body
responses.add_callback(
responses.POST,
PAY_URL,
callback=request_callback,
content_type="application/json",
)
@responses.activate
def test_pay(user):
mock_success_pay()
switch_as_user(user) as u:
order = pay_order(u)
assert order.status == "PAID"
other Pytest Tips
sometimes ipdb Than pdb It is not only a little better to use . How to be in pytest For internal use ?
pytest -v --pdb --pdbcls=IPython.terminal.debugger:Pdb
The above is all the content shared this time , Want to know more python Welcome to official account :Python Programming learning circle , send out “J” Free access to , Daily dry goods sharing