Mock a series of interdependent calls
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
I have a method that scrapes a web page and saves data into a file (see below for an example code). I need to test that the resulting data is well-formed.
The problem is, the data is received from a series of calls, and further calls use the results of previous ones. What is worse, many of the calls involved are done on the same objects (a Webdriver
, a WebDriverWait
and the expected_conditions
module), with different arguments.
I see that unittest.mock.Mock
can mock the result of a simple call, or a series of simple calls, but can't see how to implement something entangled like this. The only way I see is to manually reimplement each and every call the method makes, and copy the arguments I pass in the method into those implementations so that they know what to return for each call. And do that again for every other test case. This sounds like an absolute nightmare to write and maintain: several times more code than the tests themselves and near 1:1 duplication with the code. So I refuse to proceed until someone tells me that there's a better way or proves that there is none and everyone really does it like this (which I don't believe) and e.g. rewrites all the tests each time a label on the page changes (which is an implementation detail, so normally, it shouldn't affect test code at all).
Sample code (adapted for http://example.com):
import selenium.webdriver
from selenium.webdriver.common.by import By as by
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
def dump_accreditation_data(d, w, i, path):
f = codecs.open(os.path.join(path, "%d.txt" % i), "w", encoding="utf-8")
u = u'http://example.com/%s/accreditation' % i
d.get(u)
# page load
w.until(EC.visibility_of_element_located((by.XPATH,"//p"))) #the real code has a more complex expression here with national characters
w.until_not(EC.visibility_of_element_located((by.CSS_SELECTOR, '.waiter')))
print >> f, u
# organization name
e = w.until(EC.visibility_of_element_located((
by.CSS_SELECTOR, 'h1'
)))
org_name = e.text
print >> f, org_name
del e
#etc
e = d.find_element_by_xpath(u'//a[text()="More information..."')
print >> f, e.get_attribute('href')
#How it's supposed to be used:
d = selenium.webdriver.Firefox()
w = WebDriverWait(d, 10)
dump_accreditation_data(d, w, 123, "<output_path>")
python unit-testing selenium python-unittest.mock
add a comment |
I have a method that scrapes a web page and saves data into a file (see below for an example code). I need to test that the resulting data is well-formed.
The problem is, the data is received from a series of calls, and further calls use the results of previous ones. What is worse, many of the calls involved are done on the same objects (a Webdriver
, a WebDriverWait
and the expected_conditions
module), with different arguments.
I see that unittest.mock.Mock
can mock the result of a simple call, or a series of simple calls, but can't see how to implement something entangled like this. The only way I see is to manually reimplement each and every call the method makes, and copy the arguments I pass in the method into those implementations so that they know what to return for each call. And do that again for every other test case. This sounds like an absolute nightmare to write and maintain: several times more code than the tests themselves and near 1:1 duplication with the code. So I refuse to proceed until someone tells me that there's a better way or proves that there is none and everyone really does it like this (which I don't believe) and e.g. rewrites all the tests each time a label on the page changes (which is an implementation detail, so normally, it shouldn't affect test code at all).
Sample code (adapted for http://example.com):
import selenium.webdriver
from selenium.webdriver.common.by import By as by
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
def dump_accreditation_data(d, w, i, path):
f = codecs.open(os.path.join(path, "%d.txt" % i), "w", encoding="utf-8")
u = u'http://example.com/%s/accreditation' % i
d.get(u)
# page load
w.until(EC.visibility_of_element_located((by.XPATH,"//p"))) #the real code has a more complex expression here with national characters
w.until_not(EC.visibility_of_element_located((by.CSS_SELECTOR, '.waiter')))
print >> f, u
# organization name
e = w.until(EC.visibility_of_element_located((
by.CSS_SELECTOR, 'h1'
)))
org_name = e.text
print >> f, org_name
del e
#etc
e = d.find_element_by_xpath(u'//a[text()="More information..."')
print >> f, e.get_attribute('href')
#How it's supposed to be used:
d = selenium.webdriver.Firefox()
w = WebDriverWait(d, 10)
dump_accreditation_data(d, w, 123, "<output_path>")
python unit-testing selenium python-unittest.mock
add a comment |
I have a method that scrapes a web page and saves data into a file (see below for an example code). I need to test that the resulting data is well-formed.
The problem is, the data is received from a series of calls, and further calls use the results of previous ones. What is worse, many of the calls involved are done on the same objects (a Webdriver
, a WebDriverWait
and the expected_conditions
module), with different arguments.
I see that unittest.mock.Mock
can mock the result of a simple call, or a series of simple calls, but can't see how to implement something entangled like this. The only way I see is to manually reimplement each and every call the method makes, and copy the arguments I pass in the method into those implementations so that they know what to return for each call. And do that again for every other test case. This sounds like an absolute nightmare to write and maintain: several times more code than the tests themselves and near 1:1 duplication with the code. So I refuse to proceed until someone tells me that there's a better way or proves that there is none and everyone really does it like this (which I don't believe) and e.g. rewrites all the tests each time a label on the page changes (which is an implementation detail, so normally, it shouldn't affect test code at all).
Sample code (adapted for http://example.com):
import selenium.webdriver
from selenium.webdriver.common.by import By as by
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
def dump_accreditation_data(d, w, i, path):
f = codecs.open(os.path.join(path, "%d.txt" % i), "w", encoding="utf-8")
u = u'http://example.com/%s/accreditation' % i
d.get(u)
# page load
w.until(EC.visibility_of_element_located((by.XPATH,"//p"))) #the real code has a more complex expression here with national characters
w.until_not(EC.visibility_of_element_located((by.CSS_SELECTOR, '.waiter')))
print >> f, u
# organization name
e = w.until(EC.visibility_of_element_located((
by.CSS_SELECTOR, 'h1'
)))
org_name = e.text
print >> f, org_name
del e
#etc
e = d.find_element_by_xpath(u'//a[text()="More information..."')
print >> f, e.get_attribute('href')
#How it's supposed to be used:
d = selenium.webdriver.Firefox()
w = WebDriverWait(d, 10)
dump_accreditation_data(d, w, 123, "<output_path>")
python unit-testing selenium python-unittest.mock
I have a method that scrapes a web page and saves data into a file (see below for an example code). I need to test that the resulting data is well-formed.
The problem is, the data is received from a series of calls, and further calls use the results of previous ones. What is worse, many of the calls involved are done on the same objects (a Webdriver
, a WebDriverWait
and the expected_conditions
module), with different arguments.
I see that unittest.mock.Mock
can mock the result of a simple call, or a series of simple calls, but can't see how to implement something entangled like this. The only way I see is to manually reimplement each and every call the method makes, and copy the arguments I pass in the method into those implementations so that they know what to return for each call. And do that again for every other test case. This sounds like an absolute nightmare to write and maintain: several times more code than the tests themselves and near 1:1 duplication with the code. So I refuse to proceed until someone tells me that there's a better way or proves that there is none and everyone really does it like this (which I don't believe) and e.g. rewrites all the tests each time a label on the page changes (which is an implementation detail, so normally, it shouldn't affect test code at all).
Sample code (adapted for http://example.com):
import selenium.webdriver
from selenium.webdriver.common.by import By as by
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
def dump_accreditation_data(d, w, i, path):
f = codecs.open(os.path.join(path, "%d.txt" % i), "w", encoding="utf-8")
u = u'http://example.com/%s/accreditation' % i
d.get(u)
# page load
w.until(EC.visibility_of_element_located((by.XPATH,"//p"))) #the real code has a more complex expression here with national characters
w.until_not(EC.visibility_of_element_located((by.CSS_SELECTOR, '.waiter')))
print >> f, u
# organization name
e = w.until(EC.visibility_of_element_located((
by.CSS_SELECTOR, 'h1'
)))
org_name = e.text
print >> f, org_name
del e
#etc
e = d.find_element_by_xpath(u'//a[text()="More information..."')
print >> f, e.get_attribute('href')
#How it's supposed to be used:
d = selenium.webdriver.Firefox()
w = WebDriverWait(d, 10)
dump_accreditation_data(d, w, 123, "<output_path>")
python unit-testing selenium python-unittest.mock
python unit-testing selenium python-unittest.mock
edited Jan 3 at 5:49
ivan_pozdeev
asked Jan 3 at 5:42
ivan_pozdeevivan_pozdeev
19.8k85294
19.8k85294
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
For the code as it is, I agree, unit-testing the way you describe does not make much sense. But, that is not just because it would be a lot of work: The goal of testing is, certainly, to find errors in the code. The goal of unit-testing is, to find those errors that can be found in the isolated unit. But, a significant part of your example code is related to interaction with external libraries.
There is comparably little code on the algorithmic level, for example:
os.path.join(path, "%d.txt" % i)
or
u = u'http://example.com/%s/accreditation' % i
or the creation of the output file content.
That is, if there are bugs in the code, they are more likely to be on the interaction level: Calling the right library functions in the right order with the right parameters, parameters having the correct formats etc. - With mocks of the libraries, however, you will not find the interaction bugs, because the mocks are implemented by you and will just reflect your (potentially wrong) understanding of the library behaviour.
My suggestion for testing this code is: Separate the algorithmic code from the code that does the interaction with the libraries. You could, for example, create small helper functions to compute the output file name and the input url. You could, in the interaction dominated part of the code, extract all the data from the web page, and then (in a separate function) create the output file content using all that data.
These helper functions can then all be tested using unit-testing. The rest of the functionality you would test with integration testing.
1
I instead refactored page interaction chunks into service subroutines that return the extracted values (since they are subservient to the big data retrieval logic) and mocked them. Many thanks, you really helped me out in a pinch!
– ivan_pozdeev
Jan 26 at 15:37
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54016901%2fmock-a-series-of-interdependent-calls%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
For the code as it is, I agree, unit-testing the way you describe does not make much sense. But, that is not just because it would be a lot of work: The goal of testing is, certainly, to find errors in the code. The goal of unit-testing is, to find those errors that can be found in the isolated unit. But, a significant part of your example code is related to interaction with external libraries.
There is comparably little code on the algorithmic level, for example:
os.path.join(path, "%d.txt" % i)
or
u = u'http://example.com/%s/accreditation' % i
or the creation of the output file content.
That is, if there are bugs in the code, they are more likely to be on the interaction level: Calling the right library functions in the right order with the right parameters, parameters having the correct formats etc. - With mocks of the libraries, however, you will not find the interaction bugs, because the mocks are implemented by you and will just reflect your (potentially wrong) understanding of the library behaviour.
My suggestion for testing this code is: Separate the algorithmic code from the code that does the interaction with the libraries. You could, for example, create small helper functions to compute the output file name and the input url. You could, in the interaction dominated part of the code, extract all the data from the web page, and then (in a separate function) create the output file content using all that data.
These helper functions can then all be tested using unit-testing. The rest of the functionality you would test with integration testing.
1
I instead refactored page interaction chunks into service subroutines that return the extracted values (since they are subservient to the big data retrieval logic) and mocked them. Many thanks, you really helped me out in a pinch!
– ivan_pozdeev
Jan 26 at 15:37
add a comment |
For the code as it is, I agree, unit-testing the way you describe does not make much sense. But, that is not just because it would be a lot of work: The goal of testing is, certainly, to find errors in the code. The goal of unit-testing is, to find those errors that can be found in the isolated unit. But, a significant part of your example code is related to interaction with external libraries.
There is comparably little code on the algorithmic level, for example:
os.path.join(path, "%d.txt" % i)
or
u = u'http://example.com/%s/accreditation' % i
or the creation of the output file content.
That is, if there are bugs in the code, they are more likely to be on the interaction level: Calling the right library functions in the right order with the right parameters, parameters having the correct formats etc. - With mocks of the libraries, however, you will not find the interaction bugs, because the mocks are implemented by you and will just reflect your (potentially wrong) understanding of the library behaviour.
My suggestion for testing this code is: Separate the algorithmic code from the code that does the interaction with the libraries. You could, for example, create small helper functions to compute the output file name and the input url. You could, in the interaction dominated part of the code, extract all the data from the web page, and then (in a separate function) create the output file content using all that data.
These helper functions can then all be tested using unit-testing. The rest of the functionality you would test with integration testing.
1
I instead refactored page interaction chunks into service subroutines that return the extracted values (since they are subservient to the big data retrieval logic) and mocked them. Many thanks, you really helped me out in a pinch!
– ivan_pozdeev
Jan 26 at 15:37
add a comment |
For the code as it is, I agree, unit-testing the way you describe does not make much sense. But, that is not just because it would be a lot of work: The goal of testing is, certainly, to find errors in the code. The goal of unit-testing is, to find those errors that can be found in the isolated unit. But, a significant part of your example code is related to interaction with external libraries.
There is comparably little code on the algorithmic level, for example:
os.path.join(path, "%d.txt" % i)
or
u = u'http://example.com/%s/accreditation' % i
or the creation of the output file content.
That is, if there are bugs in the code, they are more likely to be on the interaction level: Calling the right library functions in the right order with the right parameters, parameters having the correct formats etc. - With mocks of the libraries, however, you will not find the interaction bugs, because the mocks are implemented by you and will just reflect your (potentially wrong) understanding of the library behaviour.
My suggestion for testing this code is: Separate the algorithmic code from the code that does the interaction with the libraries. You could, for example, create small helper functions to compute the output file name and the input url. You could, in the interaction dominated part of the code, extract all the data from the web page, and then (in a separate function) create the output file content using all that data.
These helper functions can then all be tested using unit-testing. The rest of the functionality you would test with integration testing.
For the code as it is, I agree, unit-testing the way you describe does not make much sense. But, that is not just because it would be a lot of work: The goal of testing is, certainly, to find errors in the code. The goal of unit-testing is, to find those errors that can be found in the isolated unit. But, a significant part of your example code is related to interaction with external libraries.
There is comparably little code on the algorithmic level, for example:
os.path.join(path, "%d.txt" % i)
or
u = u'http://example.com/%s/accreditation' % i
or the creation of the output file content.
That is, if there are bugs in the code, they are more likely to be on the interaction level: Calling the right library functions in the right order with the right parameters, parameters having the correct formats etc. - With mocks of the libraries, however, you will not find the interaction bugs, because the mocks are implemented by you and will just reflect your (potentially wrong) understanding of the library behaviour.
My suggestion for testing this code is: Separate the algorithmic code from the code that does the interaction with the libraries. You could, for example, create small helper functions to compute the output file name and the input url. You could, in the interaction dominated part of the code, extract all the data from the web page, and then (in a separate function) create the output file content using all that data.
These helper functions can then all be tested using unit-testing. The rest of the functionality you would test with integration testing.
answered Jan 23 at 19:48
Dirk HerrmannDirk Herrmann
2,223523
2,223523
1
I instead refactored page interaction chunks into service subroutines that return the extracted values (since they are subservient to the big data retrieval logic) and mocked them. Many thanks, you really helped me out in a pinch!
– ivan_pozdeev
Jan 26 at 15:37
add a comment |
1
I instead refactored page interaction chunks into service subroutines that return the extracted values (since they are subservient to the big data retrieval logic) and mocked them. Many thanks, you really helped me out in a pinch!
– ivan_pozdeev
Jan 26 at 15:37
1
1
I instead refactored page interaction chunks into service subroutines that return the extracted values (since they are subservient to the big data retrieval logic) and mocked them. Many thanks, you really helped me out in a pinch!
– ivan_pozdeev
Jan 26 at 15:37
I instead refactored page interaction chunks into service subroutines that return the extracted values (since they are subservient to the big data retrieval logic) and mocked them. Many thanks, you really helped me out in a pinch!
– ivan_pozdeev
Jan 26 at 15:37
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54016901%2fmock-a-series-of-interdependent-calls%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown