Pada artikel ini, saya mencoba mengumpulkan beberapa teknik pengujian Python saya. Anda tidak boleh menganggapnya sebagai dogma, karena saya pikir seiring waktu saya akan memperbarui praktik saya.
Sedikit terminologi
The Target adalah apa yang Anda saat ini sedang menguji. Mungkin itu adalah fungsi, metode, atau perilaku yang dihasilkan oleh sekumpulan elemen.
โ , . , ( , ), โ , , .
- . -. . , .
โ , . -, ยซยป .
,
pytest. , . , transport.py test_transport.py.
, .
def refresh(...):
...
def test_refresh():
...
, , , :
def test_refresh_failure():
...
def test_refresh_with_timeout():
...
, , , , . , :
class Thing(object):
...
class TestThing(object):
def test_something(self):
...
test_constructor
, , test_default_state
:
def test_default_state(self):
credentials = self.make_credentials()
# No access token, so these shouldn't be valid.
assert not credentials.valid
# Expiration hasn't been set yet
assert not credentials.expired
# Scopes aren't required for these credentials
assert not credentials.requires_scopes
assert , ,
, . , : ( ) . . . , , . , .
, , , :
test_payload = {'test': 'value'}
encoded = jwt.encode(signer, test_payload)
expected_header = {'typ': 'JWT', 'alg': 'RS256', 'kid': signer.key_id}
expected_call = json.dumps(expected_header) + '.' + json.dumps(test_payload)
signer.sign.assert_called_once_with(expected_call)
, , , :
test_payload = {'test': 'value'}
encoded = jwt.encode(signer, test_payload)
header, payload, _, _ = jwt._unverified_decode(encoded)
assert payload == test_payload
assert header == {'typ': 'JWT', 'alg': 'RS256', 'kid': signer.key_id}
, assert_call
*, , , . , , , , , , . , ( ).
,
, - , , . , , .
, ( ):
signer = mock.create_autospec(crypt.Signer, instance=True)
signer.key_id = 1
test_payload = {'test': 'value'}
encoded = jwt.encode(signer, test_payload)
expected_header = {'typ': 'JWT', 'alg': 'RS256', 'kid': signer.key_id}
expected_call = json.dumps(expected_header) + '.' + json.dumps(test_payload)
signer.sign.assert_called_once_with(expected_call)
- , , :
signer = crypt.RSASigner.from_string(PRIVATE_KEY_BYTES, '1')
test_payload = {'test': 'value'}
encoded = jwt.encode(signer, test_payload)
header, payload, _, _ = jwt._unverified_decode(encoded)
assert payload == test_payload
assert header == {'typ': 'JWT', 'alg': 'RS256', 'kid': signer.key_id}
, , , , .
, Mock- . mock.create_autospec()
(https://docs.python.org/3/library/unittest.mock.html#unittest.mock.create_autospec) mock.patch(autospec=True)
(https://docs.python.org/3/library/unittest.mock.html#autospeccing), . , , , . , , , , , !
, , , :
signer = mock.Mock() encoded = jwt.encode(signer, test_payload) ... signer.sign.assert_called_once_with(expected_call)
, , . , , :
signer = mock.Mock(spec=['sign', 'key_id'])
encoded = jwt.encode(signer, test_payload)
...
signer.sign.assert_called_once_with(expected_call)
โ mock.create_autospec()
mock.patch(..., autospec=True)
. , . , , :
signer = mock.create_autospec(crypt.Signer, instance=True)
encoded = jwt.encode(signer, test_payload)
...
signer.sign.assert_called_once_with(expected_call)
autospec, , , . , .
, , , , , , , (stub). , -, , , (, in-memory ).
, :
class CredentialsStub(google.auth.credentials.Credentials):
def __init__(self, token='token'):
super(CredentialsStub, self).__init__()
self.token = token
def apply(self, headers, token=None):
headers['authorization'] = self.token
def before_request(self, request, method, url, headers):
self.apply(headers)
def refresh(self, request):
self.token += '1'
Memcache:
class MemcacheFake(object):
def __init__(self):
self._data = {}
def set(self, key, value):
self._data[key] = value
def get(self, key):
return self._data.get(key)
, . , pylint, , , .
ยซยป
, , , ยซยป. โ , . Mock , wraps
:
credentials = mock.Mock(wraps=CredentialsStub())
...
assert credentials.refresh.called
//
, . mock_x, x_mock, mocked_x, fake_x ., x. , , , . , :
mock_signer = mock.create_autospec(crypt.Signer, instance=True)
signer:
signer = mock.create_autospec(crypt.Signer, instance=True)
patch , :
@mock.patch('google.auth._helpers.utcnow')
def test_refresh_success(mock_utcnow):
mock_utcnow.return_value = datetime.datetime.min
...
utcnow
:
@mock.patch('google.auth._helpers.utcnow')
def test_refresh_success(utcnow):
utcnow.return_value = datetime.datetime.min
...
patch
, x_patch
:
utcnow_patch = mock.patch('google.auth._helpers.utcnow')
with utcnow_patch as utcnow:
utcnow.return_value = datetime.datetime.min
...
, utcnow_patch
utcnow
. , , , .
, patch
, unused_x
:
@mock.patch('google.auth._helpers.utcnow')
def test_refresh_success(unused_utcnow):
...
helper-
. , helper- . , http-, :
def make_http(data, status=http_client.OK, headers=None):
response = mock.create_autospec(transport.Response, instance=True)
response.status = status
response.data = _helpers.to_bytes(data)
response.headers = headers or {}
http = mock.create_autospec(transport.Request)
http.return_value = response
return request
:
def test_refresh_success():
http = make_http('OK')
assert refresh(http)
def test_refresh_failure():
http = make_http('Not Found', status=http_client.NOT_FOUND)
with pytest.raises(exceptions.TransportError):
refresh(http)
pytest (https://docs.pytest.org/en/latest/fixture.html) โ . , helper- , helper
. , , . , , - :
@pytest.fixture()
def server():
server = WSGIServer(application=TEST_APP)
server.start()
yield server
server.stop()
, . , , :
@pytest.fixture()
def database():
db = database.Client()
yield db
db.delete(db.list_all())
โ , , . , . , , urllib3
transport
:
@pytest.fixture(params=['urllib3', 'requests'])
def http_request(request):
if request.param == 'urllib3':
yield google.auth.transport.urllib3.Request(URLLIB3_HTTP)
elif request.param == 'requests':
yield google.auth.transport.requests.Request(REQUESTS_SESSION)
2021 , Django . , ยซยป Django Docker, , , . .
- "Python Developer. Professional"