ViewModel ์ ๋ ํ ์คํธ, CacheManager ์ ๋ ํ ์คํธ
๋๋์ด protocol ์ถ์ํ, ์์กด์ฑ ์ฃผ์ ์ด ๋น์ ๋ฐํ ๋๊ฐ ๋์๋ค..!๐ฒ๐ฅ
์ผ๋จ์ Repository๊ฐ ์ฑ๊ณต์ ์๋๋ฆฌ์ค๋ง ๋ฐ์์ํค๋๋ก ๊ตฌํ. ์คํจ ์๋๋ฆฌ์ค๊ฐ ํ์ํ ์, ๊ฐ ์๋ต์ property ๋ก ๋ง๋ค์ด ํ ์คํธ ์ง์ ์ํ๋ ๊ฒฐ๊ณผ๋ฅผ ์ฃผ์ ์์ผ์ค ์ ์์ ๊ฒ ๊ฐ์์
final class MockClothesRepository: ClothesRepositoryProtocol {
func fetchClothesList() -> AnyPublisher<ClothesList, RepositoryError> {
return Just(ClothesList.mocks)
.setFailureType(to: RepositoryError.self)
.eraseToAnyPublisher()
}
...
ClothesRepositoryProtocol
๋ฅผ ๊ตฌํํ MockRepository
๋ฅผ ViewModel ์ ์ฃผ์
ํด์ sut
๋ฅผ ์ด๊ธฐํvar sut: ClothesViewModel!
override func setUpWithError() throws {
let mockRepository = MockClothesRepository()
sut = ClothesViewModel(repository: mockRepository)
...
func test_๊ณ์ _filter๊ฐ_์ ์ฉ๋๋์ง_ํ
์คํธ() {
// given
let categories = ClothesCategory.allCases
let weatherFilterType: WeatherType = .fall
sut.searchFilters.send([.weather(weatherFilterType)]) // ๊ณ์ filter ๊ฒ์
// ๊ฐ๊ฐ์ ์นดํ
๊ณ ๋ฆฌ์ ๋ํ expectation
var expectations: [XCTestExpectation] = []
categories.forEach { category in
let expectation = XCTestExpectation(description: category.korean)
expectations.append(expectation)
// when
sut.clothes(of: category)
.sink { clothes in
// then
XCTAssertTrue(clothes.allSatisfy {
// ๋ชจ๋ ๊ฒฐ๊ณผ๊ฐ์ด ํด๋น filter์ ๋์ผํ์ง ์ฒดํฌ
$0.weatherType == weatherFilterType
})
expectation.fulfill()
}
.store(in: &cancellables)
...
ImageCacheManager
๋ฅผ ํ
์คํธ๋ค๋ง, ํด๋น ํ ์คํธ๊ฐ ๋ฐ๋์ ์ฑ๊ณตํ๋ฆฌ๋ผ๋ ๋ณด์ฅ์ ํ ์ ์์๋๋ฐ,
NSCache์ ํน์ฑ์countLimit
๊ณผtotalCostLimit
์ด ์ ๊ณตํ๋ limit์ด imprecise ํ๋ค๊ณ ๋ช ์๋์ด ์์๊ธฐ ๋๋ฌธ.
๋คํํ, ์ด๋ ์ ๋๊น์ง๋ ์์ํ ๋๋ก ๋์ํ๋ ๊ฒ์ ํ์ธํ ์ ์์์
func test_์ ์ฅ์_๊ฐฏ์์ ํ์ด_์ ์ฉ๋๋์ง_ํ์ธ() {
// given
let ids = (0...10).map { _ in UUID() }
let countLimit = 3
// when
sut.countLimit = countLimit // ์บ์ฑ ์ ์ฅ ์ด๋ฏธ์ง ์๋ฅผ 3๊ฐ๋ก ์ ํ
ids.forEach { id in
sut.store(UIImage(), for: id)
}
// then
let storedImages = ids
.compactMap { sut.get(for: $0) }
// ๊ฐฏ์ ์ ํ์ ์ค ๊ฐฏ์๋ณด๋ค ๊ฐ๊ฑฐ๋ ์ ๊ฒ ์ ์ฅ๋์๋์ง ํ์ธ
XCTAssertGreaterThanOrEqual(countLimit, storedImages.count)
func test_์ ์ฅ์_์ฉ๋์ ํ์ด_์ ์ฉ๋๋์ง_ํ์ธ() {
// given
let images = [
UIImage(systemName: "pencil")!,
UIImage(systemName: "pencil.slash")!,
UIImage(systemName: "pencil.circle")!,
UIImage(systemName: "pencil.circle.fill")!,
UIImage(systemName: "pencil.line")!
]
// ๊ฐ์ฅ ์์ ์ด๋ฏธ์ง ์ฉ๋
let imageDataSize = images.compactMap { $0.pngData()?.count }.min() ?? 0
let ids = (0..<5).map { _ in UUID() }
// when
sut.byteLimit = imageDataSize * 3 // ๋๋ต ์ด๋ฏธ์ง 3๊ฐ ์ ๋์ ์ฌ์ด์ฆ๋งํผ ์ฉ๋ ์ ํ์ ์ค
zip(images, ids).forEach { image, id in
sut.store(image, for: id)
}
// then
let storedImages = ids
.compactMap { sut.get(for: $0) }
// ์ฉ๋ ์ ํ์ ์ค 3๊ฐ๋ก ์ฃผ์๊ธฐ์, ๊ทธ๋ณด๋ค ๊ฐ๊ฑฐ๋ ์ ๊ฒ ์ ์ฅ๋์๋์ง ํ์ธ
XCTAssertGreaterThanOrEqual(3, storedImages.count)