HttpRunner V3.x學習筆記系列 (四) -- 測試用例結構及用例配置config


一、官方首推pytest格式

httprunner可以支持三種格式的用例,分別是pytest、yaml和json。yaml和json是以前的版本所使用的用例格式,但是在3.x版本上,官方強烈建議使用的是pytest格式的用例。

 

上圖是來自官方的用例格式關系圖,可以看出來,httprunner再對於第三方導出的har文件進行了轉換處理,有的人喜歡轉換成json,有的人喜歡轉換成yaml。但是最終,還是通過解析json格式的文件,生成pytest的python文件。

二、用例結構

錄制生成的case很便捷,但是這並不是說,不需要我們做任何的改動了。在實踐的過程中,我們仍然會根據我們實際項目的不同需求來對case作進一步的調整,所以徹底的了解case的構造尤為重要。
首先,我錄制了一個百度搜索“httprunner”的一個請求,轉換成pytest文件后如下:

 

可以看到:

每個測試用例都是 HttpRunner 的子類(一個類即為一個測試用例),並且必須具有兩個類屬性:configteststeps

  • 每個testcase都是HttpRunner的子類
  • 必須有兩個類屬性:config和teststeps。
  • 單個teststeps列表中的單個Step內部通過鏈式調用(RunRequest().get().with_params().with_header().with_cookies().validate().assert_equal())
  1. config:配置測試用例級設置,包括基礎url、驗證、變量、導出。
  2. teststeps:teststep的列表(list[Step]),每個步驟對應於一個API請求,也可以調用另一個testcase。此外,還支持variables/extract/validate/hooks機制來創建極其復雜的測試場景。
  3. 鏈式調用:HttpRunner v3.x 的最強大功能之一是鏈式調用,使用它無需記住任何測試用例格式的詳細信息,並且在 IDE 中編寫測試用例時可以智能完成。可以看到一個case的請求,經過了各個環節的調用,這也是httprunner 3.x版本一大亮點。

 

 

三、httprunner的用例結構

補一個官方完整的一個demo代碼,並說說httprunner中的用例與自己編寫的測試用例之間的聯系。

 1 # NOTE: Generated By HttpRunner v3.1.4
 2 # FROM: testcases\demo_testcase_request.yml
 3 
 4 
 5 from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase
 6 
 7 
 8 class TestCaseDemoTestcaseRequest(HttpRunner):
 9 
10     config = (
11         Config("request methods testcase with functions")
12         .variables(
13             **{
14                 "foo1": "config_bar1",
15                 "foo2": "config_bar2",
16                 "expect_foo1": "config_bar1",
17                 "expect_foo2": "config_bar2",
18             }
19         )
20         .base_url("https://postman-echo.com")
21         .verify(False)
22         .export(*["foo3"])
23     )
24 
25     teststeps = [
26         Step(
27             RunRequest("get with params")
28             .with_variables(
29                 **{"foo1": "bar11", "foo2": "bar21", "sum_v": "${sum_two(1, 2)}"}
30             )
31             .get("/get")
32             .with_params(**{"foo1": "$foo1", "foo2": "$foo2", "sum_v": "$sum_v"})
33             .with_headers(**{"User-Agent": "HttpRunner/${get_httprunner_version()}"})
34             .extract()
35             .with_jmespath("body.args.foo2", "foo3")
36             .validate()
37             .assert_equal("status_code", 200)
38             .assert_equal("body.args.foo1", "bar11")
39             .assert_equal("body.args.sum_v", "3")
40             .assert_equal("body.args.foo2", "bar21")
41         ),
42         Step(
43             RunRequest("post raw text")
44             .with_variables(**{"foo1": "bar12", "foo3": "bar32"})
45             .post("/post")
46             .with_headers(
47                 **{
48                     "User-Agent": "HttpRunner/${get_httprunner_version()}",
49                     "Content-Type": "text/plain",
50                 }
51             )
52             .with_data(
53                 "This is expected to be sent back as part of response body: $foo1-$foo2-$foo3."
54             )
55             .validate()
56             .assert_equal("status_code", 200)
57             .assert_equal(
58                 "body.data",
59                 "This is expected to be sent back as part of response body: bar12-$expect_foo2-bar32.",
60             )
61         ),
62         Step(
63             RunRequest("post form data")
64             .with_variables(**{"foo2": "bar23"})
65             .post("/post")
66             .with_headers(
67                 **{
68                     "User-Agent": "HttpRunner/${get_httprunner_version()}",
69                     "Content-Type": "application/x-www-form-urlencoded",
70                 }
71             )
72             .with_data("foo1=$foo1&foo2=$foo2&foo3=$foo3")
73             .validate()
74             .assert_equal("status_code", 200)
75             .assert_equal("body.form.foo1", "$expect_foo1")
76             .assert_equal("body.form.foo2", "bar23")
77             .assert_equal("body.form.foo3", "bar21")
78         ),
79     ]
80 
81 
82 if __name__ == "__main__":
83     TestCaseDemoTestcaseRequest().test_start()
  1. httprunner中的testcase,其實說的就是上面的這一整個Python文件。
  2. teststeps列表中的Step,其實就是自己編寫case時候的一個個def test_xxx():pass。
  3. 而每一個Step內部,依然是按照 傳參——調用接口——斷言,這樣的過程來的。

 

 四、測試用例-config

在配置中,我們可以配置測試用例級級別的一些設置,比如基礎url、驗證、變量、導出。

# NOTE: Generated By HttpRunner v3.1.4
# FROM: testcases\demo_testcase_request.yml


from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase


class TestCaseDemoTestcaseRequest(HttpRunner):

    config = (
        Config("request methods testcase with functions")
        .variables(
            **{
                "foo1": "config_bar1",
                "foo2": "config_bar2",
                "expect_foo1": "config_bar1",
                "expect_foo2": "config_bar2",
            }
        )
        .base_url("https://postman-echo.com")
        .verify(False)
        .export(*["foo3"])
    )

    teststeps = [
        Step(
            RunRequest("get with params")
            .with_variables(
                **{"foo1": "bar11", "foo2": "bar21", "sum_v": "${sum_two(1, 2)}"}
            )
            .get("/get")
            .with_params(**{"foo1": "$foo1", "foo2": "$foo2", "sum_v": "$sum_v"})
            .with_headers(**{"User-Agent": "HttpRunner/${get_httprunner_version()}"})
            .extract()
            .with_jmespath("body.args.foo2", "foo3")
            .validate()
            .assert_equal("status_code", 200)
            .assert_equal("body.args.foo1", "bar11")
            .assert_equal("body.args.sum_v", "3")
            .assert_equal("body.args.foo2", "bar21")
        ),
        Step(
            RunRequest("post raw text")
            .with_variables(**{"foo1": "bar12", "foo3": "bar32"})
            .post("/post")
            .with_headers(
                **{
                    "User-Agent": "HttpRunner/${get_httprunner_version()}",
                    "Content-Type": "text/plain",
                }
            )
            .with_data(
                "This is expected to be sent back as part of response body: $foo1-$foo2-$foo3."
            )
            .validate()
            .assert_equal("status_code", 200)
            .assert_equal(
                "body.data",
                "This is expected to be sent back as part of response body: bar12-$expect_foo2-bar32.",
            )
        ),
        Step(
            RunRequest("post form data")
            .with_variables(**{"foo2": "bar23"})
            .post("/post")
            .with_headers(
                **{
                    "User-Agent": "HttpRunner/${get_httprunner_version()}",
                    "Content-Type": "application/x-www-form-urlencoded",
                }
            )
            .with_data("foo1=$foo1&foo2=$foo2&foo3=$foo3")
            .validate()
            .assert_equal("status_code", 200)
            .assert_equal("body.form.foo1", "$expect_foo1")
            .assert_equal("body.form.foo2", "bar23")
            .assert_equal("body.form.foo3", "bar21")
        ),
    ]


if __name__ == "__main__":
    TestCaseDemoTestcaseRequest().test_start()

上面是官方給出的一個例子

(1)  name(必填)

即用例名稱,這是一個必填參數。測試用例名稱,將顯示在執行日志和測試報告中。比如,官方給出的case里,加入name。

 

執行用例:

pytest -s -v demo_testcase_ref_test.py

 運行后,在debug日志里,可以看到用例名稱被展示出來。

 

 (2)  base_url(選填)

這個配置一般在多環境切換中最常用。
比如你的這套測試用例在多套環境(測試環境,生成環境)都要使用,那么就可以把基礎地址(舉例http://demo.qa.com),設置進去。在后面的teststep中,只需要填上接口的相對路徑就好了(舉例 /get)。
這樣的話,切換環境運行,只需要修改base_url即可。

 

 (3) variables(選填) -- 變量和值一一對應

在 HttpRunner 中,支持變量聲明(variables)和引用($var)的機制。調用函數(${func($var)})

在 config 和 test 中均可以通過 variables 關鍵字定義變量,然后在測試步驟中可以通過 $ + 變量名稱 的方式引用變量。

區別在於:

在 config 中定義的變量為全局的,整個測試用例(testcase)的所有地方均可以引用;

在 test 中定義的變量作用域僅局限於當前測試步驟(teststep)

config這里可以存放一些公共的變量,可以在測試用例里引用。這里大家可以記住這個“公共”的詞眼,因為在后面的Step中,還會有步驟變量。

比如說,我的接口有個傳參是不變的,比如用戶名username,而且后面的每個Step都會用到這個傳參,那么username就可以放在config的公共變量里。
另外,Step里的變量優先級是比config里的變量要高的,如果step和config中variables聲明的參數名相同,在運行測試用例的時候會優先取step里面的參數值。

注意:一般寫用例的時候,最好把可能會變的參數單獨寫個變量。做到測試數據和代碼的分離,以便后續維護。

全局變量

如果要設置一個全局變量,需把變量聲明(variables)放到config下

pytest格式:

# NOTE: Generated By HttpRunner v3.1.4
# FROM: testcases\demo_testcase_request.yml


from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase


class TestCaseDemoTestcaseRequest(HttpRunner):

    config = (
        Config("request methods testcase with functions")
        .variables(
            **{
                "foo1": "config_bar1",
                "foo2": "config_bar2",
                "expect_foo1": "config_bar1",
                "expect_foo2": "config_bar2",
            }
        )
        .base_url("https://postman-echo.com")
        .verify(False)
        .export(*["foo3"])
    )

    teststeps = [
        Step(
            RunRequest("get with params")
            .with_variables(
                **{"foo1": "bar11", "foo2": "bar21", "sum_v": "${sum_two(1, 2)}"}
            )
            .get("/get")
            .with_params(**{"foo1": "$foo1", "foo2": "$foo2", "sum_v": "$sum_v"})
            .with_headers(**{"User-Agent": "HttpRunner/${get_httprunner_version()}"})
            .extract()
            .with_jmespath("body.args.foo2", "foo3")
            .validate()
            .assert_equal("status_code", 200)
            .assert_equal("body.args.foo1", "bar11")
            .assert_equal("body.args.sum_v", "3")
            .assert_equal("body.args.foo2", "bar21")
        ),
        Step(
            RunRequest("post raw text")
            .with_variables(**{"foo1": "bar12", "foo3": "bar32"})
            .post("/post")
            .with_headers(
                **{
                    "User-Agent": "HttpRunner/${get_httprunner_version()}",
                    "Content-Type": "text/plain",
                }
            )
            .with_data(
                "This is expected to be sent back as part of response body: $foo1-$foo2-$foo3."
            )
            .validate()
            .assert_equal("status_code", 200)
            .assert_equal(
                "body.data",
                "This is expected to be sent back as part of response body: bar12-$expect_foo2-bar32.",
            )
        ),
        Step(
            RunRequest("post form data")
            .with_variables(**{"foo2": "bar23"})
            .post("/post")
            .with_headers(
                **{
                    "User-Agent": "HttpRunner/${get_httprunner_version()}",
                    "Content-Type": "application/x-www-form-urlencoded",
                }
            )
            .with_data("foo1=$foo1&foo2=$foo2&foo3=$foo3")
            .validate()
            .assert_equal("status_code", 200)
            .assert_equal("body.form.foo1", "$expect_foo1")
            .assert_equal("body.form.foo2", "bar23")
            .assert_equal("body.form.foo3", "bar21")
        ),
    ]


if __name__ == "__main__":
    TestCaseDemoTestcaseRequest().test_start()

 

 ymal格式:

config:
    name: "request methods testcase with functions"
    variables:
        foo1: config_bar1
        foo2: config_bar2
        expect_foo1: config_bar1
        expect_foo2: config_bar2
    base_url: "https://postman-echo.com"
    verify: False
    export: ["foo3"]

teststeps:
-
    name: get with params
    variables:
        foo1: bar11
        foo2: bar21
        sum_v: "${sum_two(1, 2)}"
    request:
        method: GET
        url: /get
        params:
            foo1: $foo1
            foo2: $foo2
            sum_v: $sum_v
        headers:
            User-Agent: HttpRunner/${get_httprunner_version()}
    extract:
        foo3: "body.args.foo2"
    validate:
        - eq: ["status_code", 200]
        - eq: ["body.args.foo1", "bar11"]
        - eq: ["body.args.sum_v", "3"]
        - eq: ["body.args.foo2", "bar21"]
-
    name: post raw text
    variables:
        foo1: "bar12"
        foo3: "bar32"
    request:
        method: POST
        url: /post
        headers:
            User-Agent: HttpRunner/${get_httprunner_version()}
            Content-Type: "text/plain"
        data: "This is expected to be sent back as part of response body: $foo1-$foo2-$foo3."
    validate:
        - eq: ["status_code", 200]
        - eq: ["body.data", "This is expected to be sent back as part of response body: bar12-$expect_foo2-bar32."]
-
    name: post form data
    variables:
        foo2: bar23
    request:
        method: POST
        url: /post
        headers:
            User-Agent: HttpRunner/${get_httprunner_version()}
            Content-Type: "application/x-www-form-urlencoded"
        data: "foo1=$foo1&foo2=$foo2&foo3=$foo3"
    validate:
        - eq: ["status_code", 200]
        - eq: ["body.form.foo1", "$expect_foo1"]
        - eq: ["body.form.foo2", "bar23"]
        - eq: ["body.form.foo3", "bar21"]

引用foo1和foo2變量用$foo1,$foo2

 

局部變量

如果在step下聲明的變量,作用域只在當前step下有效。聲明變量用with_variables,變量和對應值用鍵值對,如

Step(
            RunRequest("post raw text")
            .with_variables(**{"foo1": "bar12", "foo3": "bar32"})
            .post("/post")
            .with_headers(
                **{
                    "User-Agent": "HttpRunner/${get_httprunner_version()}",
                    "Content-Type": "text/plain",
                }
            )
            .with_data(
                "This is expected to be sent back as part of response body: $foo1-$foo2-$foo3."
            )
            .validate()
            .assert_equal("status_code", 200)
            .assert_equal(
                "body.data",
                "This is expected to be sent back as part of response body: bar12-$expect_foo2-bar32.",
            )
        ),

完整代碼如下:

# NOTE: Generated By HttpRunner v3.1.4
# FROM: testcases\demo_testcase_request.yml


from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase


class TestCaseDemoTestcaseRequest(HttpRunner):

    config = (
        Config("request methods testcase with functions")
        .variables(
            **{
                "foo1": "config_bar1",
                "foo2": "config_bar2",
                "expect_foo1": "config_bar1",
                "expect_foo2": "config_bar2",
            }
        )
        .base_url("https://postman-echo.com")
        .verify(False)
        .export(*["foo3"])
    )

    teststeps = [
        Step(
            RunRequest("get with params")
            .with_variables(
                **{"foo1": "bar11", "foo2": "bar21", "sum_v": "${sum_two(1, 2)}"}
            )
            .get("/get")
            .with_params(**{"foo1": "$foo1", "foo2": "$foo2", "sum_v": "$sum_v"})
            .with_headers(**{"User-Agent": "HttpRunner/${get_httprunner_version()}"})
            .extract()
            .with_jmespath("body.args.foo2", "foo3")
            .validate()
            .assert_equal("status_code", 200)
            .assert_equal("body.args.foo1", "bar11")
            .assert_equal("body.args.sum_v", "3")
            .assert_equal("body.args.foo2", "bar21")
        ),
        Step(
            RunRequest("post raw text")
            .with_variables(**{"foo1": "bar12", "foo3": "bar32"})
            .post("/post")
            .with_headers(
                **{
                    "User-Agent": "HttpRunner/${get_httprunner_version()}",
                    "Content-Type": "text/plain",
                }
            )
            .with_data(
                "This is expected to be sent back as part of response body: $foo1-$foo2-$foo3."
            )
            .validate()
            .assert_equal("status_code", 200)
            .assert_equal(
                "body.data",
                "This is expected to be sent back as part of response body: bar12-$expect_foo2-bar32.",
            )
        ),
        Step(
            RunRequest("post form data")
            .with_variables(**{"foo2": "bar23"})
            .post("/post")
            .with_headers(
                **{
                    "User-Agent": "HttpRunner/${get_httprunner_version()}",
                    "Content-Type": "application/x-www-form-urlencoded",
                }
            )
            .with_data("foo1=$foo1&foo2=$foo2&foo3=$foo3")
            .validate()
            .assert_equal("status_code", 200)
            .assert_equal("body.form.foo1", "$expect_foo1")
            .assert_equal("body.form.foo2", "bar23")
            .assert_equal("body.form.foo3", "bar21")
        ),
    ]


if __name__ == "__main__":
    TestCaseDemoTestcaseRequest().test_start()

 

(4) verify(選填)

 request請求一個https鏈接時,會驗證一次SSL證書。當目標網站使用的是自簽名證書時,則會拋出下圖的異常。

request模塊發送請求函數有個參數verify值默認為True

verify用來決定是否驗證服務器TLS證書的開關。
通常設置為False,當請求https請求時,就會跳過驗證。如果你運行時候發現拋錯SSLError,可以檢查一下是不是verify沒傳,或者設置了True。

解決方法:

在request下添加一個verify參數,值為false

config:
    name: "request methods testcase: reference testcase"
    variables:
        foo1: testsuite_config_bar1
        expect_foo1: testsuite_config_bar1
        expect_foo2: config_bar2
    base_url: "https://postman-echo.com" verify: False #全局設置 request忽略對SSL證書的校驗

teststeps:
-
    name: request with functions
    variables:
        foo1: testcase_ref_bar1
        expect_foo1: testcase_ref_bar1
    testcase: testcases/demo_testcase_request.yml
    export:
        - foo3
-
    name: post form data
    variables:
        foo1: bar1
    request:
        verify:False # 局部設置 只對當前用例有效 request忽略對SSL證書的校驗
        method: POST
        url: /post
        headers:
            User-Agent: HttpRunner/${get_httprunner_version()}
            Content-Type: "application/x-www-form-urlencoded"
        data: "foo1=$foo1&foo2=$foo3"
    validate:
        - eq: ["status_code", 200]
        - eq: ["body.form.foo1", "bar1"]
        - eq: ["body.form.foo2", "bar21"]

 

(5) export(選填)

 導出的變量,主要是用於Step之間參數的傳遞。還是以上面的官方代碼為例:

可以指定要導出的變量,以供后續Step引用。
可以看的.export()內部是一個列表[],這里可以用來導出多個變量。

  1. 在config中配置export“foo3”這個變量。
  2. 在第一個Step中,.extract() 提取了"body.args.foo2"給變量“foo3”。
  3. 在第二個Step中,引用變量"foo3"。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM