We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
import Foundation import RxCocoa import RxSwift protocol SearchUseCase { var successReqeustSearch: PublishRelay<Repos> { get set } var failGithubError: PublishRelay<GithubServerError> { get set } func requestSearch(searchName: String, page: Int) } final class DefaultSearchUseCase: SearchUseCase { private let githubRepository: GithubRepositoryType private let disposeBag = DisposeBag() var successReqeustSearch = PublishRelay<Repos>() var failGithubError = PublishRelay<GithubServerError>() init( githubRepository: GithubRepositoryType ){ self.githubRepository = githubRepository } } extension DefaultSearchUseCase { func requestSearch(searchName: String, page: Int) { let query = ReposQuery(searchName: searchName) self.githubRepository.requestSearch(query: query, page: page) { [weak self] response in guard let self = self else { return } switch response { case .success(let repos): self.successReqeustSearch.accept(repos) case .failure(let error): self.failGithubError.accept(error) } } } }
final class SearchViewModel: ViewModelType { private weak var coordinator: TabBarCoordinator? private let useCase: SearchUseCase struct Input { let pullRefresh: Signal<Void> let didScrollToBottom: Signal<Void> let searchBarText: Signal<String> } struct Output { let repoList: Driver<[RepoItem]> let refreshAction: Signal<Bool> let bottomSpinnerAction: Signal<Bool> } var disposeBag = DisposeBag() ... }
SearchUseCase
import Foundation import RxCocoa import RxSwift @testable import GithubRepos final class MockSearchUseCase: SearchUseCase { var successReqeustSearch = PublishRelay<Repos>() var failGithubError = PublishRelay<GithubServerError>() init() { } func requestSearch(searchName: String, page: Int) { if page < 30 && page > 0 { self.successReqeustSearch.accept( Repos( items: [ RepoItem(id: 1, fullName: "GodRepos/kingkinggod", description: nil, topics: ["likes", "king", "godofkingking"], star: 1000, fork: 2, language: "Swift", updatedAt: Date()) ] ) ) } else { self.failGithubError.accept(.unknown) } } }
import XCTest import RxCocoa import RxSwift import RxTest @testable import GithubRepos class SearchViewModelTests: XCTestCase { private var viewModel: SearchViewModel! private var disposeBag: DisposeBag! private var scheduler: TestScheduler! private var input: SearchViewModel.Input! private var output: SearchViewModel.Output! private let dummyData = [ RepoItem(id: 1, fullName: "GodRepos/kingkinggod", description: nil, topics: ["likes", "king", "godofkingking"], star: 1000, fork: 2, language: "Swift", updatedAt: Date()) ] override func setUpWithError() throws { self.viewModel = SearchViewModel( coordinator: nil, useCase: MockSearchUseCase() ) self.disposeBag = DisposeBag() self.scheduler = TestScheduler(initialClock: 0) } override func tearDownWithError() throws { self.viewModel = nil self.disposeBag = nil } func test_Search_Success_Case() throws { let refreshTestableObservable = self.scheduler.createHotObservable([ .next(0, ()) ]) let scrollTestableObservable = self.scheduler.createHotObservable([ .next(20, ()) ]) let textTestableObservable = self.scheduler.createHotObservable([ .next(10, "29cm") ]) let repoListObserver = self.scheduler.createObserver([RepoItem].self) self.input = SearchViewModel.Input( pullRefresh: refreshTestableObservable.asSignal(onErrorJustReturn: ()), didScrollToBottom: scrollTestableObservable.asSignal(onErrorJustReturn: ()), searchBarText: textTestableObservable.asSignal(onErrorJustReturn: "") ) self.viewModel.transform(input: input) .repoList .drive(repoListObserver) .disposed(by: self.disposeBag) scheduler.start() XCTAssertEqual(repoListObserver.events, [ .next(0, []), .next(10, []), // 백그라운드 배경을 띄우려고 나온 빈배열 .next(10, dummyData) ], "The objects should be equal but is not") } }
import XCTest class GithubReposUITests: XCTestCase { override func setUpWithError() throws { continueAfterFailure = false } override func tearDownWithError() throws { } func testSearchRepositoryFlow() throws { let app = XCUIApplication() app.launch() let searchField = app.otherElements["searchBar"] searchField.tap() searchField.typeText("Youngminah") app.buttons["searchButton"].tap() } func testLaunchPerformance() throws { if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) { // This measures how long it takes to launch your application. measure(metrics: [XCTApplicationLaunchMetric()]) { XCUIApplication().launch() } } } }
The text was updated successfully, but these errors were encountered:
No branches or pull requests
테스트 코드 도전기
SearchViewModel 테스트 코드 작성을 위한 선행 작업
1. SearchUseCase프로토콜을 만들어 인터페이스로 채택하도록
2.SearchViewModel에선 UseCase를 프로토콜 형식으로 선언.
SearchUseCase
란 프로토콜 형식으로 유즈케이스가 선언되어있음!MockSearchUseCase
간단한 UITest 코드 작성
UITest 코드
UITest 실행 화면
Simulator.Screen.Recording.-.iPhone.12.Pro.-.2022-03-17.at.09.10.33.mp4
The text was updated successfully, but these errors were encountered: