Как проверить сложные функции, которые используют запросы? - PullRequest
0 голосов
/ 11 апреля 2019

Я хочу протестировать свой код на основе API, созданного кем-то другим, но я не уверен, как мне это сделать.

Я создал некоторую функцию для сохранения json в файл, поэтому я нене нужно отправлять запросы каждый раз, когда я запускаю тестирование, но я не знаю, как заставить его работать в ситуации, когда исходная функция (проверка) принимает входной аргумент (problem_report), который является экземпляром некоторого класса, предоставляемого API иу него есть метод problem_report.get_correction (corr_link) .Мне просто интересно, является ли это признаком плохого написанного мной кода, потому что я не могу написать тест для этого, или, возможно, мне следует переписать эту функцию в моем файле тестов, как я показал в конце приведенного ниже кода.

# I to want test this function
def check(problem_report): 
    corrections = {}
    for corr_link, corr_id in problem_report.links.items():
        if re.findall(pattern='detailCorrection', string=corr_link):
            correction = problem_report.get_correction(corr_link)
            corrections.update({corr_id: correction})
    return corrections

# function serves to load json from file, normally it is downloaded by API from some page.
def load_pr(pr_id): 
    print('loading')
    with open('{}{}_view_pr.json'.format(saved_prs_path, pr_id)) as view_pr:
        view_pr = json.load(view_pr)
    ...
    pr_info = {'view_pr': view_pr, ...}
    return pr_info

# create an instance of class MyPR which takes json to __init__
@pytest.fixture
def setup_pr():
    print('setup')
    pr = load_pr('123')
    my_pr = MyPR(pr['view_pr'])
    return my_pr 

# test function
def test_check(setup_pr):
    pr = setup_pr
    checked_pr = pr.check(setup_rft[1]['problem_report_pr'])
    assert checker_pr

# rewritten check function in test file 
@mock.patch('problem_report.get_correction', side_effect=get_corr)
def test_check(problem_report):
    corrections = {}
    for corr_link, corr_id in problem_report.links.items():
        if re.findall(pattern='detailCorrection', string=corr_link):
            correction = problem_report.get_correction(corr_link)
            corrections.update({corr_id: correction})
    return corrections

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

Ответы [ 2 ]

1 голос
/ 18 апреля 2019

Я понимаю ваш вопрос следующим образом: у вас есть функция check, которую вы считаете сложной для тестирования из-за ее зависимости от problem_report. Чтобы сделать его лучше тестируемым, вы скопировали код в тестовый файл. Вы будете тестировать скопированный код, потому что вы можете изменить его, чтобы его было проще тестировать. И вы хотите знать, имеет ли этот подход смысл.

Ответ - нет, это не имеет смысла. Вы проверяете не реальную функцию, а совершенно другой код. Ну, код может не начать полностью отличаться, но в скором времени копия и оригинал будут отличаться, и это будет кошмар обслуживания, чтобы гарантировать, что копия всегда напоминает оригинал. Совершенствование кода для тестируемости - это отдельная история: вы можете внести изменения в функцию check, чтобы улучшить ее тестируемость. Но тогда в тесте и в рабочем коде должна использоваться одна и та же результирующая функция.

Как лучше проверить функцию check тогда? Во-первых, вы уверены, что использование оригинальных объектов problem_report не может быть разумно использовано в ваших тестах? (Вот несколько критериев, которые помогут вам решить: Что подделать для тестовых случаев Python? ). Теперь давайте предположим, что вы пришли к выводу, что вы не можете разумно использовать оригинал problem_report.

В этом случае интерфейс достаточно прост, чтобы определить макет problem_report. Имейте в виду, что Python использует типизацию утили, поэтому вам нужно всего лишь создать класс, в котором есть links член, который имеет метод items(). Кроме того, вашему высмеянному problem_report классу нужен метод get_correction(). Кроме того, ваш макет не должен производить типы, которые похожи на типы, используемые problem_report. Метод items() может просто возвращать список списков, например [["a",2],["xxxxdetailCorrectionxxxx",4]]. Тот же аргумент справедлив для get_correction, который может, например, просто вернуть свой аргумент или производное значение, например, его отрицательное значение.

Для приведенного выше примера (items() возвращает [["a",2],["xxxxdetailCorrectionxxxx",4]] и get_correction возвращает отрицательный аргумент) ожидаемый результат будет {4: -4}. Не нужно имитировать реальные correction объекты. И вы можете создавать свои смоделированные версии problem_report без необходимости считывать данные из файлов - макеты могут быть полностью настроены из кода модульного тестирования.

0 голосов
/ 11 апреля 2019

Попробуйте исправить символ problem_report в модуле. Вы должны поместить свои тесты в отдельный класс.

@mock.patch('some.module.path.problem_report')
def test_check(problem_report):
    problem_report.side_effect = get_corr
    corrections = {}
    for corr_link, corr_id in problem_report.links.items():
        if re.findall(pattern='detailCorrection', string=corr_link):
            correction = problem_report.get_correction(corr_link)
            corrections.update({corr_id: correction})
    return corrections
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...