Skip to content

Commit

Permalink
Merge pull request #19 from f-lab-edu/feature/FixInputOutput
Browse files Browse the repository at this point in the history
FetchRecipeDetailUseCaseTests를 생성하였습니다
  • Loading branch information
GeonH0 authored Jul 23, 2024
2 parents 1182d52 + ca5ca69 commit 3cb3f10
Show file tree
Hide file tree
Showing 3 changed files with 258 additions and 0 deletions.
22 changes: 22 additions & 0 deletions HomeCafeRecipes/HomeCafeRecipes/Domain/Entities/Recipe.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,25 @@ struct Recipe {
let likeCount: Int
let createdAt: Date
}

extension Recipe {

static func dummyRecipe() -> Recipe {
.init(
id: 1,
type: .coffee,
name: "",
description: "",
writer: .init(
id: 1,
profileImage: "",
nickname: "",
createdAt: Date()
),
imageUrls: [],
isLikedByCurrentUser: false,
likeCount: 0,
createdAt: Date()
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
//
// FetchRecipeDetailUseCaseTests.swift
// HomeCafeRecipesTests
//
// Created by 김건호 on 7/17/24.
//

import Foundation
import XCTest

import RxSwift

@testable
import HomeCafeRecipes

final class FetchRecipeDetailUseCaseTests: XCTestCase {

var fetchRecipeDetailRepository: FetchRecipeRepositoryMock!
var disposeBag: DisposeBag!

final class FetchRecipeRepositoryMock: RecipeDetailRepository {
var fetchRecipeDetailCallCount: Int = 0
var fetchRecipeDetailStub: Single<Recipe> = .just(Recipe.dummyRecipe())
func fetchRecipeDetail(recipeID: Int) -> Single<Recipe> {
fetchRecipeDetailCallCount += 1
return fetchRecipeDetailStub
}
}

func createUseCase() -> FetchRecipeDetailUseCase {
let usecase = FetchRecipeDetailUseCaseImpl(
repository: fetchRecipeDetailRepository
)
return usecase
}

override func setUpWithError() throws {
fetchRecipeDetailRepository = .init()
disposeBag = .init()
}
}

extension FetchRecipeDetailUseCaseTests {

func test_execute를_호출하면_RecipeDetailRepository의_fetchRecipeDetail을_호출합니다(){

// Given

let usecase = createUseCase()
fetchRecipeDetailRepository.fetchRecipeDetailStub = .just(Recipe.dummyRecipe())

// When

usecase.execute(recipeID: 1)
.subscribe()
.disposed(by: disposeBag)

// Then

XCTAssertEqual(fetchRecipeDetailRepository.fetchRecipeDetailCallCount, 1)
}

func test_RecipeDetailRepository의_성공응답이오면_Recipe를_반환합니다(){

// Given

let usecase = createUseCase()
let recipe = Recipe.dummyRecipe()
fetchRecipeDetailRepository.fetchRecipeDetailStub = .just(recipe)
let expectation = self.expectation(description: "Fetch Recipe Success")

// When

usecase.execute(recipeID: 1)
.subscribe(onSuccess: { result in
if case .success(let fetchedRecipe) = result {
// Then

XCTAssertEqual(fetchedRecipe.id, recipe.id)
expectation.fulfill()
} else {
XCTFail("Expected success but got failure")
}
}, onFailure: { error in
XCTFail("Expected success but got error: \(error)")
})
.disposed(by: disposeBag)

wait(for: [expectation], timeout: 1.0)
XCTAssertEqual(fetchRecipeDetailRepository.fetchRecipeDetailCallCount, 1)
}

func test_RecipeDetailRepository의_실패응답이오면_Error를_반환합니다() {

// Given

let usecase = createUseCase()
let error = NSError(domain: "TestError", code: -1)
fetchRecipeDetailRepository.fetchRecipeDetailStub = .error(error)
let expectation = self.expectation(description: "Fetch Recipe Failure")

// When

usecase.execute(recipeID: 1)
.subscribe(onSuccess: { result in
if case .failure(let receivedError as NSError) = result {
// Then

XCTAssertEqual(receivedError.domain, error.domain)
XCTAssertEqual(receivedError.code, error.code)
expectation.fulfill()
} else {
XCTFail("Expected failure but got success")
}
}, onFailure: { error in
XCTFail("Expected failure but got error: \(error)")
})
.disposed(by: disposeBag)

wait(for: [expectation], timeout: 1.0)
XCTAssertEqual(fetchRecipeDetailRepository.fetchRecipeDetailCallCount, 1)

}

}
111 changes: 111 additions & 0 deletions HomeCafeRecipes/HomeCafeRecipesTests/RecipeDeatilInteractorTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
//
// RecipeDeatilInteractorTests.swift
// HomeCafeRecipesTests
//
// Created by 김건호 on 7/9/24.
//

import Foundation
import XCTest

import RxSwift

@testable
import HomeCafeRecipes

final class RecipeDetailInteractorTests: XCTestCase {
var fetchRecipeDetailUsecase: FetchRecipeDetailUseCaseMock!
var delegate: RecipeDetailInteractorDelegateMock!

final class FetchRecipeDetailUseCaseMock: FetchRecipeDetailUseCase {
var executeCallCount: Int = 0
var executeStub: Single<Result<Recipe, Error>> = .just(.failure(NSError()))
func execute(recipeID: Int) -> Single<Result<Recipe, Error>> {
executeCallCount += 1
return executeStub
}
}

final class RecipeDetailInteractorDelegateMock: RecipeDetailInteractorDelegate {
var fetchedCallCount: Int = 0
var fetchedRecipeResult: Result<Recipe, Error>?
func fetchedRecipe(result: Result<Recipe, Error>) {
fetchedCallCount += 1
fetchedRecipeResult = result
}
}

func createInteractor(recipeID: Int = 0) -> RecipeDetailInteractor {
let interactor = RecipeDetailInteractorImpl(
fetchRecipeDetailUseCase: fetchRecipeDetailUsecase,
recipeID: recipeID
)

interactor.delegate = delegate
return interactor
}

override func setUpWithError() throws {
fetchRecipeDetailUsecase = .init()
delegate = .init()
}
}

// MARK: viewDidLoad

extension RecipeDetailInteractorTests {

func test_화면이_로드될때_FetchRecipeDetailUsecase를_호출합니다() {
// given
let interactor = createInteractor()

// when
interactor.viewDidLoad()

// then
XCTAssertEqual(self.fetchRecipeDetailUsecase.executeCallCount, 1)
}

func test_FetchRecipeDetailUsecase의_성공응답이오면_Delegate로_성공을_전달합니다() {
// given
let interactor = createInteractor()
let recipe = Recipe.dummyRecipe()
fetchRecipeDetailUsecase.executeStub = .just(.success(recipe))

// when
interactor.viewDidLoad()

// then
XCTAssertEqual(self.fetchRecipeDetailUsecase.executeCallCount, 1)
XCTAssertEqual(self.delegate.fetchedCallCount, 1)

if case .success(let fetchedRecipe)? = delegate.fetchedRecipeResult {
XCTAssertEqual(fetchedRecipe.id, recipe.id)
} else {
XCTFail("Expected success but got failure or nil")
}
}

func test_FetchRecipeDetailUsecase의_실패응답이오면_Delegate로_실패를_전달합니다() {

// given
let interactor = createInteractor()
let error = NSError(domain: "TestError", code: -1)
fetchRecipeDetailUsecase.executeStub = .just(.failure(error))

// when
interactor.viewDidLoad()

// then
XCTAssertEqual(self.fetchRecipeDetailUsecase.executeCallCount, 1)
XCTAssertEqual(self.delegate.fetchedCallCount, 1)

if case .failure(let fetchedError as NSError) = delegate.fetchedRecipeResult {
XCTAssertEqual(fetchedError.domain, error.domain)
XCTAssertEqual(fetchedError.code, error.code)
} else {
XCTFail("Expected success but got failure or nil")
}

}
}

0 comments on commit 3cb3f10

Please sign in to comment.