Post

my-Repository-Traffic프로젝트 이슈 - Python third-party mocking하기

my-Repository-Traffic 저장소

😂 개요

프로젝트는 github API를 다른 Third-party를 이용해서 호출하고 있었다.

유닛 테스트를 위해 테스트코드를 짜려다보니.. Third-party API들은 어떻게 모킹하지?

의문이 들었다.

chatGPT에게 물어봐서 해결하긴 했지만 그 과정을 적고 이해하기 위해 블로그에 적는다.

🔅 환경

1
2
3
4
5
6
7
8
9
10
11
12
def get_all_repositories_cloner(repositories: github.PaginatedList.PaginatedList) -> dict:
    cloner_counts = {}
    for repository in repositories:
        clone_traffic = get_repository_clone_traffic(repository)
        unique_cloner = clone_traffic['uniques']
        if unique_cloner == 0:
            continue
        cloner_counts[repository.full_name] = unique_cloner
    return cloner_counts

def get_repository_clone_traffic(repository: github.Repository.Repository) -> dict:
    return repository.get_clones_traffic()

이 코드를 테스트해야한다.

get_all_repositories_cloner() 파라미터를 보면 github.PaginatedList.PaginatedList라는 타입을 받는데, 이는 pygithub라는 써드파티에서 제공하는 자료형이다.

for문을 도는 부분이 있는데, 이 코드가 돌 수 있게 적절히 모킹해줘야한다.

또한 cloner_counts[repository.full_name]repository.full_name에 접근할 수 있도록 모킹해줘야한다.

그렇기에 repositories라는 인자를 모킹해줘야하고, get_repository_clone_traffic() 모킹, for문을 돌 수 있게 해야하고, .연산자를 사용하기 위한 객체로 만들어야한다.

😊 방법

1
2
3
4
5
6
7
8
9
10
11
12
13
@pytest_asyncio.fixture
async def repositories() -> github.PaginatedList.PaginatedList:
    class Repository:
        def __init__(self, full_name):
            self.full_name = full_name

    mock_paginated_list = MagicMock(spec=github.PaginatedList.PaginatedList)
    mock_paginated_list.__iter__.return_value = iter([
        Repository(full_name="kkminseok.repo1"),
        Repository(full_name="kkminseok.repo2"),
        Repository(full_name="kkminseok.repo3"),
    ])
    return mock_paginated_list

먼저, PaginatedList 자료형으로 반환해야하고, .연산자를 사용하기 위해 클래스로 만들어서 리턴하도록 하였다.

그리고, for문을 돌기 위해서 __iter__를 모킹하였고, MagicMock을 통해 자료형을 지정하였다.

실제 테스트 코드에서는

1
2
3
4
5
6
7
def test_get_all_repositories_cloner(repositories: github.PaginatedList.PaginatedList, mocker: MockerFixture):
    mocker.patch("git_utils.get_repository_clone_traffic", return_value={"uniques": 100})
    result = get_all_repositories_cloner(repositories)
    assert len(result) == 3
    assert result['kkminseok.repo1'] == 100
    assert result['kkminseok.repo2'] == 100
    assert result['kkminseok.repo3'] == 100

이렇게 호출해주면 된다.

막상 짜고나니 별 거 아닌데.. 은근 모킹하는데 오래 걸렸다.

This post is licensed under CC BY 4.0 by the author.