I have a piece of code below where it looks for an attribute known as 'ExtranetContract'within the xml and performs an assertion to check that the attribute does exist and that its value equals 'true'.
def DailyContracts = xml.'soap:Body'
.TestResponse
.TestContractType
.DailyContracts
def ContractType = DailyContracts.findAll { it.#Type == "C"}
def ExtranetContract = ContractType.DailyContract[0].#ExtranetContract
assert ExtranetContract.size() > 0 && ExtranetContract.every { it == 'true' }
Notice the line: def ExtranetContract = ContractType.DailyContract[0].#ExtranetContract. The [0] represents the first instance of DailyContract(where the contact type equals 'C'.
I am not sure if it will work if I have two or more extranet contracts under contract type 'C' (I have't got an example to test myself but I have created a dummy xml to show an example on where the above line of code may not work effectively in checking all extranet contracts attributes
<Contracts>
<DailyContracts Type="S">
<DailyContract Type="TEST" Code="xxx">
<Name>Extranet</Name>
</DailyContract>
</DailyContracts>
<DailyContracts Type="C">
<DailyContract Type="TEST" Code="xxx" ExtranetContract="true">
<Name>Test Hotel 1</Name>
</DailyContract>
<DailyContract Type="TEST" Code="xxx" ExtranetContract="true">
<Name>Test Hotel 2</Name>
</DailyContract>
</DailyContracts>
</Contracts>
My question is simply how can I replace the [0] so that it checks all extranet contracts? I tried replacing [0] with .findAll and 'collect' but no luck.
You do it as below:
//Pass the response as String to parseText method
def xml = new XmlSlurper().parseText(response)
//Get the Daily Contracts of type C
def contracts = xml.'**'.findAll { it.name() == 'DailyContracts' && it.#Type == 'C'}
//Get the ExtranetContract values
def eCon = contracts.DailyContract*.#ExtranetContract
assert eCon instanceof List
assert !(false in eCon)
You can try it quickly online Demo
The following line:
def ExtranetContract = ContractType.DailyContract[0].#ExtranetContract
gives you an instance of FilteredNodeChildren. Since this class is an instance of Iterable you can use spread operator:
import groovy.util.XmlSlurper
def input = '''<Contracts>
<DailyContracts Type="S">
<DailyContract Type="FIT" Code="xxx" Start="2017-08-15" Days="7">
<Name>Extranet</Name>
</DailyContract>
</DailyContracts>
<DailyContracts Type="C">
<DailyContract Type="FIT" Code="xxx" Start="2017-08-15" Days="7" ExtranetContract="true">
<Name>Melia Costa Del Sol Extranet</Name>
</DailyContract>
<DailyContract Type="FIT" Code="xxx" Start="2017-08-15" Days="7" ExtranetContract="true">
<Name>Melia Costa Del Sol Extranet 2</Name>
</DailyContract>
</DailyContracts>
</Contracts>'''
def slurped = new XmlSlurper().parseText(input)
def ContractType = slurped.DailyContracts.findAll { it.#Type == "C"}
def ExtranetContract = ContractType.DailyContract*.#ExtranetContract
assert ExtranetContract.size() == 2 && ExtranetContract.every { it == 'true' }
Related
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."
I have some names and scores as follows
input = {
'Maths': dict(Mohsen=19, Sadegh=18, Hafez=15),
'Physics': dict(Sadegh=16, Hafez=17, Mohsen=17),
'Chemistry': dict(Hafez=13),
'Literature': dict(Sadegh=14),
'Biology': dict(Mohsen=16, Sadegh=10),
}
if a person don't have any lesson its score consider zero also get avrege of scores's person and sort final list by averge and i want to get an output like this.
answer = [
dict(Name='Sadegh', Literature=14, Chemistry=0, Maths=18, Physics=16, Biology=10, Average=11.6),
dict(Name='Mohsen', Maths=19, Physics=17, Chemistry=0, Biology=16, Literature=0, Average=10.4),
dict(Name='Hafez', Chemistry=13, Biology=0, Physics=17, Literature=0, Maths=15, Average=9),
]
how to do it?
Essentially, you have a dictionary, where the information is arranged based on subjects, where for each subject, you have student marks. You want to collection all information related to each student in separate dictionaries.
One of the approaches which can try, is as below:
Try converting the data which you have into student specific data and then you can calculate the Average of the Marks of all subjects for that student. There is a sample code below.
Please do note that, this is just a sample and you should be trying
out a solution by yourself. There are many alternate ways of doing it and you should explore them by yourself.
The below code works with Python 2.7
from __future__ import division
def convert_subject_data_to_student_data(subject_dict):
student_dict = {}
for k, v in subject_dict.items():
for k1, v1 in v.items():
if k1 not in student_dict:
student_dict[k1] = {k:v1}
else:
student_dict[k1][k] = v1
student_list = []
for k,v in student_dict.items():
st_dict = {}
st_dict['Name'] = k
st_dict['Average'] = sum(v.itervalues()) / len(v.keys())
st_dict.update(v)
student_list.append(st_dict)
print student_list
if __name__ == "__main__":
subject_dict = {
'Maths': dict(Mohsen=19, Sadegh=18, Hafez=15),
'Physics': dict(Sadegh=16, Hafez=17, Mohsen=17),
'Chemistry': dict(Hafez=13),
'Literature': dict(Sadegh=14),
'Biology': dict(Mohsen=16, Sadegh=10),
}
convert_subject_data_to_student_data(subject_dict)
sample_input = {
'Maths': dict(Mohsen=19, Sadegh=18, Hafez=15),
'Physics': dict(Sadegh=16, Hafez=17, Mohsen=17),
'Chemistry': dict(Hafez=13),
'Literature': dict(Sadegh=14),
'Biology': dict(Mohsen=16, Sadegh=10),
}
def foo(lessons):
result = {}
for lesson in lessons:
for user in lessons[lesson]:#dictionary
if result.get(user):
#print(result.get(user))
result.get(user).setdefault(lesson, lessons[lesson].get(user,0))
else:
result.setdefault(user, dict(name=user))
result.get(user).setdefault(lesson,lessons[lesson].get(user,0))
#return list(result.values())
return result.values()
#if name == '__main__':
print(foo(sample_input))
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
i want to test the GetWeather webservice
http://www.webservicex.com/globalweather.asmx
I have a text file with this content:
montreal
canada
calgary
canada
My request is:
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:web="http://www.webserviceX.NET">
<soap:Header/>
<soap:Body>
<web:GetWeather>
<!--Optional:-->
<web:CityName>${#Project#City}</web:CityName>
<!--Optional:-->
<web:CountryName>${#Project#Country}</web:CountryName>
</web:GetWeather>
</soap:Body>
</soap:Envelope>
My Groovy code is:
def f = new File("c:\\temp\\Data.txt")
def fr= new FileReader(f)
def br = new BufferedReader(fr)
def s = br.readLine()
def x = br.readLine()
while(s && x !=null)
{
testRunner.testCase.setPropertyValue("City",s)
testRunner.testCase.setPropertyValue("Country",x)
testRunner.runTestStepByName("GetWeather - Request 1")
s = br.readLine()
x = br.readLine()
}
But i's not reading the file.
Any help please, thank you
Groovy simplifies reading lines of text files. In your case since a record consists of two lines, try this:
def f = new File('c:\temp\Data.txt')
def records = f.readLines().collate(2)
records.each {
testRunner.testCase.setPropertyValue("City",it[0])
testRunner.testCase.setPropertyValue("Country",it[1])
testRunner.runTestStepByName("GetWeather - Request 1")
}
How it works
Lets assume the input file contains the following lines:
New York
USA
Istanbul
Turkey
Lines 1 and 2 are cities and lines 2 and 4 are countries. The statement f.readLines() returns a list of the file contents, like this:
[
'New York',
'USA',
'Istanbul',
'Turkey'
]
To make the data easier to work with, I turned it into a list of city and country pairs. That's what collate(2) does:
[
['New York', 'USA'],
['Istanbul', 'Turkey]'
]
With this new list, each(Closure) is used to iterate through the pairs.
records.each {
// it[0] is the city
// it[1] is the country
}
I am new to Groovy and I could not get around this issue. I appreciate any help.
I want to read a file from Groovy. While I am reading the content, for each line I want to substitute the string '${random_id}' and '${entryAuthor}' with different string values.
protected def doPost(String url, URL bodyFile, Map headers = new HashMap() ) {
StringBuffer sb = new StringBuffer()
def randomId = getRandomId()
bodyFile.eachLine { line ->
sb.append( line.replace("\u0024\u007Brandom_id\u007D", randomId)
.replace("\u0024\u007BentryAuthor\u007D", entryAuthor) )
sb.append("\n")
}
return doPost(url, sb.toString())
}
But I got the following error:
groovy.lang.MissingPropertyException:
No such property: random_id for class: tests.SimplePostTest
Possible solutions: randomId
at foo.test.framework.FooTest.doPost_closure1(FooTest.groovy:85)
at groovy.lang.Closure.call(Closure.java:411)
at groovy.lang.Closure.call(Closure.java:427)
at foo.test.framework.FooTest.doPost(FooTest.groovy:83)
at foo.test.framework.FooTest.doPost(FooTest.groovy:80)
at tests.SimplePostTest.Post & check Entry ID(SimplePostTest.groovy:42)
Why would it complain about a property, when I am not doing anything? I also tried "\$\{random_id\}", which works in Java String.replace(), but not in Groovy.
You are doing it the hard way. Just evaluate your file's contents with Groovy's SimpleTemplateEngine.
import groovy.text.SimpleTemplateEngine
def text = 'Dear "$firstname $lastname",\nSo nice to meet you in <% print city %>.\nSee you in ${month},\n${signed}'
def binding = ["firstname":"Sam", "lastname":"Pullara", "city":"San Francisco", "month":"December", "signed":"Groovy-Dev"]
def engine = new SimpleTemplateEngine()
template = engine.createTemplate(text).make(binding)
def result = 'Dear "Sam Pullara",\nSo nice to meet you in San Francisco.\nSee you in December,\nGroovy-Dev'
assert result == template.toString()
you better use groovy.text.SimpleTemplateEngine class; check this for more details http://groovy.codehaus.org/Groovy+Templates
The issue here is that Groovy Strings will evaluate "${x}" by substituting the value of 'x', and we don't want that behaviour in this case. The trick is to use single-quotes which denote plain old Java Strings.
Using a data file like this:
${random_id} 1 ${entryAuthor}
${random_id} 2 ${entryAuthor}
${random_id} 3 ${entryAuthor}
Consider this code, which is analogous to the original:
// spoof HTTP POST body
def bodyFile = new File("body.txt").getText()
StringBuffer sb = new StringBuffer()
def randomId = "257" // TODO: use getRandomId()
def entryAuthor = "Bruce Eckel"
// use ' here because we don't want Groovy Strings, which would try to
// evaluate e.g. ${random_id}
String randomIdToken = '${random_id}'
String entryAuthorToken = '${entryAuthor}'
bodyFile.eachLine { def line ->
sb.append( line.replace(randomIdToken, randomId)
.replace(entryAuthorToken, entryAuthor) )
sb.append("\n")
}
println sb.toString()
The output is:
257 1 Bruce Eckel
257 2 Bruce Eckel
257 3 Bruce Eckel