[swift] Swift Moya에서 테스트 Double 사용하기

Swift Moya는 네트워크 요청을 쉽게 관리하고 처리하는 라이브러리입니다. 하지만 테스트 시에 실제 네트워크 호출을 원치 않을 수 있습니다. 이럴 때 Moya에서 제공하는 테스트 Double을 사용하여 가짜 응답을 생성할 수 있습니다.

테스트 Double이란?

테스트 Double은 테스트 시에 실제 의존성을 대신하는 객체입니다. Moya에서는 MoyaProvider 객체를 통해 네트워크 호출을 수행합니다. 이때 MoyaProvider의 생성자에는 stubClosure 매개변수가 있는데, 이를 사용하여 테스트 Double을 구현할 수 있습니다.

테스트 Double 사용하기

아래는 Moya에서 테스트 Double을 사용하는 간단한 예제입니다.

import Moya
import XCTest

class NetworkManager {
    let provider: MoyaProvider<GitHubAPI>

    init(provider: MoyaProvider<GitHubAPI>) {
        self.provider = provider
    }

    func getUser(username: String, completion: @escaping (Result<User, Error>) -> Void) {
        provider.request(.getUser(username: username)) { result in
            switch result {
            case let .success(response):
                do {
                    let user = try response.map(User.self)
                    completion(.success(user))
                } catch {
                    completion(.failure(error))
                }
            case let .failure(error):
                completion(.failure(error))
            }
        }
    }
}

enum GitHubAPI {
    case getUser(username: String)
}

extension GitHubAPI: TargetType {
    var baseURL: URL {
        return URL(string: "https://api.github.com")!
    }

    var path: String {
        switch self {
        case .getUser(let username):
            return "/users/\(username)"
        }
    }

    var method: Moya.Method {
        return .get
    }

    var task: Task {
        return .requestPlain
    }

    var sampleData: Data {
        switch self {
        case .getUser:
            return """
                {
                    "login": "john",
                    "name": "John Doe"
                }
                """.data(using: .utf8)!
        }
    }

    var headers: [String: String]? {
        return nil
    }
}

class NetworkManagerTests: XCTestCase {
    var networkManager: NetworkManager!

    override func setUp() {
        super.setUp()
        let stubClosure: (GitHubAPI) -> Moya.StubBehavior = { _ in .immediate }
        let provider = MoyaProvider<GitHubAPI>(stubClosure: stubClosure)
        networkManager = NetworkManager(provider: provider)
    }

    // 테스트 케이스 작성
    func testGetUser() {
        let expectation = self.expectation(description: "should return user")
        networkManager.getUser(username: "john") { result in
            switch result {
            case .success(let user):
                XCTAssertEqual(user.login, "john")
                XCTAssertEqual(user.name, "John Doe")
                expectation.fulfill()
            case .failure:
                XCTFail("Failed to get user")
            }
        }

        waitForExpectations(timeout: 5, handler: nil)
    }
}

위의 예시는 Moya를 사용하여 GitHub API에서 사용자 정보를 가져오는 getUser 메서드를 호출하는 NetworkManager 클래스를 테스트하는 예제입니다. NetworkManagerTests 클래스에서 setUp 메서드를 사용하여 MoyaProvider에서 테스트 Double을 설정하고, testGetUser 메서드에서 getUser 메서드를 호출하고 응답을 검증합니다.

이렇게 테스트 Double을 설정하여 Moya의 의존성을 대체하면 실제 네트워크 호출 없이 테스트를 수행할 수 있습니다.

참고 자료