preface
HTTP interface testing is very simple. No matter tools, frameworks or platforms, as long as a few good points are good tools.
- Test data problems: for example, deleting interfaces and repeated execution can keep the results consistent. Data initialization must be done.
- Interface dependency: interface B depends on the return value of interface A, and interface C depends on the return value of interface B.
- Encryption: different interfaces have different encryption rules. Some use timestamp, md5, base64 and AES. How to provide these capabilities.
- Assertion problem: the structure returned by some interfaces is very complex. How to assert flexibly.
For the above problems, tools and platforms either do not support or are troublesome, but the framework is the most flexible.
unittest/pytest + requests/https just write the code directly, which is simple and flexible.
So it's also to write code. Framework A needs 10 lines and framework B only needs 5 lines, but it doesn't fail. Of course, I choose fewer. After all, life is short.
seldom is suitable for personal interface automation projects. It has the following advantages.
- You can write less code
- Automatically generate HTML/XML test reports
- Support parameterization and reduce duplicate code
- Support generating random data
- Support conversion of har file to case
- Support database operation
These are the functions supported by seldom. We only need to integrate the HTTP interface library and provide powerful assertions. seldom 2.0} adds automatic test support for HTTP interface.
Seldom's compatible Requests API is as follows:
seldom | requests |
---|---|
self.get() | requests.get() |
self.post() | requests.post() |
self.put() | requests.put() |
self.delete() | requests.delete() |
Seldom VS Request+unittest
Let's take a look at how unittest + requests are used for interface automation:
import unittest import requests class TestAPI(unittest.TestCase): def test_get_method(self): payload = {'key1': 'value1', 'key2': 'value2'} r = requests.get("http://httpbin.org/get", params=payload) self.assertEqual(r.status_code, 200) if __name__ == '__main__': unittest.main()
This is actually very concise. The same use case is implemented with seldom.
# test_req.py import seldom class TestAPI(seldom.TestCase): def test_get_method(self): payload = {'key1': 'value1', 'key2': 'value2'} self.get("http://httpbin.org/get", params=payload) self.assertStatusCode(200) if __name__ == '__main__': seldom.main()
The main simplification point is the processing of the returned data of the interface. Of course, seldom's real advantages are assertions, logging, and reporting.
har to case
For those who are not familiar with the Requests library, it is still a little difficult to write interface test cases through seldom. Thus, seldom provides the command to convert the har file to case.
First, open fiddler tool to capture packets and select a request.
Then, select the menu bar: file - > Export Sessions - > Selected Sessions
Select the file format to export.
Click next # to save as demo Har file.
Finally, it is converted to demo through seldom -h2c} Py} script file.
> seldom -h2c .\demo.har .\demo.py 2021-06-14 18:05:50 [INFO] Start to generate testcase. 2021-06-14 18:05:50 [INFO] created file: D:\.\demo.py
demo.py file.
import seldom class TestRequest(seldom.TestCase): def start(self): self.url = "http://httpbin.org/post" def test_case(self): headers = {"User-Agent": "python-requests/2.25.0", "Accept-Encoding": "gzip, deflate", "Accept": "application/json", "Connection": "keep-alive", "Host": "httpbin.org", "Content-Length": "36", "Origin": "http://httpbin.org", "Content-Type": "application/json", "Cookie": "lang=zh"} cookies = {"lang": "zh"} self.post(self.url, json={"key1": "value1", "key2": "value2"}, headers=headers, cookies=cookies) self.assertStatusCode(200) if __name__ == '__main__': seldom.main()
Run test
Open debug mode seldom Run (debug = true) runs the above use case.
> python .\test_req.py 2021-04-29 18:19:39 [INFO] A run the test in debug mode without generating HTML report! 2021-04-29 18:19:39 [INFO] __ __ ________ / /___/ /___ ____ ____ / ___/ _ \/ / __ / __ \/ __ ` ___/ (__ ) __/ / /_/ / /_/ / / / / / / /____/\___/_/\__,_/\____/_/ /_/ /_/ ----------------------------------------- @itest.info test_get_method (test_req.TestAPI) ... ----------- Request 🚀 --------------- url: http://httpbin.org/get method: GET ----------- Response 🛬️ ------------- type: json {'args': {'key1': 'value1', 'key2': 'value2'}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.22.0', 'X-Amzn-Trace-Id': 'Root=1-608a883c-7b355ba81fcd0d287566405a'}, 'origin': '183.178.27.36', 'url': 'http://httpbin.org/get?key1=value1&key2=value2'} ok ---------------------------------------------------------------------- Ran 1 test in 0.619s OK
It can be clearly seen through logs / reports.
- Requested method
- Request url
- Type of response
- Response data
Stronger assertions
Asserting the data returned by the interface is a very important work of interface automation.
assertJSON
The interface returns the following results:
{ "args": { "hobby": [ "basketball", "swim" ], "name": "tom" } }
My goal is to assert the contents of the name , and , hobby , sections. seldom can assert against JSON files.
import seldom class TestAPI(seldom.TestCase): def test_assert_json(self): payload = {'name': 'tom', 'hobby': ['basketball', 'swim']} self.get("http://httpbin.org/get", params=payload) assert_json = {'args': {'hobby': ['swim', 'basketball'], 'name': 'tom'}} self.assertJSON(assert_json)
Run log
test_get_method (test_req.TestAPI) ... ----------- Request 🚀 --------------- url: http://httpbin.org/get method: GET ----------- Response 🛬️ ------------- type: json {'args': {'hobby': ['basketball', 'swim'], 'name': 'tom'}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.22.0', 'X-Amzn-Trace-Id': 'Root=1-608a896d-48fac4f6139912ba01d2626f'}, 'origin': '183.178.27.36', 'url': 'http://httpbin.org/get?name=tom&hobby=basketball&hobby=swim'} 💡 Assert data has not key: headers 💡 Assert data has not key: origin 💡 Assert data has not key: url ok ---------------------------------------------------------------------- Ran 1 test in 1.305s OK
seldom will also prompt you which fields are not asserted.
assertPath
The data returned by the interface is as follows:
{ "args": { "hobby": ["basketball", "swim"], "name": "tom" } }
In seldom, you can assert through path:
import seldom class TestAPI(seldom.TestCase): def test_assert_path(self): payload = {'name': 'tom', 'hobby': ['basketball', 'swim']} self.get("http://httpbin.org/get", params=payload) self.assertPath("name", "tom") self.assertPath("args.hobby[0]", "basketball")
assertSchema
Sometimes you don't care what the data itself is, but you need to assert the type of data. assertSchema {is an assertion method based on jsonschema implementation.
jsonschema: Learn | JSON Schema
The data returned by the interface is as follows:
{ "args": { "hobby": ["basketball", "swim"], "name": "tom", "age": "18" } }
In seldom, assertions can be made by using JSON schema:
import seldom class TestAPI(seldom.TestCase): def test_assert_schema(self): payload = {"hobby": ["basketball", "swim"], "name": "tom", "age": "18"} self.get("/get", params=payload) schema = { "type": "object", "properties": { "args": { "type": "object", "properties": { "age": {"type": "string"}, "name": {"type": "string"}, "hobby": { "type": "array", "items": { "type": "string" }, } } } }, } self.assertSchema(schema)
Feel again that the assertions provided by seldom are very flexible and powerful.
Interface data dependency
In scenario testing, we need to use the data of the previous interface to call the next interface.
import seldom class TestRespData(seldom.TestCase): def test_data_dependency(self): """ Test for interface data dependencies """ headers = {"X-Account-Fullname": "bugmaster"} self.get("/get", headers=headers) self.assertStatusCode(200) username = self.response["headers"]["X-Account-Fullname"] self.post("/post", data={'username': username}) self.assertStatusCode(200)
seldom provides self Response is used to record the results returned by the previous interface and can be used directly.
Data driven
seldom originally provides a powerful data driver, which is very convenient for interface testing.
@data
import seldom from seldom import data class TestDDT(seldom.TestCase): @data([ ("key1", 'value1'), ("key2", 'value2'), ("key3", 'value3') ]) def test_data(self, key, value): """ Data-Driver Tests """ payload = {key: value} self.post("/post", data=payload) self.assertStatusCode(200) self.assertEqual(self.response["form"][key], value)
@file_data
Create data JSON data file
{ "login": [ ["admin", "admin123"], ["guest", "guest123"] ] }
Via file_data to achieve data-driven.
import seldom from seldom import file_data class TestDDT(seldom.TestCase): @file_data("data.json", key="login") def test_data(self, username, password): """ Data-Driver Tests """ payload = {username: password} self.post("http://httpbin.org/post", data=payload) self.assertStatusCode(200) self.assertEqual(self.response["form"][username], password)
Change the data file (csv/excel/yaml), refer to
Randomly generate test data
seldom provides the method of randomly generating test data, which can generate some common data.
import seldom from seldom import testdata class TestAPI(seldom.TestCase): def test_data(self): phone = testdata.get_phone() payload = {'phone': phone} self.get("http://httpbin.org/get", params=payload) self.assertPath("args.phone", phone)
For more types of test data, refer to
Database operation
seldom supports sqlite3 and MySQL database operations.
sqlite3 | MySQL |
---|---|
delete_data() | delete_data() |
insert_data() | insert_data() |
select_data() | select_data() |
update_data() | update_data() |
init_table() | init_table() |
close() | close() |
Connect to database
Connecting to sqlit3 database
from seldom.db_operation import SQLiteDB db = SQLiteDB(r"D:\learnAPI\db.sqlite3")
Connect to MySQL database (required)
- Install pymysql driver
> pip install pymysql
- link
from seldom.db_operation import MySQLDB db = MySQLDB(host="127.0.0.1", port="3306", user="root", password="123", database="db_name")
Operation method
- delete_data
Delete table data.
db.delete_data(table="user", where={"id":1})
- insert_data
Insert a piece of data.
data = {'id': 1, 'username': 'admin', 'password': "123"}, db.insert_data(table="user", data=data)
- select_data
Query table data.
result = db.select_data(table="user", where={"id":1, "name": "tom"}) print(result)
- update_data
Update table data.
db.update_data(table="user", data={"name":"new tom"}, where={"name": "tom"})
- init_table
To insert data in batches, clear the table data before inserting.
datas = { 'api_event': [ {'id': 1, 'name': 'Red rice Pro release conference'}, {'id': 2, 'name': 'The number of participants is 0'}, {'id': 3, 'name': 'The current status is 0 closed'}, {'id': 4, 'name': 'Press conference is over'}, {'id': 5, 'name': 'Xiaomi 5 press conference'}, ], 'api_guest': [ {'id': 1, 'real_name': 'alen'}, {'id': 2, 'real_name': 'has sign'}, {'id': 3, 'real_name': 'tom'}, ] } db.init_table(datas)
- close
Close the database connection.
db.close()
Finally, the project of implementing interface automation test based on seldom: https://github.com/defnngj/pyrequest2
welfare
Welfare release, from introduction to actual combat, from e-books to real interview questions, should be the most comprehensive and complete war preparation warehouse for [software testing] friends. This warehouse has also accompanied me through the most difficult journey. I hope it can also help you.
If you need this learning material, you can scan WeChat's official CSDN official account below (100% free access).