привет! у меня есть следующий код, я хочу его протестировать:

class SomeModel:  # pylint: disable=R0903
    def predict(self, message: str) -> float:
        punctuation_symbols = [".", "!", "?", ",", ";", ":"]
        num_punctuation = sum(
            message.count(symbol) for symbol in punctuation_symbols
        )

        total_chars = len(
            [
                char
                for char in message
                if char.isalpha() or char in punctuation_symbols
            ]
        )

        if total_chars == 0:
            return 0.0

        prediction = num_punctuation / total_chars
        return prediction


def predict_message_mood(
    message: str, bad_threshold: float = 0.3, good_threshold: float = 0.8
) -> str:

    model = SomeModel()

    prediction = model.predict(message)

    if prediction < bad_threshold:
        return "неуд"
    if prediction > good_threshold:
        return "отл"
    return "норм"

я хочу использовать тестирование с помощью mock, то есть тесты предиктора должны заменять результат работы модели и тестировать predict_message_mood с учетом данной подмены

тесты предиктора должны проверять строку, которая была фактически передана в predict, это важно

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

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

import unittest
from unittest.mock import patch
from predict_function import predict_message_mood, SomeModel


class TestPredictMessageMood(unittest.TestCase):

    def mock_predict(self, message: str) -> float:
        punctuation_symbols = [".", "!", "?", ",", ";", ":"]
        num_punctuation = sum(
            message.count(symbol) for symbol in punctuation_symbols
        )

        total_chars = len(
            [
                char
                for char in message
                if char.isalpha() or char in punctuation_symbols
            ]
        )

        if total_chars == 0:
            return 0.0

        prediction = num_punctuation / total_chars
        return prediction

    @patch('predict_function.SomeModel.predict')
    def test_default_predict(self, mock_predict):
        mock_predict.side_effect = self.mock_predict

        test_cases = [
            ("Пусто", "неуд"),
            ("Привет, как дела?", "неуд"),
            ("Это тест...", "норм"),
        ]

        for message, expected in test_cases:
            with self.subTest(message=message, expected=expected):
                result = predict_message_mood(message)
                self.assertEqual(result, expected)

    def test_custom_predict(self):
        self.assertEqual(predict_message_mood("Кто????", 0.1, 0.5), "отл")
        self.assertEqual(predict_message_mood("Привет!", 0.1, 0.9), "норм")
        self.assertEqual(
            predict_message_mood("Здравствуйте.", 0.5, 0.7), "неуд"
        )
        self.assertEqual(predict_message_mood("Я!!!", 0.2, 0.5), "отл")

    def test_empty_message_predict(self):
        self.assertEqual(predict_message_mood(""), "неуд")

    def test_one_character_predict(self):
        self.assertEqual(predict_message_mood("А"), "неуд")
        self.assertEqual(predict_message_mood("!"), "отл")

    def test_only_punctuation_predict(self):
        self.assertEqual(predict_message_mood("!!!"), "отл")
        self.assertEqual(predict_message_mood("..."), "отл")
        self.assertEqual(predict_message_mood("!?."), "отл")

    def test_no_punctuation_predict(self):
        self.assertEqual(
            predict_message_mood("Это тест без знаков препинания"), "неуд"
        )

    def test_only_spaces_predict(self):
        self.assertEqual(predict_message_mood("     "), "неуд")

    def test_extremes_predict(self):
        self.assertEqual(predict_message_mood("!", 0.0, 0.01), "отл")
        self.assertEqual(predict_message_mood("!!!", 0.0, 1.0), "норм")
        self.assertEqual(predict_message_mood(".", 0.4, 0.99), "отл")

    def test_numbers_and_punctuation_predict(self):
        self.assertEqual(predict_message_mood("Пример 123!!!"), "норм")
        self.assertEqual(predict_message_mood("2024 год."), "неуд")
        self.assertEqual(
            predict_message_mood("Версия 2.0; стабильная."), "неуд"
        )

    def test_symbols_predict(self):
        self.assertEqual(predict_message_mood("Привет @2024"), "неуд")
        self.assertEqual(predict_message_mood("#хорошо!"), "неуд")
        self.assertEqual(predict_message_mood("Цена $100."), "неуд")
        self.assertEqual(predict_message_mood("#404!!!"), "отл")

    def test_repeated_punctuation_predict(self):
        self.assertEqual(predict_message_mood("!!!"), "отл")
        self.assertEqual(predict_message_mood("???"), "отл")
        self.assertEqual(predict_message_mood("!!!???"), "отл")
        self.assertEqual(predict_message_mood("!!!   ???"), "отл")

    def test_mixed_punctuation_predict(self):
        self.assertEqual(
            predict_message_mood("Привет! Как дела? Всё хорошо."), "неуд"
        )
        self.assertEqual(predict_message_mood("Что?..."), "норм")
        self.assertEqual(predict_message_mood("Ура! Супер: отлично!"), "неуд")
        self.assertEqual(predict_message_mood("Расчет: 1, 2, 3..."), "норм")

    def test_mixed_case_predict(self):
        self.assertEqual(predict_message_mood("ПРИВЕТ!!!"), "норм")
        self.assertEqual(predict_message_mood("да!!!"), "норм")
        self.assertEqual(predict_message_mood("ПрИвЕт!!!"), "норм")
        self.assertEqual(predict_message_mood("Хорошо."), "неуд")

    def test_multiple_spaces_predict(self):
        self.assertEqual(predict_message_mood("Привет!   Как   дела?"), "неуд")
        self.assertEqual(predict_message_mood("Это    тест."), "неуд")
        self.assertEqual(predict_message_mood("вау !!!!!!!!!!"), "норм")

    def test_tabs_predict(self):
        self.assertEqual(predict_message_mood("Привет!\nКак дела?"), "неуд")
        self.assertEqual(predict_message_mood("Отлично!\tВсе хорошо."), "неуд")
        self.assertEqual(
            predict_message_mood("Нормально.\nВсе в порядке."), "неуд"
        )

    def test_unrecognized_punctuation_predict(self):
        self.assertEqual(predict_message_mood("А~?"), "норм")
        self.assertEqual(predict_message_mood("` "), "неуд")


if __name__ == "__main__":
    unittest.main()