-
Notifications
You must be signed in to change notification settings - Fork 3
Unit Testing
Sue Cho edited this page Dec 19, 2020
·
3 revisions
- View์ ViewModel์ด Binding ๋์ด ์๋ ๊ตฌ์กฐ๋ก View์์ ๋ฐ์ํ ํน์ ์ด๋ฒคํธ๋ก ์ธํด ViewModel์ State ๊ฐ์ด ๋ฐ๋๋ฉด ๊ทธ ๊ฐ์ ์ํด View๊ฐ ์
๋ฐ์ดํธ ๋จ
- ๋ฐ๋ผ์, View๊ฐ ๊ทธ๋ ค์ง๋ ๋ก์ง ์ญ์ testing์ด ๊ฐ๋ฅํจ
- ๊ฐ์ฒด ๊ฐ ์์กด๊ด๊ณ๊ฐ ๋์์ง๋ฉด testing์ด ํ๋ค์ด์ง๋ฏ๋ก ์ถ์ํ๊ฐ ํ์ํจ. ํ์ฌ ํ๋ก์ ํธ์์ ์์กด๊ด๊ณ๋ฅผ ์ดํด๋ณด๋ฉด ViewModel - UseCase(+ EventLogger) - NetworkService ์ด๋ฏ๋ก,
- ViewModel์ test ํ๊ธฐ ์ํด์ UseCase๊ฐ ๋ฐ๋์ ํ์ํ๊ณ
- UseCase๋ฅผ test ํ๊ธฐ ์ํด์ NetworkService๊ฐ ๋ฐ๋์ ํ์ํจ.
- ๋ฐ๋ผ์ UseCase์ NetworkService๋ฅผ ์ถ์ํํ์ฌ Unit Test๋ฅผ ์งํํ ๋๋ ๋ชจ์ ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด ์ฃผ์ ํ๋ ๋ฐฉ์์ผ๋ก ์งํ
- UseCaes๋ NetworkService์ ์์กด์ฑ์ ๊ฐ์ง๋ฏ๋ก ์ถ์ํ๋ NetworkServiceType์ ์ฑํํ์ฌ ๋ฌด์กฐ๊ฑด์ ์ผ๋ก ์ฑ๊ณต์ ์ธ response๋ฅผ ๋๋ ค์ฃผ๋ MockSuccessNetworkService ๊ตฌํ
struct MockSuccessfulNetworkService: NetworkServiceType {
let data: Data
func request(url: String, request type: RequestType, body: Data?) -> AnyPublisher<Data, NetworkError> {
return Just(data)
.setFailureType(to: NetworkError.self)
.eraseToAnyPublisher()
}
}
- UseCase๊ฐ '์ข์์' ์์ฒญ์ ๋คํธ์ํฌ๋ฅผ ํตํด ๋ณด๋ด๊ณ ๋์์จ ์๋ต์ด ์์ ํ๋ ์๋ต๊ณผ ์ผ์นํ๊ณ ์ต์ข ์ ์ผ๋ก ์คํจํ์ง ์๋ ๊ฒ์ด ๋ณด์ฅ๋์ด์ผ ํจ
func test_like_track_success() {
let expectations = XCTestExpectation(description: "track like success test")
defer { wait(for: [expectations], timeout: 5) }
let response = TrackUseCase.LikeTrackResponse(success: true)
let data = try? JSONEncoder().encode(likeTrack)
let usecase = TrackUseCase(network: MockSuccessNetworkService(data: data!))
usecase.likeTrack(id: 0)
.sink { result in
switch result {
case .finished:
expectations.fulfill() // ์ฑ๊ณตํ์ผ๋ฏ๋ก expectation fulfill
case let .failure(error):
XCTFail(error.localizedDescription) // ์ฑ๊ณตํด์ผ ๋ ์์ฒญ์ด ์คํจํ๋ค๋ฉด XCTFail
}
} receiveValue: { receivedResult in
XCTAssertEqual(receivedResult, response.success) // ๋ฐ์์จ ๊ฐ์ด ์์ํ๋ success = true์ ์ผ์นํด์ผ ํจ
}
.store(in: &cancellables)
}
- ViewModel์ UseCase์ ์์กด์ฑ์ ๊ฐ์ง๋ฏ๋ก TrackUseCase๊ฐ ์ถ์ํ๋ TrackuseCaseType์ ์ฑํํ์ฌ ์ํ๋ ๊ทธ๋๋ก ๋ฐฉ์ถํด์ฃผ๋ MockTrackUseCase ๊ตฌํ
struct MockTrackuseCase: TrackuseCaseType {
let track: TrackInfo
...
func likeTrack(id: Int) -> AnyPublisher<Bool, UseCaseError> {
Just(true) // UseCase๋ฅผ ํตํ ์์ฒญ ๋ฐ ์๋ต์ด ์ฑ๊ณต์ ์ด์์
.setFailureType(to: UseCaseError.self)
.eraseToAnyPublisher()
}
}
- ViewModel์ State ๊ฐ์ด ๋ฐ๋ ์ ์๋๋ก View์์ ์ผ์ด๋ ์ด๋ฒคํธ๋ฅผ ๋ฃ์ด์ฃผ์ด ๊ฐ์ ๋ณํ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ๋์๋์ง ๊ด์ฐฐ
func test_like_trac() {
let expectation = XCTestExpectation(description: "Like track test")
defer { wait(for: [expectation], timeout: 5) }
let usecase = MockTrackuseCase(track: track) // track.liked == false
let eventLogger = MockEventLogger { } // EventLogger๋ ๋ชจ์๋ก ์์ฑํ์ผ๋ฉฐ, ์๋ฒ์๊ฒ ๋ณด๋ด์ง ์ด๋ฒคํธ๊ฐ ๋ง๊ฒ ๋ถ๋ ธ๋์ง ํ์ธํด์ผํจ (์ฐ์ ์๋ต)
let viewModel = TrackViewModel(track: track, usecase: usecase, eventLogger: eventLogger)
viewModel.$state
.sink { state in
if state.track.liked { // track.liked == true ๋ก ๋ฐ๋์ด์ผ expectation fulfill
expectation.fulfill()
}
}
.store(in: &cancellables)
viewModel.send(.like) // View์์ ๋ฐ์ํ ์ด๋ฒคํธ๋ฅผ ์ค
}