Retrieving value using xpath in SoapUI Groovy step - groovy

I need that the output of an operation GET ISM is transferred to the input of another operation SET ESM.
I want to recuperate talon=603090100042390 in this tag (this is response of GET ISM):
<privateUserId>603090100042390#xxxxxxxxxxxxxx</privateUserId>
I use this script:
groovyUtils = new com.eviware.soapui.support.GroovyUtils(context)
holder = groovyUtils.getXmlHolder("GET ISM#Response")
privateUserId = holder.getNodeValue( "//privateUserId" )
assert privateUserId != null
assert privateUserId.length() > 0
latlonNode = groovyUtils.getXmlHolder(privateUserId)
latlon = latlonNode.getNodeValue("//privateUserId")
log.info(latlon)
assert latlon != null
context["latlon"] = latlon
talon is input for SET ESM.
I have this Error :
Assertion failed: assert privateUserId != null | | null false Assertion failed: assert privateUserId != null | | null false error at line: 4
but i don't know why the problem in line 4.
I want to fixed this problem. Thank's

From your question it is not clear if there any namespaces in the response. Possibly that could be one of the reason to get null.
You could use Script Assertion for the first step.
assert context.response, 'Response is empty or null'
def pId = new XmlSlurper().parseText(context.response).'**'.find{it.name() == 'privateUserId'}.text()
log.info "privateUserId value : $pId"
assert pId, "Value of privateUserId is empty or null"
def userId = pId?.substring(0, pId?.indexOf('#'))
context.testCase.setPropertyValue('USERID', userId)
In the next step, wherever extracted user id is needed, use ${#TestCase#USERID}

Related

Pytest passes when run in debug mode but fails otherwise

Following is the pytest code that I execute to test the add connection command.
def test_cli_connection_add(self, cmd, expected_output, expected_conn):
runner = CliRunner()
result = runner.invoke(connections, cmd)
assert result.output.strip() == expected_output
It fails with issue that tells the expected output should have newline.
> assert result.output.strip() == expected_output
E AssertionError: assert ('Successfully added `conn_id`=new4 : '\n 'hive_metastore://airflow:******#host:9083/airflow') == ('Successfully added `conn_id`=new4 : \n'\n 'hive_metastore://airflow:******#host:9083/airflow')
E + Successfully added `conn_id`=new4 : hive_metastore://airflow:******#host:9083/airflow
E - Successfully added `conn_id`=new4 :
E - hive_metastore://airflow:******#host:9083/airflow
tests/cli/commands/test_connection.py:558: AssertionError
To debug this issue further I added set_trace in the code:
def test_cli_connection_add(self, cmd, expected_output, expected_conn):
pytest.set_trace()
runner = CliRunner()
result = runner.invoke(connections, cmd)
assert result.output.strip() == expected_output
When I execute the code via debugger, the assertion pass. Can anyone help me why this works this way?

md5(str.encode(var1)).hexdigest() giving hex value as 382fbe213f159eecf85facb256f265d0 - how to know the var1?

While running the test case, my code is failing as the expected value in hex is different then my answer.
for example, my ws_std value is 13.06 i.e. var1
md5(str.encode(var1)).hexdigest() giving hex value as 382fbe213f159eecf85facb256f265d0
But I am not sure if it matches with the hex value.
Getting error in below code :-
variables = ["ws_std", "p_range", "corr", "dew_month", "max_gust_month", "max_gust_value", "avg_temp", "temp_range", "max_p_range_day", "num_days_std", "median_b_days"]
answers = [ws_std, p_range, corr, dew_month, max_gust_month, max_gust_value, avg_temp, temp_range, max_p_range_day, num_days_std, median_b_days]
answer_dict = dict()
for var, ans in zip(variables, answers):
answer_dict[var] = md5(str.encode(ans)).hexdigest()
with open('test_files/hash.pk', 'rb') as file:
hash_dict = pickle.load(file)
def test_ws_std():
assert hash_dict["ws_std"] == answer_dict["ws_std"]
Error Code:-
========================================================== FAILURES ==========================================================
________________________________________________________ test_ws_std _________________________________________________________
def test_ws_std():
> assert hash_dict["ws_std"] == answer_dict["ws_std"]
E AssertionError: assert 'c8cc550afa85...2c6946c238f36' == '382fbe213f159...facb256f265d0'
E - c8cc550afa85496c4ee2c6946c238f36
E + 382fbe213f159eecf85facb256f265d0
test.py:40: AssertionError
see comments below .
output required : ws_std

How to set mocked exception behavior on Python?

I am using an external library (github3.py) that defines an internal exception (github3.exceptions.UnprocessableEntity). It doesn't matter how this exception is defined, so I want to create a side effect and set the attributes I use from this exception.
Tested code not-so-minimal example:
import github3
class GithubService:
def __init__(self, token: str) -> None:
self.connection = github3.login(token=token)
self.repos = self.connection.repositories()
def create_pull(self, repo_name: str) -> str:
for repo in self.repos:
if repo.full_name == repo_name:
break
try:
created_pr = repo.create_pull(
title="title",
body="body",
head="head",
base="base",
)
except github3.exceptions.UnprocessableEntity as github_exception:
extra = ""
for error in github_exception.errors:
if "message" in error:
extra += f"{error['message']} "
else:
extra += f"Invalid field {error['field']}. " # testing this case
return f"{repo_name}: {github_exception.msg}. {extra}"
I need to set the attributes msg and also errors from the exception. So I tried in my test code using pytest-mock:
#pytest.fixture
def mock_github3_login(mocker: MockerFixture) -> MockerFixture:
"""Fixture for mocking github3.login."""
mock = mocker.patch("github3.login", autospec=True)
mock.return_value.repositories.return_value = [
mocker.Mock(full_name="staticdev/nope"),
mocker.Mock(full_name="staticdev/omg"),
]
return mock
def test_create_pull_invalid_field(
mocker: MockerFixture, mock_github3_login: MockerFixture,
) -> None:
exception_mock = mocker.Mock(errors=[{"field": "head"}], msg="Validation Failed")
mock_github3_login.return_value.repositories.return_value[1].create_pull.side_effect = github3.exceptions.UnprocessableEntity(mocker.Mock())
mock_github3_login.return_value.repositories.return_value[1].create_pull.return_value = exception_mock
response = GithubService("faketoken").create_pull("staticdev/omg")
assert response == "staticdev/omg: Validation Failed. Invalid field head."
The problem with this code is that, if you have side_effect and return_value, Python just ignores the return_value.
The problem here is that I don't want to know the implementation of UnprocessableEntity to call it passing the right arguments to it's constructor. Also, I didn't find other way using just side_effect. I also tried to using return value and setting the class of the mock and using it this way:
def test_create_pull_invalid_field(
mock_github3_login: MockerFixture,
) -> None:
exception_mock = Mock(__class__ = github3.exceptions.UnprocessableEntity, errors=[{"field": "head"}], msg="Validation Failed")
mock_github3_login.return_value.repositories.return_value[1].create_pull.return_value = exception_mock
response = GithubService("faketoken").create_pull("staticdev/omg")
assert response == "staticdev/omg: Validation Failed. Invalid field head."
This also does not work, the exception is not thrown. So I don't know how to overcome this issue given the constraint I don't want to see the implementation of UnprocessableEntity. Any ideas here?
So based on your example, you don't really need to mock github3.exceptions.UnprocessableEntity but only the incoming resp argument.
So the following test should work:
def test_create_pull_invalid_field(
mocker: MockerFixture, mock_github3_login: MockerFixture,
) -> None:
mocked_response = mocker.Mock()
mocked_response.json.return_value = {
"message": "Validation Failed", "errors": [{"field": "head"}]
}
repo = mock_github3_login.return_value.repositories.return_value[1]
repo.create_pull.side_effect = github3.exceptions.UnprocessableEntity(mocked_response)
response = GithubService("faketoken").create_pull("staticdev/omg")
assert response == "staticdev/omg: Validation Failed. Invalid field head."
EDIT:
If you want github3.exceptions.UnprocessableEntity to be completely abstracted, it won't be possible to mock the entire class as catching classes that do not inherit from BaseException is not allowed (See docs). But you can get around it by mocking the constructor only:
def test_create_pull_invalid_field(
mocker: MockerFixture, mock_github3_login: MockerFixture,
) -> None:
def _initiate_mocked_exception(self) -> None:
self.errors = [{"field": "head"}]
self.msg = "Validation Failed"
mocker.patch.object(
github3.exceptions.UnprocessableEntity, "__init__",
_initiate_mocked_exception
)
repo = mock_github3_login.return_value.repositories.return_value[1]
repo.create_pull.side_effect = github3.exceptions.UnprocessableEntity
response = GithubService("faketoken").create_pull("staticdev/omg")
assert response == "staticdev/omg: Validation Failed. Invalid field head."

PyTest: fix repeating code and remove dependencies

I am writing tests for an API with pytest.
The tests are structured like that:
KEEP_BOX_IDS = ["123abc"]
#pytest.fixture(scope="module")
def s():
UID = os.environ.get("MYAPI_UID")
if UID is None:
raise KeyError("UID not set in environment variable")
PWD = os.environ.get("MYAPI_PWD")
if PWD is None:
raise KeyError("PWD not set in environment variable")
return myapi.Session(UID, PWD)
#pytest.mark.parametrize("name,description,count", [
("Normal Box", "Normal Box Description", 1),
("ÄäÖöÜüß!§", "ÄäÖöÜüß!§", 2),
("___--_?'*#", "\n\n1738\n\n", 3),
])
def test_create_boxes(s, name, description, count):
box_info_create = s.create_box(name, description)
assert box_info_create["name"] == name
assert box_info_create["desc"] == description
box_info = s.get_box_info(box_info_create["id"])
assert box_info["name"] == name
assert box_info["desc"] == description
assert len(s.get_box_list()) == count + len(KEEP_BOX_IDS)
def test_update_boxes(s):
bl = s.get_box_list()
for b in bl:
b_id = b['id']
if b_id not in KEEP_BOX_IDS:
new_name = b["name"] + "_updated"
new_desc = b["desc"] + "_updated"
s.update_box(b_id, new_name, new_desc)
box_info = s.get_box_info(b_id)
assert box_info["name"] == new_name
assert get_box_info["desc"] == new_desc
I use a fixture to set up the session (this will keep me connected to the API).
As you can see I am creating 3 boxes at the beginning.
All test that are following do some sort of operations on this 3 boxes. (Boxes are just spaces for folders and files)
For example: update_boxes, create_folders, rename_folders, upload_files, change_file names, etc..
I know it's not good, since all the tests are dependent from each other, but if I execute them in the right order the test is valid and thats enough.
The second issue, which borders me the most, is that all the following tests start with the same lines:
bl = s.get_box_list()
for b in bl:
b_id = b['id']
if b_id not in KEEP_BOX_IDS:
box_info = s.get_box_info(b_id)
I always need to call this for loop to get each boxs id and info.
I've tried to put it in a second fixture, but the problem is that then there will be two fixtures.
Is there a better way of doing this?
Thanks

soapui free version assertions request = response

I will pass any memberid or active card for matching to verify activecard(cardno) matches memberid passed.
Request:
<MemberID>${Property Looper#memberid}</MemberID>
<CardNo>${Property Looper#ActiveCard}</CardNo>
Expected result:
<ReturnMessage>Cardno not found</ReturnMessage>
OR
<ReturnMessage>SUCCESS</ReturnMessage>
How to put assertions to check if the member id in request will check matching with response? contains and not contains assertions seems like not working that well for this condition?
and i want the test to be passed even if the matching failed as the ultimate goal is to make sure the error is not from the data (the test pass regardless the return status) but the application. Thanks
Edit:
after running the step
Edit 2:
after running script assertion
custom property added
You can use Script Assertion to achieve the same.
Based on the description, the assertion should be able to handle both below cases :
some case, you may expect card not found
some case, you may expect SUCCESS
Define test case level custom property, say EXPECTED_MESSAGE and provide appropriate expected value depending on the case.
Add below script assertion for the SOAP Request test step.
//Check if the response is received
assert context.response, 'Response is empty or null'
//Parse the response and find the ReturnMessage value
def actualMessage = new XmlSlurper().parseText(context.response).'**'.find{it.name() == 'ReturnMessage'}?.text()
log.info "Return message from response: $actualMessage"
//Read the expected message from custom property
def expectedMessage = context.expand('${#TestCase#EXPECTED_MESSAGE}')
//Verify with actual value
assert actualMessage == expectedMessage
Let us assume the output is like
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<ReturnMessage>SUCCESS</ReturnMessage>
</soap:Body>
</soap:Envelope>
you can use the below script assertion
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context)
def response = groovyUtils.getXmlHolder("First Step#Response")
String x = response.getNodeValue("//*[local-name()='ReturnMessage']")
if(x.contains("Cardno not found" ) || x.contains("SUCCESS"))
{
log.info "Success"
}
else
{
log.info " Fail"
}
output is
Sat Oct 28 15:22:02 IST 2017:INFO:Success
Rao's approach is also correct. Its just that if you are following that approach you have to have 2 expected result custom properties since you have 2 properties.
You may have to use if condition before assertion as 1 assertion will fail because your results would be either "Cardno not found" or "SUCCESS"
2 Changes you might have to make in the script. replace 'First Step' with the name of your teststep
change the getNodeValue step to reach the actual place

Resources