Added type hints and pytest tests
diff --git a/patterns/behavioral/strategy.py b/patterns/behavioral/strategy.py
index 92d11f25..595df255 100644
--- a/patterns/behavioral/strategy.py
+++ b/patterns/behavioral/strategy.py
@@ -8,41 +8,81 @@
 """
 
 
+from __future__ import annotations
+
+from typing import Callable, Type
+
+
+class DiscountStrategyValidator:  # Descriptor class for check perform
+    @staticmethod
+    def validate(obj: Order, value: Callable) -> bool:
+        try:
+            if obj.price - value(obj) < 0:
+                raise ValueError(
+                    f"Discount cannot be applied due to negative price resulting. {value.__name__}"
+                )
+        except ValueError as ex:
+            print(str(ex))
+            return False
+        else:
+            return True
+
+    def __set_name__(self, owner, name: str) -> None:
+        self.private_name = f"_{name}"
+
+    def __set__(self, obj: Order, value: Callable = None) -> None:
+        if value and self.validate(obj, value):
+            setattr(obj, self.private_name, value)
+        else:
+            setattr(obj, self.private_name, None)
+
+    def __get__(self, obj: object, objtype: Type = None):
+        return getattr(obj, self.private_name)
+
+
 class Order:
-    def __init__(self, price, discount_strategy=None):
-        self.price = price
+    discount_strategy = DiscountStrategyValidator()
+
+    def __init__(self, price: float, discount_strategy: Callable = None) -> None:
+        self.price: float = price
         self.discount_strategy = discount_strategy
 
-    def price_after_discount(self):
+    def apply_discount(self) -> float:
         if self.discount_strategy:
             discount = self.discount_strategy(self)
         else:
             discount = 0
+
         return self.price - discount
 
-    def __repr__(self):
-        fmt = "<Price: {}, price after discount: {}>"
-        return fmt.format(self.price, self.price_after_discount())
+    def __repr__(self) -> str:
+        return f"<Order price: {self.price} with discount strategy: {getattr(self.discount_strategy,'__name__',None)}>"
 
 
-def ten_percent_discount(order):
+def ten_percent_discount(order: Order) -> float:
     return order.price * 0.10
 
 
-def on_sale_discount(order):
+def on_sale_discount(order: Order) -> float:
     return order.price * 0.25 + 20
 
 
 def main():
     """
-    >>> Order(100)
-    <Price: 100, price after discount: 100>
-
-    >>> Order(100, discount_strategy=ten_percent_discount)
-    <Price: 100, price after discount: 90.0>
-
-    >>> Order(1000, discount_strategy=on_sale_discount)
-    <Price: 1000, price after discount: 730.0>
+    >>> order = Order(100, discount_strategy=ten_percent_discount)
+    >>> print(order)
+    <Order price: 100 with discount strategy: ten_percent_discount>
+    >>> print(order.apply_discount())
+    90.0
+    >>> order = Order(100, discount_strategy=on_sale_discount)
+    >>> print(order)
+    <Order price: 100 with discount strategy: on_sale_discount>
+    >>> print(order.apply_discount())
+    55.0
+    >>> order = Order(10, discount_strategy=on_sale_discount)
+    Discount cannot be applied due to negative price resulting. on_sale_discount
+    >>> print(order)
+    <Order price: 10 with discount strategy: None>
     """
 
 
diff --git a/patterns/structural/3-tier.py b/patterns/structural/3-tier.py
index 64835f99..ecc04243 100644
--- a/patterns/structural/3-tier.py
+++ b/patterns/structural/3-tier.py
@@ -7,7 +7,7 @@
 
 
 class Data:
-    """ Data Store Class """
+    """Data Store Class"""
 
     products = {
         "milk": {"price": 1.50, "quantity": 10},
@@ -22,7 +22,7 @@ def __get__(self, obj, klas):
 
 
 class BusinessLogic:
-    """ Business logic holding data store instances """
+    """Business logic holding data store instances"""
 
     data = Data()
 
@@ -36,7 +36,7 @@ def product_information(
 
 
 class Ui:
-    """ UI interaction class """
+    """UI interaction class"""
 
     def __init__(self) -> None:
         self.business_logic = BusinessLogic()
diff --git a/patterns/structural/front_controller.py b/patterns/structural/front_controller.py
index 9377fefe..d93f74d6 100644
--- a/patterns/structural/front_controller.py
+++ b/patterns/structural/front_controller.py
@@ -31,7 +31,7 @@ def dispatch(self, request):
 
 
 class RequestController:
-    """ front controller """
+    """front controller"""
 
     def __init__(self):
         self.dispatcher = Dispatcher()
@@ -44,7 +44,7 @@ def dispatch_request(self, request):
 
 
 class Request:
-    """ request """
+    """request"""
 
     mobile_type = "mobile"
     tablet_type = "tablet"
diff --git a/tests/behavioral/test_strategy.py b/tests/behavioral/test_strategy.py
new file mode 100644
index 00000000..6a3b2504
--- /dev/null
+++ b/tests/behavioral/test_strategy.py
@@ -0,0 +1,52 @@
+import pytest
+
+from patterns.behavioral.strategy import Order, ten_percent_discount, on_sale_discount
+
+
+@pytest.fixture
+def order():
+    return Order(100)
+
+
+@pytest.mark.parametrize(
+    "func, discount",
+    [
+        (ten_percent_discount, 10.0),
+        (on_sale_discount, 45.0)
+    ]
+)
+def test_discount_function_return(func, order, discount):
+    assert func(order) == discount
+
+
+@pytest.mark.parametrize(
+    "func, price",
+    [
+        (ten_percent_discount, 100),
+        (on_sale_discount, 100)
+    ]
+)
+def test_order_discount_strategy_validate_success(func, price):
+    order = Order(price, func)
+
+    assert order.price == price
+    assert order.discount_strategy == func
+
+
+def test_order_discount_strategy_validate_error():
+    order = Order(10, discount_strategy=on_sale_discount)
+
+    assert order.discount_strategy is None
+
+
+@pytest.mark.parametrize(
+    "func, price, discount",
+    [
+        (ten_percent_discount, 100, 90.0),
+        (on_sale_discount, 100, 55.0)
+    ]
+)
+def test_discount_apply_success(func, price, discount):
+    order = Order(price, func)
+
+    assert order.apply_discount() == discount

#373
