Python Testing: doctest

First, let’s create a simple function that adds two numbers together:

# Creating a function that adds two numbers together
def add_numbers(x, y): # defining the function with two parameters, x and y
    return x + y # returning the sum of x and y

# Example usage of the function
result = add_numbers(5, 10) # calling the function with arguments 5 and 10 and storing the result in a variable
print(result) # printing the result, which should be 15

To test this function, we can write a test case in Python using the `unittest` module. Heres an example of how to do it:

# Import the unittest module to use for testing
import unittest
# Import the add_numbers function from the my_module module
from my_module import add_numbers

# Create a test class that inherits from the TestCase class in the unittest module
class TestAddNumbers(unittest.TestCase):
    # Create a test method to test the addition functionality of the add_numbers function
    def test_addition(self):
        # Call the add_numbers function with the arguments 2 and 3 and assign the result to the variable result
        result = add_numbers(2, 3)
        # Use the assertEqual method to check if the result is equal to 5
        self.assertEqual(result, 5) # This assertion checks if the result is equal to the expected value of 5

In this example, we first imported the `unittest` module and our function from a separate file called `my_module`. We then created a new test case class called `TestAddNumbers`, which inherits from `TestCase`. Inside this class, we defined a method named `test_addition()` that will be executed when the tests are run.
Inside the `test_addition()` method, we first call our function with some input values (2 and 3) and store the result in a variable called `result`. We then use the `assertEqual()` method to compare this result against what we expect it to be (5). If these two values are not equal, an AssertionError will be raised.
To run our tests, we can call the `main()` function of the `unittest` module:

# Import the `unittest` module
import unittest

# Define a class for our test cases
class TestSum(unittest.TestCase):
    
    # Define a function to test the `sum()` function
    def test_sum(self):
        # Create a list of numbers to pass to the `sum()` function
        numbers = [1, 2, 3]
        # Call the `sum()` function and store the result in a variable called `result`
        result = sum(numbers)
        # Use the `assertEqual()` method to compare the result against the expected value (6)
        self.assertEqual(result, 6)

# Check if the script is being run directly
if __name__ == '__main__':
    # Call the `main()` function of the `unittest` module to run our tests
    unittest.main()

# Output:
# .
# ----------------------------------------------------------------------
# Ran 1 test in 0.000s

# OK

# Explanation:
# - The `unittest` module is imported to allow us to create and run test cases.
# - A class named `TestSum` is defined to contain our test cases.
# - The `test_sum()` function is defined to test the `sum()` function.
# - A list of numbers is created to pass to the `sum()` function.
# - The `sum()` function is called and the result is stored in a variable called `result`.
# - The `assertEqual()` method is used to compare the result against the expected value (6).
# - The `unittest.main()` function is called to run our tests.
# - The `if __name__ == '__main__'` statement checks if the script is being run directly.
# - If it is being run directly, the `main()` function of the `unittest` module is called to run our tests.
# - The output shows that our test passed successfully.

This will execute all the test cases defined in this file and print out a summary of the results at the end. If any tests fail, an error message will be printed to the console.
In addition to `assertEqual()`, there are many other methods provided by the `unittest` module that can help you write more complex tests. For example:
– `assertNotEqual(a, b)`: Asserts that a and b are not equal.

However, sometimes it’s necessary to mock objects in order to test them properly. This is where Python’s built-in unittest.mock module comes into play. In this article, we will explore how to use the `unittest.
First, let’s create a simple function that sends an email using the smtplib library:

# Import the necessary libraries
import smtplib # Importing the smtplib library to send emails
from email.mime.text import MIMEText # Importing the MIMEText class from the email library to create email messages

# Define a function to send emails
def send_email(to_addresses, subject, body):
    message = MIMEText(body) # Creating a MIMEText object with the email body
    message['Subject'] = subject # Setting the email subject
    message['From'] = '[email protected]' # Setting the sender's email address
    for address in to_addresses:
        message['To'] = address # Setting the recipient's email address
    server = smtplib.SMTP('smtp.gmail.com', 587) # Creating an SMTP object to connect to the Gmail server
    server.starttls() # Starting a secure connection with the server
    server.login('[email protected]', 'your-password') # Logging into the server with your Gmail credentials
    server.sendmail('[email protected]', to_addresses, message.as_string()) # Sending the email
    server.quit() # Closing the connection with the server

To test this function, we can write a test case in Python using the `unittest` module and mocking out the smtplib library:

# Import necessary modules
import unittest # Importing the unittest module for testing
from email.mime.text import MIMEText # Importing the MIMEText class from the email module
from unittest.mock import Mock # Importing the Mock class from the unittest.mock module for mocking

# Define a test class
class TestSendEmail(unittest.TestCase):
    # Set up the test by creating a mock server and setting its return value to None
    def setUp(self):
        self.server = Mock() # Creating a mock server
        self.server.sendmail.return_value = None # Setting the return value of the sendmail method to None

    # Define a test method
    def test_send_email(self):
        # Define test data
        to_addresses = ['[email protected]', '[email protected]'] # List of recipient email addresses
        subject = 'Test email' # Subject of the email
        body = 'This is a test email.' # Body of the email

        # Call the send_email function with the test data
        send_email(to_addresses, subject, body)

        # Assert that the sendmail method was called with the correct arguments
        self.server.sendmail.assert_called_with('[email protected]', to_addresses, MIMEText(body)) # Checking if the sendmail method was called with the correct arguments

In this example, we first imported the `unittest`, `email.mime.text`, and `mock` modules. We then created a new test case class called `TestSendEmail`. Inside this class, we defined a method named `test_send_email()` that will be executed when the tests are run.

However, sometimes it’s necessary to mock objects in order to test them properly. This is where Python’s built-in unittest.mock module comes into play. In this article, we will explore how to use the `unittest.
First, let’s create a simple function that sends an email using the smtplib library:

# Import the necessary libraries
import smtplib # Importing the smtplib library to send emails
from email.mime.text import MIMEText # Importing the MIMEText class from the email library to create email messages

# Define a function to send emails
def send_email(to_addresses, subject, body):
    message = MIMEText(body) # Creating a MIMEText object with the body of the email
    message['Subject'] = subject # Setting the subject of the email
    message['From'] = '[email protected]' # Setting the sender's email address
    for address in to_addresses: # Looping through the list of recipient email addresses
        message['To'] = address # Setting the recipient's email address
    server = smtplib.SMTP('smtp.gmail.com', 587) # Creating an SMTP object to connect to the Gmail server
    server.starttls() # Starting a secure connection with the server
    server.login('[email protected]', 'your-password') # Logging into the server with your Gmail credentials
    server.sendmail('[email protected]', to_addresses, message.as_string()) # Sending the email using the sendmail() method
    server.quit() # Closing the connection to the server

# Example usage of the function
to_addresses = ['[email protected]', '[email protected]'] # List of recipient email addresses
subject = 'Test Email' # Subject of the email
body = 'This is a test email sent using Python!' # Body of the email
send_email(to_addresses, subject, body) # Calling the send_email function with the necessary parameters

To test this function, we can write a test case in Python using the `unittest` module and mocking out the smtplib library:

# Import necessary modules
import unittest # Importing the unittest module for testing
from email.mime.text import MIMEText # Importing the MIMEText class from the email module
from unittest.mock import Mock # Importing the Mock class from the unittest.mock module for mocking

# Define a test class
class TestSendEmail(unittest.TestCase):
    # Set up the test by creating a mock server and setting its return value to None
    def setUp(self):
        self.server = Mock() # Creating a mock server
        self.server.sendmail.return_value = None # Setting the return value of the sendmail method to None

    # Define a test method
    def test_send_email(self):
        # Define test data
        to_addresses = ['[email protected]', '[email protected]'] # List of recipient email addresses
        subject = 'Test email' # Subject of the email
        body = 'This is a test email.' # Body of the email

        # Call the send_email function with the test data
        send_email(to_addresses, subject, body)

        # Assert that the sendmail method was called with the correct arguments
        self.server.sendmail.assert_called_with('[email protected]', to_addresses, MIMEText(body)) # Checking if the sendmail method was called with the correct arguments

In this example, we first imported the `unittest`, `email.mime.text`, and `mock` modules. We then created a new test case class called `TestSendEmail`. Inside this class, we defined a method named `test_send_email()` that will be executed when the tests are run.
Inside the `setUp()` method, we first create an instance of our mock object and assign it to the `server` variable. We then set up its behavior by returning None for any calls made to its `sendmail()` method. This allows us to test that our function is calling this method correctly without actually sending emails over the network.
Inside the `test_send_email()` method, we first define some input values (to_addresses, subject, body) and call our function with these inputs. We then use the `assert_called_with()` method provided by the mock object to assert that the expected arguments were passed to its `sendmail()` method when it was called during the execution of our test case.
This allows us to write tests for functions that interact with external resources (like sending emails) without actually having to set up a real email server or send actual emails over the network. This can save time and resources, especially in development environments where setting up these resources can be difficult or expensive.

SICORPS