Skip to content

level 2#2

Merged
uraniumcore238 merged 2 commits intomainfrom
level_2
Mar 10, 2024
Merged

level 2#2
uraniumcore238 merged 2 commits intomainfrom
level_2

Conversation

@uraniumcore238
Copy link
Copy Markdown
Owner

No description provided.

Copy link
Copy Markdown

@vppuzakov vppuzakov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 тесты отличные, кейсы хорошие. Вмерживай.
💡 далее по комментам давай поработаем и разделим некоторые тесты по раздельным тесткейсам - чтобы ты мог каждому этому тесту дать такое название - по которому не глядя в тело теста и параметры (только глядя в аутпут при запуске теста) будет понятно, что этот тест по факту тестируем (заметь - нам не важно как тестирует - нам важно что)

  • тестирую что функция деления при делении на ноль вернет ошибку
  • тестирую что уровнение находит два разных корня
  • тестирую что уровнение не может найти корни когда оба коэффициента нули
    итд

ПС: сорри за долгий отклик, далее буду стараться держать SLA

Comment thread functions/level_2/five_replace_word.py Outdated
return ' '.join(new_words)


print(replace_word('replace', 'replace', 'htllo')) No newline at end of file
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

print - выпиливай
💡 смотри какой пайплайн норм вместо принтов, чтобы узнать а как же работает функция:

# если функция возвращает строку
def test__somefunc__smoke():
    assert somefunc() == ''

и запустив это с флагом -vv и установленным для удобства pytest-clarity ты увидешь четкий дифф и значение которое возвращает эта функция и уже в готовом тесте. Дальше остается только понять что уже ты хочешь потестить, написать тест и какое название дать этому тесту.

from functions.level_2.four_sentiment import check_tweet_sentiment


@pytest.mark.parametrize(('text', 'result'), [
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 круто, что попробовал задействовать тут parametrize.
💡 в данном варианте у нас несколько тест кейсов спрятались в один тест - это не здорово. Давай разделим их по кейсам (и для некоторых вполне можно оставить параметрайз):

  • return_good
  • return_bad
  • return_none_on_good_and_bad_equal
  • return_none_on_if_no_good_or_bad_verbs_in_text

Так станет понятнее, почему именно такая комбинация параметров дает именно такой результат - не ошибка ли это и тд. Потому что зафиксирован контракт функции словами в ее названии.

💡 а что, если наш словарь плохих и хороших слов пустой?

from functions.level_2.one_pr_url import is_github_pull_request_url


@pytest.mark.parametrize(('url', 'result'), [
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 тоже давай разобьем этот параметрайз на несколько тестов в соответствии с их кейсами - не забывай в названии отразить какой именно кейс тестируем. Некоторые параметры возможно сохранятся - зависит от того какие кейсы ты выделишь.

Помни, всегда название теста должно читаться как осмысленное законченное предложение и выглядеть так test__funcname__do_something_when_something

Comment thread tests/level_2/test_replace_word.py Outdated
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 название теста должно повторять структуру модулей - test_five_replace_word.py

Comment thread tests/level_2/test_replace_word.py Outdated
('one', 'one'),
('seven', 'one')
])
def test_five_replace_word_no_replacement(replace_from, replace_to):
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 название теста обязательно пиши по шаблону: test__funcname__do_something_when_something, обрати внимание на двойное подчеркивание

💡 обязательно нужно добавить ожидаемое действие - тут видно только что по факту нет соответствия - ок, но что в таком случае функция должна сделать? - это приходится понимать только глядя уже в тело теста. Тут нужно добавить - test__five_replace_word__do_not_replace_words_if_no_words_for_replace_found

не бойся длинных названий тестов, главное, чтобы они были осмысленными - описывали часть контракта функции.

Comment thread tests/level_2/test_replace_word.py Outdated
('one', 'seven'),
('one', 'two')
])
def test_five_replace_word_with_replacement(replace_from, replace_to):
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 вот тут параметры зашли вполне неплохо

💡 сложно интерпретировать такой тест из-за сложной логике в теле ради использования параметров. Смотри че можно придумать:

  • использовать тупо expected - это будет в данном случае куда читаемей и вполне уместно тут
# все в параметры
assert replace_word(text, replace_from, replace_to) == expected
  • использовать переменные поактивнее:
replaced_word = "one"
other = "some text here"  # or use faker.words
assert replace_word(f"{replaced_word} {other}") == f"{replaced_word} {other}"
  • но есть самый лучший вариант - сузить тесткейсы:
def test__replace_word__replace_one_word():
    assert replace_word("one two three four", "one", "seven") == "seven two three four"


def test__replace_word__replace_many_words():
    assert replace_word("one two one four", "one", "seven") == "seven two seven four" 

Эти тесты весьма понятные, потому что максимально явные.

💡 докинь еще кейсов на тему совпадения строк по ignorecase или нет - тоже вполне себе контракт на функцию - надо зафиксировать в тесте.

Comment thread tests/level_2/test_three_first.py Outdated
assert first(items, default) == result


def test_with_attribute_error():
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 хороший кейс
💡 добавь имя тестируемой функции по шаблону, а заодно надо дописать причину почему она райзит эту ошибку test__somefunc__do_something_when_something

Comment thread tests/level_2/test_three_first.py Outdated
from functions.level_2.three_first import first


@pytest.mark.parametrize(('items', 'default', 'result'), [
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 ну как будто все тест-кейсы отличные
💡 станет куда понятнее, если все таки раскидаешь параметры по разным кейсам - параметры используем, когда хотим проверить один кейс на разных входах:

@parametrize(...)
def test__add__correctly_sum_two_numbers(a, b, expected):
    assert a + b == expected


@parametrize(('number'), [10, 20, 0, 1000, -100, 100.500])
def test__division__raise_zero_division_error(number):
    with pytest.raises(...):
        divide(number, 0)

(0.0, 0.1, -0.1, (1.0, None)),
(0.0, -0.1, -0.1, (-1.0, None))
])
def test_two_square_zero_data(square_coeff, linear_coeff, const_coeff, result):
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 кейсы точно стоит разделить - я даже не сразу понял о какой zero_data - речь. Каждый коэффициент может быть 0 - это все разные тест кейсы. И обязательно ожидаемое поведение - вообще если видишь, что в тесте нет или не можешь дать ожидаемое поведение в названии - что-то с тестом не так. Надо сужать кейсы.

  • test__solve_square_equation__no_roots_found_for_zero_ab_coeffs
  • test__solve_square_equation__found_one_root_if_only_a_coeff_is_zero

Давай разобьем.

❗ обязательно название функции в тест, а не модуль

(-0.1, 0.1, -0.9, (None, None)),
(-0.1, -0.1, -0.1, (None, None))
])
def test_two_square_some_equal_coefficients(square_coeff, linear_coeff, const_coeff, result):
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 не так важны входы в кейсе, как то что ты от него ожидаешь. Вот тут ожидаемый результат разный - где-то корень будет найден, где-то нет. Это разные кейсы скорее всего - либо это просто стандартная история при решении уровнения и явно конкретизировать одинаковость коэффициентов не имеет смысла. В этих параметрах я вижу два кейса:

  • кейс когда корни остутствуют
  • кейс когда корни найдены (а это отлично объединяется со следующим кейсом)

@uraniumcore238 uraniumcore238 merged commit a75865d into main Mar 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants