Applied Programming/Testing/Python3

From Wikiversity
Jump to navigation Jump to search

test_temperature.py[edit | edit source]

"""This file tests the Fahrenheit temperature conversion program using PyTest.

Run "pytest" in this folder to automatically run these tests.

Expected output:
    8 passed in 0.xx seconds

References:
    * https://realpython.com/python-testing/
    * http://docs.pytest.org/en/latest/getting-started.html

"""
import pytest
import temperature


def test_get_fahrenheit_returns_valid_input():
    input_values = ['100']

    def input(prompt=None):
        return input_values.pop(0)

    temperature.input = input
    assert temperature.get_fahrenheit() == 100


def test_get_fahrenheit_ignores_below_absolute_zero():
    input_values = ['-500', '0']

    def input(prompt=None):
        return input_values.pop(0)

    temperature.input = input
    assert temperature.get_fahrenheit() == 0


def test_get_fahrenheit_ignores_string_value():
    input_values = ['error', '0']

    def input(prompt=None):
        return input_values.pop(0)

    temperature.input = input
    assert temperature.get_fahrenheit() == 0


def test_get_fahrenheit_empty_string_returns_none():
    input_values = ['']

    def input(prompt=None):
        return input_values.pop(0)

    temperature.input = input
    assert temperature.get_fahrenheit() == None


def test_fahrenheit_to_celsius_returns_celsius():
    assert temperature.fahrenheit_to_celsius(98.6) == 37
    assert temperature.fahrenheit_to_celsius(32) == 0
    assert temperature.fahrenheit_to_celsius(-40) == -40
    assert round(temperature.fahrenheit_to_celsius(-459.67), 2) == -273.15


def test_fahrenheit_to_celsius_raises_value_error_on_non_numeric_value():
    with pytest.raises(ValueError):
        temperature.fahrenheit_to_celsius(float("X"))


def test_fahrenheit_to_celsius_raises_value_error_below_absolute_zero():
    with pytest.raises(ValueError):
        temperature.fahrenheit_to_celsius(-459.68)


def test_display_results_displays_results(capsys):
    temperature.display_results(32, 0)
    captured = capsys.readouterr()
    assert captured.out == "32.0° Fahrenheit is 0.0° Celsius\n\n"


def test_display_results_raises_assertion_error_fahrenheit():
    with pytest.raises(AssertionError):
        temperature.display_results("X", 0)


def test_display_results_raises_assertion_error_celsius():
    with pytest.raises(AssertionError):
        temperature.display_results(0, "X")

temperature.py[edit | edit source]

"""This program converts a Fahrenheit temperature to Celsius.

Input:
    Fahrenheit temperature

Output:
    Fahrenheit temperature
    Celsius temperature

Example:
    Enter Fahrenheit temperature or press <Enter> to quit:
     100
    100.0° Fahrenheit is 37.8° Celsius

    Enter Fahrenheit temperature or press <Enter> to quit:
    ...

References:
    * http://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html
    * https://wiki.python.org/moin/UsingAssertionsEffectively
    * https://stackoverflow.com/questions/1278705/python-when-i-catch-an-exception-how-do-i-get-the-type-file-and-line-number
    * http://www.mathsisfun.com/temperature-conversion.html

"""

import os
import sys

ABSOLUTE_ZERO = -459.67


def get_fahrenheit():
    """Gets Fahrenheit temperature.

    Args:
        None

    Returns:
        float: Fahrenheit temperature or None if no temperature entered.

    """
    while True:
        fahrenheit = input()
        try:
            print("Enter Fahrenheit temperature or press <Enter> to quit:")
            fahrenheit = float(fahrenheit)
            if fahrenheit < ABSOLUTE_ZERO:
                print("Fahrenheit temperature cannot be below absolute zero.")
                print("ValueError: '%f' is invalid.\n" % fahrenheit)
            else:
                return fahrenheit

        except ValueError:
            if fahrenheit == '':
                return None
            else:
                print("Fahrenheit temperature must be a floating point value.")
                print("ValueError: '%s' is invalid.\n" % fahrenheit)


def fahrenheit_to_celsius(fahrenheit):
    """Converts Fahrenheit temperature to Celsius.

    Args:
        fahrenheit (float): Fahrenheit temperature to be converted

    Returns:
        float: Celsius temperature

    Raises:
        ValueError: If Fahrenheit temperature is not a valid float.
        ValueError: If Fahrenheit temperature is below absolute zero.

    """
    try:
        fahrenheit = float(fahrenheit)
    except ValueError:
        raise ValueError("fahrenheit must be a float. Received '" + str(fahrenheit) + "'")
    except:
        raise

    if fahrenheit < ABSOLUTE_ZERO:
        raise ValueError(
            "fahrenheit must not be below absolute zero. Received %f" % fahrenheit)

    temperature_difference = 32
    temperature_ratio = 5 / 9
    celsius = (fahrenheit - temperature_difference) * temperature_ratio
    return celsius


def display_results(fahrenheit, celsius):
    """Displays Fahrenheit and Celsius temperatures.

    Args:
        fahrenheit (float): Fahrenheit temperature
        celsuis (float): Celsius temperature

    Returns:
        None

    Raises:
        AssertionError: If Fahrenheit temperature is not a valid float.
        AssertionError: If Celsius temperature is not a valid float.

    """
    assert isinstance(fahrenheit, float) or isinstance(fahrenheit, int), \
        "fahrenheit must be a float. Received %s" % type(fahrenheit)
    assert isinstance(celsius, float) or isinstance(celsius, int), \
        "celsius must be a float. Received %s" % type(celsius)
    print("%.1f° Fahrenheit is %.1f° Celsius\n" % (fahrenheit, celsius))


def display_table(fahrenheit):
    """Displays nearest multiples of 10 Fahrenheit and Celsius temperatures.

    Args:
        fahrenheit (float): Fahrenheit temperature

    Returns:
        None

    Raises:
        AssertionError: If Fahrenheit temperature is not a valid float.

    """
    assert isinstance(fahrenheit, float) or isinstance(fahrenheit, int), \
        "fahrenheit must be a float. Received %s" % type(fahrenheit)

    print("F\tC")
    start = int(fahrenheit / 10) * 10
    for fahrenheit in range(start, start + 11):
        print("%.1f" % fahrenheit, end="\t")
        print("%.1f" % fahrenheit_to_celsius(fahrenheit))
    print()


def main():  # pragma: no cover
    """Runs the main program logic."""

    while True:
        try:
            fahrenheit = get_fahrenheit()
            if fahrenheit == None:
                break
            celsius = fahrenheit_to_celsius(fahrenheit)
            display_results(fahrenheit, celsius)
            display_table(fahrenheit)
        except:
            print("Unexpected error.")
            print("Error:", sys.exc_info()[1])
            print("File: ", sys.exc_info()[2].tb_frame.f_code.co_filename)
            print("Line: ", sys.exc_info()[2].tb_lineno)


if __name__ == "__main__":  # pragma: no cover
    main()

Try It[edit | edit source]

Copy and paste the code above into one of the following free online development environments or use your own Python3 compiler / interpreter / IDE.

See Also[edit | edit source]