From 97f4956ea167f9e836349c9651b734c895999548 Mon Sep 17 00:00:00 2001 From: Vlad Lazorik Date: Fri, 21 May 2021 16:08:53 +0300 Subject: [PATCH] Unittesting main.py --- python_module/.gitignore | 3 +- python_module/tests/__init__.py | 0 python_module/tests/conftest.py | 20 ++++ python_module/tests/unit/__init__.py | 0 python_module/tests/unit/test_main.py | 136 ++++++++++++++++++++++ python_module/unittesting/__init__.py | 0 python_module/unittesting/main.py | 158 ++++++++++++++++++++++++++ 7 files changed, 316 insertions(+), 1 deletion(-) create mode 100644 python_module/tests/__init__.py create mode 100644 python_module/tests/conftest.py create mode 100644 python_module/tests/unit/__init__.py create mode 100644 python_module/tests/unit/test_main.py create mode 100644 python_module/unittesting/__init__.py create mode 100644 python_module/unittesting/main.py diff --git a/python_module/.gitignore b/python_module/.gitignore index 630ed9a..3393e5c 100644 --- a/python_module/.gitignore +++ b/python_module/.gitignore @@ -5,4 +5,5 @@ pycache/ logs/ # Files -.env \ No newline at end of file +.env +/.coverage diff --git a/python_module/tests/__init__.py b/python_module/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/python_module/tests/conftest.py b/python_module/tests/conftest.py new file mode 100644 index 0000000..1b994c3 --- /dev/null +++ b/python_module/tests/conftest.py @@ -0,0 +1,20 @@ +import pytest +from unittesting.main import Product, Shop + + +@pytest.fixture +def init_prod(): + return Product('name1', 34.5, 5) + + +@pytest.fixture(name='init_empty_shop') +def init_shop_wout_products(): + return Shop(products=None) + + +@pytest.fixture(name='init_shop') +def init_shop_with_product(): + return Shop(products=[Product('name1', 43.5, 5), Product('name2', 43.5, 5), + Product('name3', 43.5, 5), Product('name4', 43.5, 5), + Product('name5', 43.5, 5), Product('name6', 43.5, 5)]) + diff --git a/python_module/tests/unit/__init__.py b/python_module/tests/unit/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/python_module/tests/unit/test_main.py b/python_module/tests/unit/test_main.py new file mode 100644 index 0000000..987167e --- /dev/null +++ b/python_module/tests/unit/test_main.py @@ -0,0 +1,136 @@ +import pytest + +from unittesting.main import even_odd, sum_all, time_of_day, Product + +import datetime +import unittest +from mock import patch, Mock + + +# Test even_odd +@pytest.mark.parametrize('test_arg, expected', [ + (1, 'odd'), + (10, 'even'), + (-4, 'even'), + (1.0, 'odd')]) +def test_even_odd(test_arg, expected): + + assert even_odd(test_arg) == expected + + +# Test even_odd with input argument None +def test_even_odd_none_arg(): + test_arg = None + + with pytest.raises(TypeError): + even_odd(test_arg) + + +# Test sum_all_type +@pytest.mark.parametrize('test_args, expected', [([1, 2], 3), + ([-3, 5, 2], 4), + ([3], 3)]) +def test_sum_all(test_args, expected): + assert sum_all(*test_args) == expected + + +# Test sum_all_type with Exception +def test_sum_all_type(): + numbers = ('er', 3) + with pytest.raises(TypeError): + sum_all(*numbers) + + +# Test initialisation object +@pytest.mark.parametrize('test_args, expected', + [(('name_1', 34.5, 5), ('name_1', 34.5, 5)), + pytest.param(('name_1', 34.5, 5), ('name_1', 34.5, 5), + marks=pytest.mark.xfail), + pytest.param(('name_1', 34.5, 5), ('name_1', 34.5, 5), + marks=pytest.mark.xfail) + ]) +def test_product_init(test_args, expected): + product = Product(*test_args) + assert isinstance(product.title, str) and product.title == expected[0] + assert isinstance(product.price, float) and product.price == expected[1] + assert isinstance(product.quantity, int) and product.quantity == expected[2] + + +# Test substract_products from class Product +@pytest.mark.parametrize('to_subtract, expected', + [(3, 2), + (2, 3)]) +def test_subtract_products(init_prod, to_subtract, expected): + product = init_prod + product.subtract_quantity(to_subtract) + assert product.quantity == expected + + +# Test add_product from class Product +@pytest.mark.parametrize('add, expected', + [(4, 9), + (3, 8)]) +def test_add_products(init_prod, add, expected): + product = init_prod + product.add_quantity(add) + assert product.quantity == expected + + +# Test change_price from class Product +@pytest.mark.parametrize('new_price', + [15, 12, 2, 5]) +def test_change_price(init_prod, new_price): + prod = init_prod + prod.change_price(new_price) + assert prod.price == new_price + + +# Test add_product from class Shop +@pytest.mark.parametrize('new_prod', [ + ('name', 35.5, 5), + ('name', 75.5, 5)]) +def test_add_product(init_empty_shop, new_prod): + shop = init_empty_shop + prod = Product(*new_prod) + shop.add_product(prod) + assert prod in shop.products + + +# Test get index from class Shop +@pytest.mark.parametrize('test_arg, expected', + [('name3', 2), + ('name5', 4)]) +def test_get_index(init_shop, test_arg, expected): + shop = init_shop + assert shop._get_product_index(test_arg) == expected + + +# Test get index from class Shop for index is none +def test_get_index_none(init_shop): + shop = init_shop + none_name = 'None' + assert shop._get_product_index(none_name) is None + + +# Test sell product from class Shop +@pytest.mark.parametrize('name, quantity, expected', + [('name5', 2, 87), + ('name3', 3, 130.5), + ('name4', 5, 217.5) + ]) +def test_sell_product(init_shop, name, quantity, expected): + shop = init_shop + assert shop.sell_product(name, quantity) == expected + if quantity == 5: + with pytest.raises(TypeError): + assert shop.products[shop._get_product_index(name)] + else: + with pytest.raises(ValueError): + shop.sell_product(name, quantity + 5) + + +# Test sell product from class Shop +def test_sell_prod_none(init_shop): + shop = init_shop + none_name = 'None' + assert shop.sell_product(none_name, 4) is None diff --git a/python_module/unittesting/__init__.py b/python_module/unittesting/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/python_module/unittesting/main.py b/python_module/unittesting/main.py new file mode 100644 index 0000000..c45408f --- /dev/null +++ b/python_module/unittesting/main.py @@ -0,0 +1,158 @@ +from datetime import datetime + + +def even_odd(x): + """Checks number if it even or odd. + + Args: + x (int): number to check. + + Returns: + str: result of check. `even` if given number is even + and `odd` if the number is odd. + """ + if x % 2 == 0: + return "even" + else: + return "odd" + + +def sum_all(*numbers): + """Sums all given numbers together. + + Args: + *args (int or float): variable length argument list. + + + Returns: + int or float: the result of adding all numbers together. + """ + result = 0 + for num in numbers: + result += num + return result + + +def time_of_day(): + """Identifies current time of day. + + Returns: + str: current time of day. Could be: "night", "morning", "afternoon". + """ + now = datetime.now() + if now.hour >= 0 and now.hour < 6: + return "night" + if now.hour >= 6 and now.hour < 12: + return "morning" + if now.hour >= 12 and now.hour < 18: + return "afternoon" + return "night" + + +class Product: + """Data class representation of a product in a shop. + + Args: + title (str): title of the product + price (float): price of one product + quantity (int, optional): the amount of the product available. + Defaults to 1 + """ + + def __init__(self, title, price, quantity=1): + self.title = title + self.quantity = quantity + self.price = price + + def subtract_quantity(self, num_of_products=1): + """Subtracts the number of available products. + + Args: + num_of_products (int, optional): number of products + available to subtract. Defaults to 1. + """ + self.quantity -= num_of_products + + def add_quantity(self, num_of_products=1): + """Adds the number of available products. + + Args: + num_of_products (int, optional): number of products + available to add. Defaults to 1. + """ + self.quantity += num_of_products + + def change_price(self, new_price): + """Changes price of one product. + + Args: + new_price (float): the price to change to. + """ + self.price = new_price + + +class Shop: + """Representation of the shop + + Args: + products (list or Product, optional): products to add to a shop while creating it. + """ + + def __init__(self, products=None): + if products is None: + products = [] + elif isinstance(products, Product): + products = [products] + self.products = products + self.money = .0 + + def add_product(self, product): + """Adds product to the shop. + + Args: + product (Product): product to add to the shop. + """ + self.products.append(product) + + def _get_product_index(self, product_title): + """Looks for products in the shop. + + Args: + product_title (str): title of the product to look for. + + Returns: + int: the index of the product if it present in the shop else None + """ + for index, product in enumerate(self.products): + if product.title == product_title: + return index + return None + + def sell_product(self, product_title, qty_to_sell=1): + """Sells product and returns the final money amount to pay. + + Args: + product_title (str): the title of the product to sell. + qty_to_sell (int, optional): the quantity of the product to sell. + Defaults to 1. + + Raises: + ValueError: in case if amount of available products + of that type is less then given. + + Returns: + float: money amount to pay. + """ + product_index = self._get_product_index(product_title) + receipt = .0 + if product_index is not None: + if self.products[product_index].quantity < qty_to_sell: + raise ValueError('Not enough products') + else: + receipt = self.products[product_index].price * qty_to_sell + if self.products[product_index].quantity == qty_to_sell: + del self.products[product_index] + else: + self.products[product_index].subtract_quantity(qty_to_sell) + self.money += receipt + return receipt