Improving testing coverage

Now we will write additional tests functions to improve the testing coverage. Specifically, we will write unit tests related to notifications and users.

Open the existing service/tests/test_views.py file and insert the following lines after the last line. The code file for the sample is included in the restful_python_2_04_02 folder, in the Flask01/service/tests/test_views.py file:

def create_notification(client, message, ttl,
notification_category): url = url_for('service.notificationlistresource', _external=True) data = {'message': message, 'ttl': ttl, 'notification_category': notification_category} response = client.post( url, headers=get_authentication_headers(TEST_USER_NAME, TEST_USER_PASSWORD), data=json.dumps(data)) return response def test_create_and_retrieve_notification(client): """ Ensure we can create a new notification and then retrieve it """ create_user_response = create_user(client, TEST_USER_NAME, TEST_USER_PASSWORD) assert create_user_response.status_code == HttpStatus.created_201.value new_notification_message = 'Welcome to the eSports Competition' new_notification_category = 'Information' post_response = create_notification(client, new_notification_message, 15, new_notification_category) assert post_response.status_code ==
HttpStatus.created_201.value assert Notification.query.count() == 1 # The notification should have created a new notification
catagory assert NotificationCategory.query.count() == 1 post_response_data = json.loads(post_response.get_data(as_text=True)) assert post_response_data['message'] == new_notification_message new_notification_url = post_response_data['url'] get_response = client.get( new_notification_url, headers=get_authentication_headers(TEST_USER_NAME, TEST_USER_PASSWORD)) assert get_response.status_code == HttpStatus.ok_200.value get_response_data =
json.loads(get_response.get_data(as_text=True)) assert get_response_data['message'] ==
new_notification_message assert get_response_data['notification_category']['name'] == new_notification_category def test_create_duplicated_notification(client): """ Ensure we cannot create a duplicated Notification """ create_user_response = create_user(client, TEST_USER_NAME, TEST_USER_PASSWORD) assert create_user_response.status_code == HttpStatus.created_201.value new_notification_message = 'Welcome to the 4th eSports Competition' new_notification_category = 'Information' post_response = create_notification(client, new_notification_message, 25, new_notification_category) assert post_response.status_code == HttpStatus.created_201.value assert Notification.query.count() == 1 post_response_data = json.loads(post_response.get_data(as_text=True)) assert post_response_data['message'] == new_notification_message new_notification_url = post_response_data['url'] get_response = client.get( new_notification_url, headers=get_authentication_headers(TEST_USER_NAME, TEST_USER_PASSWORD)) assert get_response.status_code == HttpStatus.ok_200.value get_response_data = json.loads(get_response.get_data(as_text=True)) assert get_response_data['message'] == new_notification_message assert get_response_data['notification_category']['name'] == new_notification_category second_post_response = create_notification(client, new_notification_message, 15, new_notification_category) assert second_post_response.status_code == HttpStatus.bad_request_400.value assert Notification.query.count() == 1

The previous code added many functions to the test_views module. The create_notification function receives the test client, the desired message, ttl, and notification_category (notification category name) for the new notification as arguments. The method builds the URL and the data dictionary, composes and sends an HTTP POST method to create a new notification, and returns the response generated by this request. Many test functions will call the create_notification method to create a notification and then compose and send other HTTP requests to the test client.

The previous code declares the following test functions whose name start with the test_ prefix:

  • test_create_and_retrieve_notification: This function tests whether we can create a new Notification and then retrieve it.
  • test_create_duplicated_notification: This function tests whether the unique constraints make it possible for us to create two notifications with the same message. The second time we compose and send an HTTP POST request with a duplicate notification, we must receive an HTTP 400 Bad Request status code (HttpStatus.bad_request_400.value) and the total number of Notification objects retrieved from the database must be equal to 1.

Open the existing service/tests/test_views.py file and insert the following lines after the last line. The code file for the sample is included in the restful_python_2_04_02 folder, in the Flask01/service/tests/test_views.py file:

def test_retrieve_notifications_list(client): 
    """ 
    Ensure we can retrieve the notifications paginated list 
    """ 
    create_user_response = create_user(client, TEST_USER_NAME, TEST_USER_PASSWORD) 
    assert create_user_response.status_code == HttpStatus.created_201.value 
    new_notification_message_1 = 'The winners will be announced in 1 minute' 
    new_notification_category_1 = 'Information' 
    post_response = create_notification(client, new_notification_message_1, 15, new_notification_category_1) 
    assert post_response.status_code == HttpStatus.created_201.value 
    assert Notification.query.count() == 1 
    new_notification_message_2 = 'There is a problem with one score' 
    new_notification_category_2 = 'Error' 
    post_response = create_notification(client, new_notification_message_2, 10, new_notification_category_2) 
    assert post_response.status_code == HttpStatus.created_201.value 
    assert Notification.query.count() == 2 
    get_first_page_url = url_for('service.notificationlistresource', _external=True) 
    get_first_page_response = client.get( 
        get_first_page_url, 
        headers=get_authentication_headers(TEST_USER_NAME, TEST_USER_PASSWORD)) 
    assert get_first_page_response.status_code == HttpStatus.ok_200.value 
    get_first_page_response_data = json.loads(get_first_page_response.get_data(as_text=True)) 
    assert get_first_page_response_data['count'] == 2 
    assert get_first_page_response_data['previous'] is None 
    assert get_first_page_response_data['next'] is None 
    assert get_first_page_response_data['results'] is not None 
    assert len(get_first_page_response_data['results']) == 2 
    assert get_first_page_response_data['results'][0]['message'] == new_notification_message_1 
    assert get_first_page_response_data['results'][1]['message'] == new_notification_message_2 
    get_second_page_url = url_for('service.notificationlistresource', page=2) 
    get_second_page_response = client.get( 
        get_second_page_url, 
        headers=get_authentication_headers(TEST_USER_NAME, TEST_USER_PASSWORD)) 
    assert get_second_page_response.status_code == HttpStatus.ok_200.value 
    get_second_page_response_data = json.loads(get_second_page_response.get_data(as_text=True)) 
    assert get_second_page_response_data['previous'] is not None 
    assert get_second_page_response_data['previous'] == url_for('service.notificationlistresource', page=1) 
    assert get_second_page_response_data['next'] is None 
    assert get_second_page_response_data['results'] is not None 
    assert len(get_second_page_response_data['results']) == 0 

The previous code declared the test_retrieve_notifications_list test function. This function tests whether we can retrieve the paginated notifications list. First, the function creates two notifications and then it makes sure that the retrieved list includes the two created notifications on the first page. In addition, the method makes sure that the second page doesn't include any message and that the value for the previous page includes the URL for the first page.

Open the existing service/tests/test_views.py file and insert the following lines after the last line. The code file for the sample is included in the restful_python_2_04_02 folder, in the Flask01/service/tests/test_views.py file:

def test_update_notification(client): 
    """ 
    Ensure we can update a single field for an existing notification 
    """ 
    create_user_response = create_user(client, TEST_USER_NAME, TEST_USER_PASSWORD) 
    assert create_user_response.status_code == HttpStatus.created_201.value 
     
    new_notification_message_1 = 'Fortnite has a new winner' 
    new_notification_category_1 = 'Information' 
    post_response = create_notification(client, new_notification_message_1, 30, new_notification_category_1) 
    assert post_response.status_code == HttpStatus.created_201.value 
    assert Notification.query.count() == 1 
    post_response_data = json.loads(post_response.get_data(as_text=True)) 
    new_notification_url = post_response_data['url'] 
    new_displayed_times = 1 
    new_displayed_once = True 
    data = {'displayed_times': new_displayed_times, 'displayed_once': str.lower(str(new_displayed_once))} 
    patch_response = client.patch( 
        new_notification_url,  
        headers=get_authentication_headers(TEST_USER_NAME, TEST_USER_PASSWORD), 
        data=json.dumps(data)) 
    assert patch_response.status_code == HttpStatus.ok_200.value 
    get_response = client.get( 
        new_notification_url, 
        headers=get_authentication_headers(TEST_USER_NAME, TEST_USER_PASSWORD)) 
    assert get_response.status_code == HttpStatus.ok_200.value 
    get_response_data = json.loads(get_response.get_data(as_text=True)) 
    assert get_response_data['displayed_times'] == new_displayed_times 
    assert get_response_data['displayed_once'] == new_displayed_once 
 
 
def test_create_and_retrieve_user(client): 
    """ 
    Ensure we can create a new User and then retrieve it 
    """ 
    new_user_name = TEST_USER_NAME 
    new_user_password = TEST_USER_PASSWORD 
    post_response = create_user(client, new_user_name, new_user_password) 
    assert post_response.status_code == HttpStatus.created_201.value 
    assert User.query.count() == 1 
    post_response_data = json.loads(post_response.get_data(as_text=True)) 
    assert post_response_data['name'] == new_user_name 
    new_user_url = post_response_data['url'] 
    get_response = client.get( 
        new_user_url, 
        headers=get_authentication_headers(new_user_name, new_user_password)) 
    assert get_response.status_code == HttpStatus.ok_200.value 
    get_response_data = json.loads(get_response.get_data(as_text=True)) 
    assert get_response_data['name'] == new_user_name

The previous code added the following two test functions:

  • test_update_notification: This function tests whether we can update many fields for a notification, specifically, the values for the displayed_times and displayed_once fields. The code makes sure that both fields have been updated.
  • test_create_and_retrieve_user: This function tests whether we can create a new User and then retrieve it.

We just coded a few tests related to notifications and one test related to users in order to improve test coverage and notice the impact on the test coverage report.

Now we will use the pytest command to run tests and measure their code coverage. Make sure you run the command in the Terminal or Command Prompt window in which you have activated the virtual environment and that you are located within the service folder. Run the following command:

    pytest --cov -s

The following lines show the sample output:

    =================================== test session starts 
===================================
platform darwin -- Python 3.7.1, pytest-4.0.1, py-1.7.0, pluggy-
0.8.0 - - /Users/gaston/HillarPythonREST2/Flask01/bin/python3
cachedir: .pytest_cache
rootdir: /Users/gaston/HillarPythonREST2/Flask01/service, inifile:
setup.cfg

plugins: cov-2.6.0 collected 10 items tests/test_views.py::test_request_without_authentication PASSED
[ 10%]
tests/test_views.py::test_create_and_retrieve_notification_category
PASSED [ 20%]
tests/test_views.py::test_create_duplicated_notification_category
PASSED [ 30%]
tests/test_views.py::test_retrieve_notification_categories_list
PASSED [ 40%]
tests/test_views.py::test_update_notification_category PASSED
[ 50%]
tests/test_views.py::test_create_and_retrieve_notification PASSED
[ 60%]
tests/test_views.py::test_create_duplicated_notification PASSED
[ 70%]
tests/test_views.py::test_retrieve_notifications_list PASSED
[ 80%]
tests/test_views.py::test_update_notification PASSED
[ 90%]
tests/test_views.py::test_create_and_retrieve_user PASSED
[100%]
---------- coverage: platform darwin, python 3.7.1-final-0 --------
---
Name Stmts Miss Branch BrPart Cover --------------------------------------------- models.py 101 11 24 9 84% views.py 208 68 46 19 65% --------------------------------------------- TOTAL 309 79 70 28 71% ========================= 10 passed, 1 warnings in 39.45 seconds
==========================

The output provided details indicating that the test runner executed 10 tests and all of them passed. The test code coverage measurement report provided by the coverage package increased the Cover percentage of the models.py module from 66% to 84%. In addition, the Cover percentage of the views.py module increased from 43% in the previous run to 65%. The new additional tests we wrote executed additional code in different modules, and therefore, there was a significant impact upon the coverage report. The total coverage increased from 51% to 71%.

We just created a few unit tests to understand how we can code them. However, of course, it would be necessary to write more tests to provide an appropriate coverage of all the features and execution scenarios included in the API.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.125.7