Skip to content

Commit 0b35054

Browse files
author
Benjamin Townsend
committed
Translate several doctest tests to pytest
1 parent d4b7f97 commit 0b35054

File tree

9 files changed

+138
-56
lines changed

9 files changed

+138
-56
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,6 @@ venv/
1010
.vscode/
1111
.python-version
1212
.coverage
13+
.project
14+
.pydevproject
15+
/.pytest_cache/

patterns/behavioral/catalog.py

Lines changed: 34 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
"""
2-
A class that uses different static function depending of a parameter passed in
3-
init. Note the use of a single dictionary instead of multiple conditions
2+
A class that uses a different static function depending on a parameter passed in
3+
init. Note the use of a single dictionary instead of multiple conditions.
44
"""
55

66
__author__ = "Ibrahim Diop <[email protected]>"
77

88

99
class Catalog:
10-
"""catalog of multiple static methods that are executed depending on an init
11-
12-
parameter
10+
"""catalog of multiple static methods that are executed depending on an init parameter
1311
"""
1412

1513
def __init__(self, param: str) -> None:
@@ -29,27 +27,24 @@ def __init__(self, param: str) -> None:
2927
raise ValueError(f"Invalid Value for Param: {param}")
3028

3129
@staticmethod
32-
def _static_method_1() -> None:
33-
print("executed method 1!")
30+
def _static_method_1() -> str:
31+
return "executed method 1!"
3432

3533
@staticmethod
36-
def _static_method_2() -> None:
37-
print("executed method 2!")
34+
def _static_method_2() -> str:
35+
return "executed method 2!"
3836

39-
def main_method(self) -> None:
37+
def main_method(self) -> str:
4038
"""will execute either _static_method_1 or _static_method_2
4139
4240
depending on self.param value
4341
"""
44-
self._static_method_choices[self.param]()
42+
return self._static_method_choices[self.param]()
4543

4644

4745
# Alternative implementation for different levels of methods
4846
class CatalogInstance:
49-
50-
"""catalog of multiple methods that are executed depending on an init
51-
52-
parameter
47+
"""catalog of multiple methods that are executed depending on an init parameter
5348
"""
5449

5550
def __init__(self, param: str) -> None:
@@ -61,31 +56,28 @@ def __init__(self, param: str) -> None:
6156
else:
6257
raise ValueError(f"Invalid Value for Param: {param}")
6358

64-
def _instance_method_1(self) -> None:
65-
print(f"Value {self.x1}")
59+
def _instance_method_1(self) -> str:
60+
return f"Value {self.x1}"
6661

67-
def _instance_method_2(self) -> None:
68-
print(f"Value {self.x2}")
62+
def _instance_method_2(self) -> str:
63+
return f"Value {self.x2}"
6964

7065
_instance_method_choices = {
7166
"param_value_1": _instance_method_1,
7267
"param_value_2": _instance_method_2,
7368
}
7469

75-
def main_method(self) -> None:
70+
def main_method(self) -> str:
7671
"""will execute either _instance_method_1 or _instance_method_2
7772
7873
depending on self.param value
7974
"""
80-
self._instance_method_choices[self.param].__get__(self)() # type: ignore
75+
return self._instance_method_choices[self.param].__get__(self)() # type: ignore
8176
# type ignore reason: https://github.com/python/mypy/issues/10206
8277

8378

8479
class CatalogClass:
85-
86-
"""catalog of multiple class methods that are executed depending on an init
87-
88-
parameter
80+
"""catalog of multiple class methods that are executed depending on an init parameter
8981
"""
9082

9183
x1 = "x1"
@@ -99,32 +91,29 @@ def __init__(self, param: str) -> None:
9991
raise ValueError(f"Invalid Value for Param: {param}")
10092

10193
@classmethod
102-
def _class_method_1(cls) -> None:
103-
print(f"Value {cls.x1}")
94+
def _class_method_1(cls) -> str:
95+
return f"Value {cls.x1}"
10496

10597
@classmethod
106-
def _class_method_2(cls) -> None:
107-
print(f"Value {cls.x2}")
98+
def _class_method_2(cls) -> str:
99+
return f"Value {cls.x2}"
108100

109101
_class_method_choices = {
110102
"param_value_1": _class_method_1,
111103
"param_value_2": _class_method_2,
112104
}
113105

114-
def main_method(self):
106+
def main_method(self) -> str:
115107
"""will execute either _class_method_1 or _class_method_2
116108
117109
depending on self.param value
118110
"""
119-
self._class_method_choices[self.param].__get__(None, self.__class__)() # type: ignore
111+
return self._class_method_choices[self.param].__get__(None, self.__class__)() # type: ignore
120112
# type ignore reason: https://github.com/python/mypy/issues/10206
121113

122114

123115
class CatalogStatic:
124-
125-
"""catalog of multiple static methods that are executed depending on an init
126-
127-
parameter
116+
"""catalog of multiple static methods that are executed depending on an init parameter
128117
"""
129118

130119
def __init__(self, param: str) -> None:
@@ -135,45 +124,45 @@ def __init__(self, param: str) -> None:
135124
raise ValueError(f"Invalid Value for Param: {param}")
136125

137126
@staticmethod
138-
def _static_method_1() -> None:
139-
print("executed method 1!")
127+
def _static_method_1() -> str:
128+
return "executed method 1!"
140129

141130
@staticmethod
142-
def _static_method_2() -> None:
143-
print("executed method 2!")
131+
def _static_method_2() -> str:
132+
return "executed method 2!"
144133

145134
_static_method_choices = {
146135
"param_value_1": _static_method_1,
147136
"param_value_2": _static_method_2,
148137
}
149138

150-
def main_method(self) -> None:
139+
def main_method(self) -> str:
151140
"""will execute either _static_method_1 or _static_method_2
152141
153142
depending on self.param value
154143
"""
155144

156-
self._static_method_choices[self.param].__get__(None, self.__class__)() # type: ignore
145+
return self._static_method_choices[self.param].__get__(None, self.__class__)() # type: ignore
157146
# type ignore reason: https://github.com/python/mypy/issues/10206
158147

159148

160149
def main():
161150
"""
162151
>>> test = Catalog('param_value_2')
163152
>>> test.main_method()
164-
executed method 2!
153+
'executed method 2!'
165154
166155
>>> test = CatalogInstance('param_value_1')
167156
>>> test.main_method()
168-
Value x1
157+
'Value x1'
169158
170159
>>> test = CatalogClass('param_value_2')
171160
>>> test.main_method()
172-
Value x2
161+
'Value x2'
173162
174163
>>> test = CatalogStatic('param_value_1')
175164
>>> test.main_method()
176-
executed method 1!
165+
'executed method 1!'
177166
"""
178167

179168

patterns/behavioral/mediator.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class ChatRoom:
1515
"""Mediator class"""
1616

1717
def display_message(self, user: User, message: str) -> None:
18-
print(f"[{user} says]: {message}")
18+
return f"[{user} says]: {message}"
1919

2020

2121
class User:
@@ -26,7 +26,7 @@ def __init__(self, name: str) -> None:
2626
self.chat_room = ChatRoom()
2727

2828
def say(self, message: str) -> None:
29-
self.chat_room.display_message(self, message)
29+
return self.chat_room.display_message(self, message)
3030

3131
def __str__(self) -> str:
3232
return self.name
@@ -39,11 +39,11 @@ def main():
3939
>>> ethan = User('Ethan')
4040
4141
>>> molly.say("Hi Team! Meeting at 3 PM today.")
42-
[Molly says]: Hi Team! Meeting at 3 PM today.
42+
'[Molly says]: Hi Team! Meeting at 3 PM today.'
4343
>>> mark.say("Roger that!")
44-
[Mark says]: Roger that!
44+
'[Mark says]: Roger that!'
4545
>>> ethan.say("Alright.")
46-
[Ethan says]: Alright.
46+
'[Ethan says]: Alright.'
4747
"""
4848

4949

patterns/behavioral/memento.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def rollback(self):
4242

4343

4444
class Transactional:
45-
"""Adds transactional semantics to methods. Methods decorated with
45+
"""Adds transactional semantics to methods. Methods decorated with
4646
4747
@Transactional will rollback to entry-state upon exceptions.
4848
"""

patterns/behavioral/visitor.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,10 @@ def visit(self, node, *args, **kwargs):
4646
return meth(node, *args, **kwargs)
4747

4848
def generic_visit(self, node, *args, **kwargs):
49-
print("generic_visit " + node.__class__.__name__)
49+
return "generic_visit " + node.__class__.__name__
5050

5151
def visit_B(self, node, *args, **kwargs):
52-
print("visit_B " + node.__class__.__name__)
52+
return "visit_B " + node.__class__.__name__
5353

5454

5555
def main():
@@ -58,13 +58,13 @@ def main():
5858
>>> visitor = Visitor()
5959
6060
>>> visitor.visit(a)
61-
generic_visit A
61+
'generic_visit A'
6262
6363
>>> visitor.visit(b)
64-
visit_B B
64+
'visit_B B'
6565
6666
>>> visitor.visit(c)
67-
visit_B C
67+
'visit_B C'
6868
"""
6969

7070

tests/behavioral/test_catalog.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import pytest
2+
3+
from patterns.behavioral.catalog import Catalog, CatalogClass, CatalogInstance, CatalogStatic
4+
5+
def test_catalog_multiple_methods():
6+
test = Catalog('param_value_2')
7+
token = test.main_method()
8+
assert token == 'executed method 2!'
9+
10+
def test_catalog_multiple_instance_methods():
11+
test = CatalogInstance('param_value_1')
12+
token = test.main_method()
13+
assert token == 'Value x1'
14+
15+
def test_catalog_multiple_class_methods():
16+
test = CatalogClass('param_value_2')
17+
token = test.main_method()
18+
assert token == 'Value x2'
19+
20+
def test_catalog_multiple_static_methods():
21+
test = CatalogStatic('param_value_1')
22+
token = test.main_method()
23+
assert token == 'executed method 1!'

tests/behavioral/test_mediator.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import pytest
2+
3+
from patterns.behavioral.mediator import User
4+
5+
def test_mediated_comments():
6+
molly = User('Molly')
7+
mediated_comment = molly.say("Hi Team! Meeting at 3 PM today.")
8+
assert mediated_comment == "[Molly says]: Hi Team! Meeting at 3 PM today."
9+
10+
mark = User('Mark')
11+
mediated_comment = mark.say("Roger that!")
12+
assert mediated_comment == "[Mark says]: Roger that!"
13+
14+
ethan = User('Ethan')
15+
mediated_comment = ethan.say("Alright.")
16+
assert mediated_comment == "[Ethan says]: Alright."

tests/behavioral/test_memento.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import pytest
2+
3+
from patterns.behavioral.memento import NumObj, Transaction
4+
5+
def test_object_creation():
6+
num_obj = NumObj(-1)
7+
assert repr(num_obj) == '<NumObj: -1>', "Object representation not as expected"
8+
9+
def test_rollback_on_transaction():
10+
num_obj = NumObj(-1)
11+
a_transaction = Transaction(True, num_obj)
12+
for _i in range(3):
13+
num_obj.increment()
14+
a_transaction.commit()
15+
assert num_obj.value == 2
16+
17+
for _i in range(3):
18+
num_obj.increment()
19+
try:
20+
num_obj.value += 'x' # will fail
21+
except TypeError:
22+
a_transaction.rollback()
23+
assert num_obj.value == 2, "Transaction did not rollback as expected"
24+
25+
def test_rollback_with_transactional_annotation():
26+
num_obj = NumObj(2)
27+
with pytest.raises(TypeError):
28+
num_obj.do_stuff()
29+
assert num_obj.value == 2

tests/behavioral/test_visitor.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import pytest
2+
3+
from patterns.behavioral.visitor import A, B, C, Visitor
4+
5+
@pytest.fixture
6+
def visitor():
7+
return Visitor()
8+
9+
def test_visiting_generic_node(visitor):
10+
a = A()
11+
token = visitor.visit(a)
12+
assert token == 'generic_visit A', "The expected generic object was not called"
13+
14+
def test_visiting_specific_nodes(visitor):
15+
b = B()
16+
token = visitor.visit(b)
17+
assert token == 'visit_B B', "The expected specific object was not called"
18+
19+
def test_visiting_inherited_nodes(visitor):
20+
c = C()
21+
token = visitor.visit(c)
22+
assert token == 'visit_B C', "The expected inherited object was not called"

0 commit comments

Comments
 (0)