Python requests as automated test in a Jenkins pipeline - python

I am relatively inexperienced in the field of Python. I am working with Python Requets and BeautifulSoup. The scripts I write with it are all executable.
Since I don't know anything about Pytest and Unittest, I tried to acquire this knowledge, but I just can't get any further.
I've seen in particular that Python Requests works over Mocks, but I have to say, I'm not sure this is the right way to write tests and include them in a Jenkins pipeline. The goal is to test different http requests of a website, either as a unit test or via Pytest.
What is your opinion?
Is that also possible with Python requests (integration) via mocks?
Do I have to use Pytest or Unittesting?
import requests
from requests.exceptions import HTTPError
import pytest
from bs4 import BeautifulSoup
import postpython
page = requests.get('http://google.de')
soup = BeautifulSoup(page.content, 'html.parser')
print(soup)

Taken from here:
You have two types of tests:
Integration - An integration test checks that components in your
application operate with each other i.e. as a whole end-to-end without any mocks.
Unit - A unit test checks a small
component in your application in isolation i.e. mocking all the dependencies for that.
Suppose you have application code that makes a request to an API.
You would use unit test to check whether in your application code a request to the API is called or not (without actually making the API request). You would mock the behavior of sending request and plant a fake response in your unit test. This is so that you can test your code in isolation of the API request/response.
But, if you wanted to actually call the API and get back a real response, then you would use integration tests. This allows you to test the application behavior as a whole.
In python, unittest and pytest are two of many available test runner libraries for writing and managing such tests.
If you wanted to mock the requests/response then check this out: How can I mock requests and the response?
From what I understand, you're looking to actually make the request in your Jenkins CI/CD pipeline to the server and see if you get a successful response. This falls into the category of Integration Testing so you wouldn't need to mock anything.
You can do integration tests with both unittest or pytest.
Here's an example with pytest:
import pytest
def test_get_request():
response = requests.get('http://google.de')
assert response.status_code == 200
To run this you can run this command line task in your jenkins pipeline:
pytest your_test_file.py
You can follow this tutorial for more info and introduction on PyTest here.

Related

Does vcrpy's record_mode=None guarantee no HTTP requests will be sent even if the requests are made in a thread?

I am testing some code with pytest and using the vcrpy decorator as follows:
#pytest.mark.vcr(record_mode='none')
def test_something():
make_requests_in_a_thread_and_save_to_queue()
logged_responses = log_responses_from_queue_in_a_thread()
assert logged_responses == expected_logged_responses
The test fails because the logged_responses are new responses, which are the results of new HTTP requests that have been made during test_something().
I have a cassette saved in the correct place, but this is probably irrelevant because even if I didn't I should be getting a vcrpy CassetteError rather than a failed test.
Does record_mode='none' not apply to code executed within threads?
If not, how should I approach the testing problem? Thank you!
I found out what the problem was. I was using a stream API rather than sending http requests. record_mode='none' refers to http requests.

How to write a unit test code for functions which make API requests to web?

I am writing unit-test code with pytest for my python functions.
Those functions work with requests module that allows us to easily talk to the web servers.
The thing is that the web server to which the functions communicate don't return same value.
For example, the functions communicate to www.toolmarket.com to ask how much Tommy drill is. But sometimes, Tommy drill is not in the list of the web shop. In this case, My test code returns f.
How can I write test code for this kind of function of code?
Edit : added test code
def test_get_data():
assert Info(None, None, None).get_data("Tommy drill") == (
"id" : "KRG552100411"
)
I want to do test like above. Tommy drill is just one of items in the shop. But the thing is sometimes, the item disappears from the list. So test returns f
The above code snippet looks like unit testing. And, since you are using requests module in the actual code, it is better you MOCK the API calls while writing the unit-tests.
It doesn't make an API call from the test function because we use a python mock. With mock, we use #patch and specify python where we are actually making an API call so that it knows what to mock.
It is validating the code if it can process the response. As a reason why, we don't want to make an API call to an external service every time we do unit testing.
To summarise -
When you make the actual API call, you're not doing unit testing, that's more like integration testing
When you want to do unit testing, you're testing if your code can accept and process the expected API call response without actually making the call. You do this by using a mocking library (for example the 'responses' library, which injects mock responses to calls made by requests.
If this helps, I would be happy to help on Python Mocking of API requests too.

How to test RPC of SOAP web services?

I am currently learning building a SOAP web services with django and spyne. I have successfully tested my model using unit test. However, when I tried to test all those #rpc functions, I have no luck there at all.
What I have tried in testing those #rpc functions:
1. Get dummy data in model database
2. Start a server at localhost:8000
3. Create a suds.Client object that can communicate with localhost:8000
4. Try to invoke #rpc functions from the suds.Client object, and test if the output matches what I expected.
However, when I run the test, I believe the test got blocked by the running server at localhost:8000 thus no test code can be run while the server is running.
I tried to make the server run on a different thread, but that messed up my test even more.
I have searched as much as I could online and found no materials that can answer this question.
TL;DR: how do you test #rpc functions using unit test?
I believe if you are using a service inside a test, that test should not be a unit test.
you might want to consider use factory_boy or mock, both of them are python modules to mock or fake a object, for instance, to fake a object to give a response to your rpc call.

Testing Python app which does HTTP requests

For testing I use pytest so it would be great if you suggest something pytest specific.
I have some code which uses the requests library. What it does is basically simple POST/GET requests for logging in, parsing data, etc.
Surely I want to test that code locally without doing any actual HTTP requests.
A monkeypatch funcarg could be the solution, but I think that mocking request.get(...) calls or directly pythons's urllib isn't good, because, for example, there are functions which do more than one HTTP request inside , so I can't just mock the request.get("anyURL") with a simple lambda *args, **kwaargs: """<html>response</html>""".
There are different URLs which should return different content. Sometimes it should be based on POST/GET data. Also I have no idea how will requests.session behave in case of direct mocking. Besides that how to emulate session termination? How to emulate a connection failure?
So in the end in my opinion it's quite hard to use monkey patching here. At least I am not able to write a good mocking function which will take into account everything. Also if I choose to mock urllib directly and someday requests library starts using something different all my tests will fail.
So the best way I think is to use actual HTTP server which turns on on a test run, and if possible takes into account pytest's scopes, etc (so it's a funcarg). While googling I found only two solutions:
https://pypi.python.org/pypi/pytest-localserver
https://github.com/kevin1024/pytest-httpbin
The first one sets up the HTTP server and serves predefined content over a specific URL. Definitely that does not work for me, because as I mentioned some functions which I intend to test do several requests so all inner HTTP requests.get() will get the same answer. Bad.
The second one as far a I see has the same problem. Or at least do not understand how to use it.
The third option could be writing a small Flask based service, but I guess I'll run into a problem that things I use in tests should be tested as well which is a bad practice.
You can rather unmock get after first call.
class Requester():
def get(*args):
...
def mock_get(requester, response):
orig_get = requester.get
def return_text_and_unmock(*args, **kwargs):
self.get = orig_get
return response
requester.get = return_text_and_unmock.__get__(requester, Requester)
return requester
I believe using a local server for unit testing is not a good idea as this is not really a unit test. I you're using requests one good way of being able to mock the requests is to use the module responses that is developed and maintained by dropbox: response dropbox. With responses you will be able to mock each request you make by specifying that you want a certain content to be return when a request is issued to a given URL. The README gives a quick overview of the module's abilities.

functional testing during development

I am not exposed to many of the testing framework, and wonder any recommendation on achieving the following (functional testing) during development phase. Intention is to test a web application functionality (language agnostic?) though the exposed http (REST/JSON RPC) interface.
My backend in NOT written in Python, but because of the easiness of using requests library, and creating Ad hoc http request, I simply construct http POST/GET request with appropriate cookie, payload etc and check the response to validate the server correctness.
It is little tedious to enable specific test cases (comment out / boolean flag ), and verify the results. Any framework to make this more pleasant during the development phase where frequent changes are the norm.
thanks.
Well your on the right track with requests you could tie that directly into nose or unittest or any of the common python testing frameworks that exist, bit of background requests was actually written for testing flask
Use nose to run your tests. In this case, you can declare base classes of your tests to be like this:
class SlowTestBase(BaseTestCase):
slow = True
And run it like nosetests --attr="slow", or to exclude them --attr="!slow". You can find more on nose documentation at https://nose.readthedocs.org/en/latest/

Categories