Improving testing coverage

Now, we will write additional unit tests to improve the testing coverage. Specifically, we will write unit tests related to messages and users. Open the existing api/tests/test_views.py file and insert the following lines after the last line, within the InitialTests class. We need a new import statement and we will declare the new PlayerTests class. The code file for the sample is included in the restful_python_chapter_08_02 folder:

    def create_message(self, message, duration, category): 
        url = url_for('api.messagelistresource', _external=True) 
        data = {'message': message, 'duration': duration, 'category': category} 
        response = self.test_client.post( 
            url,  
            headers=self.get_authentication_headers(self.test_user_name,
            self.test_user_password), 
            data=json.dumps(data)) 
        return response 
 
    def test_create_and_retrieve_message(self): 
        """ 
        Ensure we can create a new message and then retrieve it 
        """ 
        create_user_response = self.create_user(self.test_user_name,
        self.test_user_password) 
        self.assertEqual(create_user_response.status_code,
        status.HTTP_201_CREATED) 
        new_message_message = 'Welcome to the IoT world' 
        new_message_category = 'Information' 
        post_response = self.create_message(new_message_message, 15,
        new_message_category) 
        self.assertEqual(post_response.status_code, status.HTTP_201_CREATED) 
        self.assertEqual(Message.query.count(), 1) 
        # The message should have created a new catagory 
        self.assertEqual(Category.query.count(), 1) 
        post_response_data = json.loads(post_response.get_data(as_text=True)) 
        self.assertEqual(post_response_data['message'], new_message_message) 
        new_message_url = post_response_data['url'] 
        get_response = self.test_client.get( 
            new_message_url, 
            headers=self.get_authentication_headers(self.test_user_name,
            self.test_user_password)) 
        get_response_data = json.loads(get_response.get_data(as_text=True)) 
        self.assertEqual(get_response.status_code, status.HTTP_200_OK) 
        self.assertEqual(get_response_data['message'], new_message_message) 
        self.assertEqual(get_response_data['category']['name'],
        new_message_category) 
 
    def test_create_duplicated_message(self): 
        """ 
        Ensure we cannot create a duplicated Message 
        """ 
        create_user_response = self.create_user(self.test_user_name,
        self.test_user_password) 
        self.assertEqual(create_user_response.status_code,
        status.HTTP_201_CREATED) 
        new_message_message = 'Welcome to the IoT world' 
        new_message_category = 'Information' 
        post_response = self.create_message(new_message_message, 15,
        new_message_category) 
        self.assertEqual(post_response.status_code, status.HTTP_201_CREATED) 
        self.assertEqual(Message.query.count(), 1) 
        post_response_data = json.loads(post_response.get_data(as_text=True)) 
        self.assertEqual(post_response_data['message'], new_message_message) 
        new_message_url = post_response_data['url'] 
        get_response = self.test_client.get( 
            new_message_url, 
            headers=self.get_authentication_headers(self.test_user_name,
            self.test_user_password)) 
        get_response_data = json.loads(get_response.get_data(as_text=True)) 
        self.assertEqual(get_response.status_code, status.HTTP_200_OK) 
        self.assertEqual(get_response_data['message'], new_message_message) 
        self.assertEqual(get_response_data['category']['name'],
        new_message_category) 
        second_post_response = self.create_message(new_message_message, 15,
        new_message_category) 
        self.assertEqual(second_post_response.status_code,
        status.HTTP_400_BAD_REQUEST) 
        self.assertEqual(Message.query.count(), 1) 

The preceding code adds many methods to the InitialTests class. The create_message method receives the desired message, duration, and category (category name) for the new message as arguments. The method builds the URL and the data dictionary to compose and send an HTTP POST method, create a new message, and return the response generated by this request. Many test methods will call the create_message method to create a message and then compose and send other HTTP requests to the API.

The class declares the following methods whose names start with the test_ prefix:

  • test_create_and_retrieve_message: Tests whether we can create a new Message and then retrieve it.
  • test_create_duplicated_message: Tests whether the unique constraints don't make it possible for us to create two messages with the same message. The second time we compose and send an HTTP POST request with a duplicate message, we must receive an HTTP 400 Bad Request status code (status.HTTP_400_BAD_REQUEST) and the total number of Message objects retrieved from the database must be 1.

Open the existing api/tests/test_views.py file and insert the following lines after the last line, within the InitialTests class. The code file for the sample is included in the restful_python_chapter_08_02 folder:

    def test_retrieve_messages_list(self): 
        """ 
        Ensure we can retrieve the messages paginated list 
        """ 
        create_user_response = self.create_user(self.test_user_name,
        self.test_user_password) 
        self.assertEqual(create_user_response.status_code,
        status.HTTP_201_CREATED) 
        new_message_message_1 = 'Welcome to the IoT world' 
        new_message_category_1 = 'Information' 
        post_response = self.create_message(new_message_message_1, 15,
        new_message_category_1) 
        self.assertEqual(post_response.status_code, status.HTTP_201_CREATED) 
        self.assertEqual(Message.query.count(), 1) 
        new_message_message_2 = 'Initialization of the board failed' 
        new_message_category_2 = 'Error' 
        post_response = self.create_message(new_message_message_2, 10,
        new_message_category_2) 
        self.assertEqual(post_response.status_code, status.HTTP_201_CREATED) 
        self.assertEqual(Message.query.count(), 2) 
        get_first_page_url = url_for('api.messagelistresource', _external=True) 
        get_first_page_response = self.test_client.get( 
            get_first_page_url, 
            headers=self.get_authentication_headers(self.test_user_name,
            self.test_user_password)) 
        get_first_page_response_data =
        json.loads(get_first_page_response.get_data(as_text=True)) 
        self.assertEqual(get_first_page_response.status_code, status.HTTP_200_OK) 
        self.assertEqual(get_first_page_response_data['count'], 2) 
        self.assertIsNone(get_first_page_response_data['previous']) 
        self.assertIsNone(get_first_page_response_data['next']) 
        self.assertIsNotNone(get_first_page_response_data['results']) 
        self.assertEqual(len(get_first_page_response_data['results']), 2) 
        self.assertEqual(get_first_page_response_data['results'][0]['message'],
        new_message_message_1) 
        self.assertEqual(get_first_page_response_data['results'][1]['message'],
        new_message_message_2) 
        get_second_page_url = url_for('api.messagelistresource', page=2) 
        get_second_page_response = self.test_client.get( 
            get_second_page_url, 
            headers=self.get_authentication_headers(self.test_user_name,
            self.test_user_password)) 
        get_second_page_response_data =
        json.loads(get_second_page_response.get_data(as_text=True)) 
        self.assertEqual(get_second_page_response.status_code,
        status.HTTP_200_OK) 
        self.assertIsNotNone(get_second_page_response_data['previous']) 
        self.assertEqual(get_second_page_response_data['previous'],
        url_for('api.messagelistresource', page=1)) 
        self.assertIsNone(get_second_page_response_data['next']) 
        self.assertIsNotNone(get_second_page_response_data['results']) 
        self.assertEqual(len(get_second_page_response_data['results']), 0) 
     

The previous code added a test_retrieve_messages_list method to the InitialTests class. This method tests whether we can retrieve the paginated messages list. First, the method creates two messages and then it makes sure that the retrieved list includes the two created messages in 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 api/tests/test_views.py file and insert the following lines after the last line, within the InitialTests class. The code file for the sample is included in the restful_python_chapter_08_02 folder:

    def test_update_message(self): 
        """ 
        Ensure we can update a single field for an existing message 
        """ 
        create_user_response = self.create_user(self.test_user_name,
        self.test_user_password) 
        self.assertEqual(create_user_response.status_code,
        status.HTTP_201_CREATED) 
        new_message_message_1 = 'Welcome to the IoT world' 
        new_message_category_1 = 'Information' 
        post_response = self.create_message(new_message_message_1, 30,
        new_message_category_1) 
        self.assertEqual(post_response.status_code, status.HTTP_201_CREATED) 
        self.assertEqual(Message.query.count(), 1) 
        post_response_data = json.loads(post_response.get_data(as_text=True)) 
        new_message_url = post_response_data['url'] 
        new_printed_times = 1 
        new_printed_once = True 
        data = {'printed_times': new_printed_times, 'printed_once':
        new_printed_once} 
        patch_response = self.test_client.patch( 
            new_message_url,  
            headers=self.get_authentication_headers(self.test_user_name,
            self.test_user_password), 
            data=json.dumps(data)) 
        self.assertEqual(patch_response.status_code, status.HTTP_200_OK) 
        get_response = self.test_client.get( 
            new_message_url, 
            headers=self.get_authentication_headers(self.test_user_name,
            self.test_user_password)) 
        get_response_data = json.loads(get_response.get_data(as_text=True)) 
        self.assertEqual(get_response.status_code, status.HTTP_200_OK) 
        self.assertEqual(get_response_data['printed_times'], new_printed_times) 
        self.assertEqual(get_response_data['printed_once'], new_printed_once) 
     
    def test_create_and_retrieve_user(self): 
        """ 
        Ensure we can create a new User and then retrieve it 
        """ 
        new_user_name = self.test_user_name 
        new_user_password = self.test_user_password 
        post_response = self.create_user(new_user_name, new_user_password) 
        self.assertEqual(post_response.status_code, status.HTTP_201_CREATED) 
        self.assertEqual(User.query.count(), 1) 
        post_response_data = json.loads(post_response.get_data(as_text=True)) 
        self.assertEqual(post_response_data['name'], new_user_name) 
        new_user_url = post_response_data['url'] 
        get_response = self.test_client.get( 
            new_user_url, 
            headers=self.get_authentication_headers(self.test_user_name,
            self.test_user_password)) 
        get_response_data = json.loads(get_response.get_data(as_text=True)) 
        self.assertEqual(get_response.status_code, status.HTTP_200_OK) 
        self.assertEqual(get_response_data['name'], new_user_name) 
  • The previous code added the following two methods to the InitialTests class-test_update_message-tests whether we can update more than one fields for a message, specifically, the values for the printed_times and printed_once fields. The code makes sure that both fields have been updated.
  • test_create_and_retrieve_user: Tests whether we can create a new User and then retrieve it.

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

Now, run the following command within the same virtual environment we have been using:

nose2 -v --with-coverage

The following lines show the sample output:

test_create_and_retrieve_category (test_views.InitialTests) ... ok
test_create_and_retrieve_message (test_views.InitialTests) ... ok
test_create_and_retrieve_user (test_views.InitialTests) ... ok
test_create_duplicated_category (test_views.InitialTests) ... ok
test_create_duplicated_message (test_views.InitialTests) ... ok
test_request_without_authentication (test_views.InitialTests) ... ok
test_retrieve_categories_list (test_views.InitialTests) ... ok
test_retrieve_messages_list (test_views.InitialTests) ... ok
test_update_category (test_views.InitialTests) ... ok
test_update_message (test_views.InitialTests) ... ok
------------------------------------------------------------------
Ran 10 tests in 25.938s
OK
----------- coverage: platform win32, python 3.5.2-final-0 -------
Name                  Stmts   Miss  Cover
-----------------------------------------
app.py                    9      0   100%
config.py                11     11     0%
helpers.py               23      1    96%
migrate.py                9      9     0%
models.py               101     11    89%
run.py                    4      4     0%
status.py                56      5    91%
test_config.py           16      0   100%
tests	est_views.py     203      0   100%
views.py                204     66    68%
-----------------------------------------
TOTAL                   636    107    83% 

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 views.py module from 47% in the previous run to 68%. In addition, the percentage of the helpers.py module increased from 22% to 96% because we wrote tests that used pagination. The new additional tests we wrote executed additional code in different modules, and therefore, there is an impact in the coverage report.

Tip

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 featured 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.223.237.29