mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-11 18:11:21 +08:00
locusts support weight feature
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
__title__ = 'HttpRunner'
|
||||
__description__ = 'One-stop solution for HTTP(S) testing.'
|
||||
__url__ = 'https://github.com/HttpRunner/HttpRunner'
|
||||
__version__ = '1.5.14'
|
||||
__version__ = '1.5.15'
|
||||
__author__ = 'debugtalk'
|
||||
__author_email__ = 'mail@debugtalk.com'
|
||||
__license__ = 'MIT'
|
||||
|
||||
@@ -6,4 +6,4 @@ try:
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
from httprunner.api import HttpRunner, LocustRunner
|
||||
from httprunner.api import HttpRunner
|
||||
|
||||
@@ -255,22 +255,3 @@ class HttpRunner(object):
|
||||
html_report_name,
|
||||
html_report_template
|
||||
)
|
||||
|
||||
|
||||
class LocustRunner(object):
|
||||
|
||||
def __init__(self, locust_client):
|
||||
self.runner = HttpRunner(http_client_session=locust_client)
|
||||
|
||||
def run(self, path):
|
||||
try:
|
||||
self.runner.run(path)
|
||||
except exceptions.MyBaseError as ex:
|
||||
# TODO: refactor
|
||||
from locust.events import request_failure
|
||||
request_failure.fire(
|
||||
request_type=test.testcase_dict.get("request", {}).get("method"),
|
||||
name=test.testcase_dict.get("request", {}).get("url"),
|
||||
response_time=0,
|
||||
exception=ex
|
||||
)
|
||||
|
||||
@@ -14,8 +14,13 @@ class Context(object):
|
||||
""" init Context with testcase variables and functions.
|
||||
"""
|
||||
# testcase level context
|
||||
## TESTCASE_SHARED_VARIABLES_MAPPING and TESTCASE_SHARED_FUNCTIONS_MAPPING will not change.
|
||||
self.TESTCASE_SHARED_VARIABLES_MAPPING = variables or OrderedDict()
|
||||
## TESTCASE_SHARED_VARIABLES_MAPPING and TESTCASE_SHARED_FUNCTIONS_MAPPING are unchangeable.
|
||||
if isinstance(variables, list):
|
||||
self.TESTCASE_SHARED_VARIABLES_MAPPING = utils.convert_mappinglist_to_orderdict(variables)
|
||||
else:
|
||||
# dict
|
||||
self.TESTCASE_SHARED_VARIABLES_MAPPING = variables or OrderedDict()
|
||||
|
||||
self.TESTCASE_SHARED_FUNCTIONS_MAPPING = functions or OrderedDict()
|
||||
|
||||
# testcase level request, will not change
|
||||
|
||||
@@ -987,3 +987,50 @@ def load_tests(path, dot_env_path=None):
|
||||
testcases_list = []
|
||||
|
||||
return testcases_list
|
||||
|
||||
|
||||
def load_locust_tests(path, dot_env_path=None):
|
||||
""" load locust testcases
|
||||
|
||||
Args:
|
||||
path (str): testcase/testsuite file path.
|
||||
dot_env_path (str): specified .env file path
|
||||
|
||||
Returns:
|
||||
dict: locust testcases with weight
|
||||
{
|
||||
"config": {...},
|
||||
"tests": [
|
||||
# weight 3
|
||||
[teststep11],
|
||||
[teststep11],
|
||||
[teststep11],
|
||||
# weight 2
|
||||
[teststep21, teststep22],
|
||||
[teststep21, teststep22]
|
||||
]
|
||||
}
|
||||
|
||||
"""
|
||||
raw_testcase = load_file(path)
|
||||
project_mapping = load_project_tests(path, dot_env_path)
|
||||
|
||||
config = {
|
||||
"refs": project_mapping
|
||||
}
|
||||
tests = []
|
||||
for item in raw_testcase:
|
||||
key, test_block = item.popitem()
|
||||
|
||||
if key == "config":
|
||||
config.update(test_block)
|
||||
elif key == "test":
|
||||
teststeps = _load_teststeps(test_block, project_mapping)
|
||||
weight = test_block.pop("weight", 1)
|
||||
for _ in range(weight):
|
||||
tests.append(teststeps)
|
||||
|
||||
return {
|
||||
"config": config,
|
||||
"tests": tests
|
||||
}
|
||||
|
||||
@@ -40,13 +40,10 @@ def gen_locustfile(testcase_file_path):
|
||||
"templates",
|
||||
"locustfile_template"
|
||||
)
|
||||
testcases = loader.load_tests(testcase_file_path)
|
||||
host = testcases[0].get("config", {}).get("request", {}).get("base_url", "")
|
||||
|
||||
with io.open(template_path, encoding='utf-8') as template:
|
||||
with io.open(locustfile_path, 'w', encoding='utf-8') as locustfile:
|
||||
template_content = template.read()
|
||||
template_content = template_content.replace("$HOST", host)
|
||||
template_content = template_content.replace("$TESTCASE_FILE", testcase_file_path)
|
||||
locustfile.write(template_content)
|
||||
|
||||
|
||||
@@ -1,24 +1,46 @@
|
||||
#coding: utf-8
|
||||
import logging
|
||||
import random
|
||||
|
||||
import zmq
|
||||
from httprunner.exceptions import MyBaseError, MyBaseFailure
|
||||
from httprunner.loader import load_locust_tests
|
||||
from httprunner.runner import Runner
|
||||
from locust import HttpLocust, TaskSet, task
|
||||
from httprunner import LocustRunner
|
||||
from httprunner.loader import load_tests
|
||||
from locust.events import request_failure
|
||||
|
||||
logging.getLogger().setLevel(logging.CRITICAL)
|
||||
logging.getLogger('locust.main').setLevel(logging.INFO)
|
||||
logging.getLogger('locust.runners').setLevel(logging.INFO)
|
||||
|
||||
|
||||
class WebPageTasks(TaskSet):
|
||||
def on_start(self):
|
||||
self.test_runner = LocustRunner(self.client)
|
||||
self.testcases = loader.load_tests(self.locust.file_path)
|
||||
self.test_runner = Runner(self.locust.config, self.client)
|
||||
self.testcases = load_locust_tests(self.locust.file_path)
|
||||
|
||||
@task
|
||||
def test_specified_scenario(self):
|
||||
self.test_runner.run(self.testcases)
|
||||
@task(weight=1)
|
||||
def test_any(self):
|
||||
teststeps = random.choice(self.locust.tests)
|
||||
for teststep in teststeps:
|
||||
try:
|
||||
self.test_runner.run_test(teststep)
|
||||
except (MyBaseError, MyBaseFailure) as ex:
|
||||
request_failure.fire(
|
||||
request_type=teststep.get("request", {}).get("method"),
|
||||
name=teststep.get("name"),
|
||||
response_time=0,
|
||||
exception=ex
|
||||
)
|
||||
|
||||
|
||||
class WebPageUser(HttpLocust):
|
||||
host = "$HOST"
|
||||
task_set = WebPageTasks
|
||||
min_wait = 1000
|
||||
max_wait = 5000
|
||||
min_wait = 10
|
||||
max_wait = 30
|
||||
|
||||
file_path = "$TESTCASE_FILE"
|
||||
locust_tests = load_locust_tests(file_path)
|
||||
config = locust_tests["config"]
|
||||
tests = locust_tests["tests"]
|
||||
|
||||
host = config.get('request', {}).get('base_url', '')
|
||||
|
||||
34
tests/data/demo_locust.yml
Normal file
34
tests/data/demo_locust.yml
Normal file
@@ -0,0 +1,34 @@
|
||||
- config:
|
||||
name: basic test with httpbin
|
||||
request:
|
||||
base_url: https://httpbin.org/
|
||||
|
||||
- test:
|
||||
name: index
|
||||
weight: 5
|
||||
request:
|
||||
url: /
|
||||
method: GET
|
||||
validate:
|
||||
- eq: ["status_code", 200]
|
||||
- contains: [content, "HTTP Request & Response Service"]
|
||||
|
||||
- test:
|
||||
name: headers
|
||||
weight: 3
|
||||
request:
|
||||
url: /headers
|
||||
method: GET
|
||||
validate:
|
||||
- eq: ["status_code", 200]
|
||||
- eq: [content.headers.Host, "httpbin.org"]
|
||||
|
||||
- test:
|
||||
name: user-agent
|
||||
weight: 2
|
||||
request:
|
||||
url: /user-agent
|
||||
method: GET
|
||||
validate:
|
||||
- eq: ["status_code", 200]
|
||||
- startswith: [content.user-agent, "python-requests"]
|
||||
@@ -2,7 +2,7 @@ import os
|
||||
import shutil
|
||||
import time
|
||||
|
||||
from httprunner import HttpRunner, LocustRunner, api, loader, parser
|
||||
from httprunner import HttpRunner, api, loader, parser
|
||||
from locust import HttpLocust
|
||||
from tests.api_server import HTTPBIN_SERVER
|
||||
from tests.base import ApiServerUnittest
|
||||
@@ -375,15 +375,3 @@ class TestHttpRunner(ApiServerUnittest):
|
||||
os.getcwd(), 'tests/httpbin/basic.yml')
|
||||
runner = HttpRunner().run(testcase_file_path)
|
||||
self.assertTrue(runner.summary["success"])
|
||||
|
||||
|
||||
class TestLocustRunner(ApiServerUnittest):
|
||||
|
||||
def setUp(self):
|
||||
WebPageUser = type('WebPageUser', (HttpLocust,), {})
|
||||
self.locust_client = WebPageUser.client
|
||||
|
||||
def test_LocustRunner(self):
|
||||
testcase_file = os.path.join(os.getcwd(), 'tests', 'httpbin', 'basic.yml')
|
||||
locust_runner = LocustRunner(self.locust_client)
|
||||
locust_runner.run(testcase_file)
|
||||
|
||||
@@ -553,3 +553,12 @@ class TestSuiteLoader(unittest.TestCase):
|
||||
self.assertIn("get_token", project_mapping["def-api"])
|
||||
self.assertIn("setup_and_reset", project_mapping["def-testcase"])
|
||||
self.assertEqual(project_mapping["env"]["PROJECT_KEY"], "ABCDEFGH")
|
||||
|
||||
def test_load_locust_tests(self):
|
||||
path = os.path.join(
|
||||
os.getcwd(), 'tests/data/demo_locust.yml')
|
||||
locust_tests = loader.load_locust_tests(path)
|
||||
self.assertEqual(locust_tests["config"]["refs"]["env"]["UserName"], "debugtalk")
|
||||
self.assertEqual(len(locust_tests["tests"]), 10)
|
||||
self.assertEqual(locust_tests["tests"][0][0]["name"], "index")
|
||||
self.assertEqual(locust_tests["tests"][9][0]["name"], "user-agent")
|
||||
|
||||
Reference in New Issue
Block a user