Last active
October 25, 2021 11:26
-
-
Save a-recknagel/00ab259d1ee46326d27122b02f52cf20 to your computer and use it in GitHub Desktop.
bad test - good test
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# adding widgets to my app | |
import my_app | |
def foo(user_id: int, num_widgets: int): | |
user = my_app.get_user(user_id) | |
widgets = [] | |
for _ in range(num_widgets): | |
widgets.append(my_app.create_widget(user)) | |
my_app.bootstrap(widgets) | |
return my_app.ensure_status() == 0 | |
# testing that "it works correctly" | |
import pytest | |
@pytest.mark.parametrize( | |
"state, expected", | |
[ | |
pytest.param(0, True, id="success"), | |
pytest.param(1, False, id="failure") | |
] | |
) | |
def test_foo(mocker, state, expected): | |
# arrange, if this block is big -> danger zone: | |
user_id, num_widgets = 1, 5 | |
get_user = mocker.patch("my_app.get_user") | |
create_widget = mocker.patch("my_app.create_widget") | |
bootstrap = mocker.patch("my_app.bootstrap") | |
mocker.patch("my_app.ensure_status", return_value=state) | |
# act: | |
result = foo(user_id, num_widgets) | |
# assert, pretty much runs down the implementation line by line. ugly and high-maintenance: | |
get_user.assert_called_with(user_id) # trash | |
create_widget.assert_called_with(get_user.return_value) # trash | |
bootstrap.called_once() # trash | |
assert len(load_env.return_value) == num_widgets # maybe reasonable | |
assert result == expected # reasonable |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def levenshtein(s1: str, s2: str) -> int: | |
"""Compute Levenshtein's edit distance between two strings. | |
The edit distance is defined as the number of change-operations | |
necessary to transform one string into another. Valid | |
operations are 1) adding a character, 2) deleting a character, | |
and 3) replacing a character. An edit distance of 0 means that | |
the input strings are equal, an edit distance of the length of | |
the longer strings means that they are as different as | |
possible. | |
For additional details, see | |
https://en.wikipedia.org/wiki/Levenshtein_distance | |
Raises: | |
ValueError if one of the inputs is not a string. | |
""" | |
if not isinstance(s1, str) or not isinstance(s1, str): | |
raise ValueError("Right types, please.") | |
if len(s1) < len(s2): | |
return levenshtein(s2, s1) | |
if len(s2) == 0: | |
return len(s1) | |
previous_row: List[int] = [*range(len(s2) + 1)] | |
for i, c1 in enumerate(s1): | |
current_row = [i + 1] | |
for j, c2 in enumerate(s2): | |
insertions = previous_row[j + 1] + 1 | |
deletions = current_row[j] + 1 | |
substitutions = previous_row[j] + (c1 != c2) | |
current_row.append(min(insertions, deletions, substitutions)) | |
previous_row = current_row | |
return previous_row[-1] | |
# I could write these tests simply by reading the function-under-test's docstring, | |
# no need to take a look at the implementation. | |
import pytest | |
@pytest.mark.parametrize( | |
"s_1, s_2, distance", | |
[ | |
("", "", 0), | |
("foo", "", 3), | |
("", "bar", 3), | |
("bar", "baz", 1), | |
("foofoofoo", "foo", 6), | |
], | |
) | |
def test_levenshtein(s_1, s_2, distance): | |
# arrange is done completely via parametrize | |
# act and assert: | |
assert levenshtein(s_1, s_2) == distance # perfectly reasonable | |
@pytest.mark.parametrize( | |
"s_1, s_2", | |
[ | |
("", b""), | |
("foo", 3), | |
(1, 11), | |
], | |
) | |
def test_levenshtein_bad_types(): | |
with pytest.raises(ValueError): | |
assert levenshtein(s_1, s_2) # reasonable | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment