|
| 1 | +--- |
| 2 | +title: Testing OpsRamp APIs with PyTest Fixtures |
| 3 | +date: 2023-07-26T06:58:31.750Z |
| 4 | +featuredBlog: false |
| 5 | +author: BalaSubramanian Vetrivel |
| 6 | +authorimage: /img/vetrivel-balasubramanian1-photo.jpg |
| 7 | +disable: false |
| 8 | +--- |
| 9 | +The OpsRamp platform provides a rich set of APIs. |
| 10 | + |
| 11 | + |
| 12 | +By using these APIs, customers can build solutions to automate various IT Operations Management (ITOM) workflows. These could include discovery and monitoring, event and incident management, or remediation and automation. |
| 13 | +Testing these APIs and the resulting automated solution is critical to ensure the reliability and stability of the workflow |
| 14 | + |
| 15 | + |
| 16 | +The PyTest is a powerful Python testing framework and it is widely used to test APIs. Fixtures are one of the most important capabilities of the PyTest framework. In this article, I will discuss some advanced techniques for testing OpsRamp APIs using PyTest fixtures. |
| 17 | + |
| 18 | + |
| 19 | +## What Fixtures are |
| 20 | +PyTest fixtures are a special type of Python function that provisions a fixed baseline for testing. With the help of this baseline, you can ensure tests are run reliably and produce consistent results. In addition, you can ensure that the same tests are repeatable. |
| 21 | + |
| 22 | + |
| 23 | +## Install PyTest |
| 24 | +Run the below command. |
| 25 | + |
| 26 | + |
| 27 | +```shell |
| 28 | +pip install -U pytest |
| 29 | +``` |
| 30 | + |
| 31 | + |
| 32 | +## Verify PyTest installation |
| 33 | +Run the below command. |
| 34 | + |
| 35 | + |
| 36 | +```shell |
| 37 | +pytest --version |
| 38 | +pytest 7.4.0 |
| 39 | +``` |
| 40 | +## Define fixture |
| 41 | +You can define fixtures by decorating a simple Python function with [@pytest.fixture](https://docs.pytest.org/en/6.2.x/reference.html#pytest.fixture) for example |
| 42 | + |
| 43 | + |
| 44 | +Python Decorators are a very powerful and convenient way to alter the behaviour of functions. For more details, refer to [Python Decorators](https://www.geeksforgeeks.org/decorators-in-python). |
| 45 | + |
| 46 | + |
| 47 | +```python |
| 48 | +import pytest |
| 49 | + |
| 50 | + |
| 51 | +@pytest.fixture |
| 52 | +def hello_world(): |
| 53 | + return 'Hello, Happy testing' |
| 54 | +``` |
| 55 | +## Invoke fixtures |
| 56 | +Test functions can invoke fixtures just by declaring the required fixtures as arguments. |
| 57 | + |
| 58 | + |
| 59 | +```python |
| 60 | +def test_hello_world(hello_world): |
| 61 | + assert hello_world == 'Hello, Happy testing' |
| 62 | +``` |
| 63 | +## Invoke OpsRamp API |
| 64 | +As shown below, execute OpsRamp [*Get Access Token* API](https://develop.opsramp.com/v2/api/auth/tenancy-auth-oauth-token). |
| 65 | + |
| 66 | + |
| 67 | +```python |
| 68 | +import http.client |
| 69 | +import json |
| 70 | +import traceback |
| 71 | +import urllib |
| 72 | +from asyncio.log import logger |
| 73 | +import pytest |
| 74 | + |
| 75 | + |
| 76 | +def get_auth_header(api_endpoint, client_id, client_secret, grant_type="client_credentials"): |
| 77 | + """ |
| 78 | + Returns bearer token string in the blow format |
| 79 | + bearer adfa-afdaf-1599-402c-a3ee-1ed24f597cc8 |
| 80 | + """ |
| 81 | + api_connection = http.client.HTTPSConnection(api_endpoint) |
| 82 | + params = {"client_id": client_id, "client_secret": client_secret, "grant_type": "client_credentials"} |
| 83 | + payload = urllib.parse.urlencode(params) |
| 84 | + |
| 85 | + |
| 86 | + headers = { |
| 87 | + 'accept': "application/json", |
| 88 | + 'content-type': "application/x-www-form-urlencoded", |
| 89 | + } |
| 90 | +``` |
| 91 | +## Define fixture to get access token |
| 92 | +You can transform the above function as a PyTest fixture by simply decorating the code as shown below. |
| 93 | + |
| 94 | + |
| 95 | +```python |
| 96 | +@pytest.fixture |
| 97 | +def get_auth_header(api_endpoint, client_id, client_secret, grant_type="client_credentials"): |
| 98 | +``` |
| 99 | + |
| 100 | + |
| 101 | +## Autouse fixtures |
| 102 | +Sometimes some of your fixtures are required for all other tests. The above Get access token is the perfect use case for this. Every API call depends on this API. In this case, you can designate this fixture as an “autouse fixture” by passing in *autouse=True* to the fixture’s decorator. The autouse fixture capability will reduce a lot of redundant requests. |
| 103 | + |
| 104 | + |
| 105 | +```python |
| 106 | +@pytest.fixture(autouse=True) |
| 107 | +def get_auth_header(api_endpoint, client_id, client_secret, grant_type="client_credentials"): |
| 108 | +``` |
| 109 | +## Provisioning of third-party plugin fixtures |
| 110 | +You do not necessarily have to define all fixtures on your code. Fixtures can be provided by third-party plugins as well and you are free to use them. You just need to install the required plugins. You can see an example with the pytest-datadir plugin. |
| 111 | + |
| 112 | + |
| 113 | +Install this plugin as shown below. |
| 114 | + |
| 115 | + |
| 116 | +```shell |
| 117 | +pip install pytest-datadir |
| 118 | +``` |
| 119 | + |
| 120 | + |
| 121 | +```python |
| 122 | +@pytest.fixture(autouse=True) |
| 123 | +def get_bearer_token(shared_datadir,request): |
| 124 | + json_path = (shared_datadir / "auth_header_input.json") |
| 125 | +``` |
| 126 | + |
| 127 | + |
| 128 | + |
| 129 | + |
| 130 | + |
| 131 | +The get\_bearer\_token fixture is using [shared_datadir](https://pypi.org/project/pytest-datadir/) fixture from a third-party plugin. The *Shared_datadir* fixture provisions the data folder as *pathlib.Path* object. |
| 132 | + |
| 133 | + |
| 134 | +## Fixture finalization |
| 135 | +Usually, you do teardown or cleanup activities for each test. There are many good reasons for this, such as: |
| 136 | + |
| 137 | + |
| 138 | +- The executed tests will not impact other tests |
| 139 | +- Do not want to have the testing environment piled up with tons of test data |
| 140 | +- Every test should execute in a clean state |
| 141 | + |
| 142 | + |
| 143 | +Fixtures offer a very powerful teardown/cleanup capability known as finalization. |
| 144 | + |
| 145 | + |
| 146 | +```python |
| 147 | +@pytest.fixture() |
| 148 | +def create_client(shared_datadir, get_bearer_token, request): |
| 149 | + client = Client() |
| 150 | + client.logger.debug("IN***") |
| 151 | + |
| 152 | + |
| 153 | + payload_file = (shared_datadir / "create_client1.json") |
| 154 | + input_payload = client.http_helper.to_json(payload_file) |
| 155 | + |
| 156 | + |
| 157 | + # client_response=client.http_helper.do_post(url, input_payload, get_bearer_token) |
| 158 | + client_response = client.create_client(input_payload, get_bearer_token) |
| 159 | + |
| 160 | + |
| 161 | + def terminate_client(): |
| 162 | + client.logger.debug("IN***") |
| 163 | + util = Utils() |
| 164 | + |
| 165 | + |
| 166 | + clientId = Client.clientId |
| 167 | + |
| 168 | + |
| 169 | + if len(str(clientId)) > 0: |
| 170 | + oauth_token = get_bearer_token |
| 171 | + client.terminate_client(clientId, oauth_token) |
| 172 | + client.logger.debug("OUT***") |
| 173 | + |
| 174 | + |
| 175 | + request.addfinalizer(terminate_client) |
| 176 | + |
| 177 | + |
| 178 | + client.print_log(client_response) |
| 179 | + client.logger.debug("OUT***") |
| 180 | + return client_response |
| 181 | + |
| 182 | + |
| 183 | +``` |
| 184 | + |
| 185 | + |
| 186 | +You should add the finalizer function to the request’s context object of the test as shown below: |
| 187 | + |
| 188 | + |
| 189 | +*request.addfinalizer(terminate_client)* |
| 190 | + |
| 191 | + |
| 192 | +In the above example, you do all the test set-up on the client and execute the test. Once the test is complete, the finalizer function runs and cleans up the whole thing. |
| 193 | + |
| 194 | + |
| 195 | +## Conclusion |
| 196 | +In this article, I have explained what PyTest fixtures are and how to define, invoke and implement fixtures. I also showed you how to leverage the testing of OpsRamp APIs using these fixtures and how to do teardown activities using the finalizer functions. Check back often on the HPE Developer Community blog to find more blog posts on OpsRamp. |
| 197 | + |
| 198 | + |
| 199 | + |
| 200 | + |
| 201 | + |
| 202 | + |
| 203 | + |
| 204 | + |
| 205 | + |
| 206 | + |
| 207 | + |
| 208 | + |
| 209 | + |
| 210 | + |
| 211 | + |
| 212 | + |
| 213 | + |
| 214 | + |
| 215 | + |
| 216 | + |
| 217 | + |
0 commit comments