-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpytest.py
More file actions
155 lines (101 loc) · 4.15 KB
/
pytest.py
File metadata and controls
155 lines (101 loc) · 4.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#pytest supports parameterized and fixture-based testing
my_func = _ # function
# using pytest raises: saying we are expecting a particular kind of error
def test_zero_divide():
with pytest.raises(ZeroDivisionError):
my_func.divide(10, 0) # dividing 10 by 0 should raise ZeroDivisionError but it won't
# we are kind of testing for negative conditions using pytest.raises.
"""Class based tests"""
#use the import file.module as file for pytest
class TestCircle:
#setup method (sets arguments that persists throughout the class)
def setup_method(self, method):
print(f"setting up {method}")
self.circle = shapes.circle(10) # 10 is the argument for radius, this will now persist throught out the class
#teardown method (terminates whatever defined within setup)
def teardown_method(self, method):
del self.circle
"""Pytest Fixtures"""
#function
class shape:
def area(self):
pass
def perimeter(self):
pass
class Rectangle(shape):
def __init__(self, length, width):
self.length = length
self.width = width
def area(self):
return self.length * self.width
def perimeter(self):
return (self.length * 2) * (self.width)
#test for class
"""NB: if we defined class based tests, we won't need to define fixtures, well just put fixtures within setup_method"""
#function based tests
@pytest.fixture
def my_rectangle():
return Rectangle(10, 20) # this arguments will persist throughout the functions that take my_rectangle as argument
def test_area(my_rectangle):
rectangle = Rectangle(10, 20)
assert rectangle.perimeter() == 10 * 20
"""NB: to persist fixtures throughout the test directory, create a conftest.py file and write all your @pytest.fixture function, then add them as function arguments when necessary"""
# we can even pass the parameters as class method arguments.
"""Pytest Marking and parameterizing"""4
import time
@pytest.mark.slow
def test_very_slow():
time.sleep(10)
result = my_functions.divie(10,20)
assert result == 2
#ptest -m slow will only run tests marked slow
@pytest.mark.skip(reason="this feature is currently broken") # marked for skip
def skip_test():
pass
@pytest.mark.xfail(reason="we cannot divide by zero") # marked to fail
def fail_test():
pass
#parameterizing
class square(Rectangle):
def __init__(self, side_length):
super().__init__(side_length, side_length) # inherits the variables within the init method of inherited class
super().area() # inherits the entire method called area. whatever the output of area is, that will be the output.
# trying out multiple values
@pytest.mark.parametrize("side_length, expected_area", [(5, 25), (4, 16)]) # two values
def test_multiple_areas(side_length, expected_area):
assert shape(side_length).area() == expected_area
"""mocking"""
# isolating the system that we are testing. testing functions without actually calling say a database or API
database = {
1: "a",
2: "b"
}
def get_user_from_db(user_id):
return database.get(user_id)
# mocking test
import unittest.mock as mock
@mock.patch("filename.get_user_from_db")
def test_get_user_from_db(get_user_from_db):
mock_get_user_from_db.return_value = "Mocked Alice"
user_name = filename.get_user_from_db(1)
assert user_name = "Mocked Alice" # setup a mock value
# using mock for an acutal api (request)
@mock.pach("request_file.get_func")
def test_get_users(mock_get):
mock_response = mock.Mock()
mock_response.status_code = 200
mock_response.json.return_value = {"id": 1, "name": "john"} # dummy value passed into mock
mock_get.return_value = mock_response # dummy passed into variable also
data = file_name.get_func()
assert data == {"id": 1, "name": "john"}
#mocks are useful when the return value isn't deterministic
#using exception in classes
class Exc(Exception):
pass
class b(Exc):
def (self):
if None:
print("x")
else:
raise Exc
#setup vscode test using comand palette: configure tests python. then select pytest. after that, you can play the tests from the test icon