Skip to content

Commit

Permalink
Merge pull request #32 from f-lab-edu/feature/Login
Browse files Browse the repository at this point in the history
Login테스트 코드 작성
  • Loading branch information
GeonH0 authored Sep 29, 2024
2 parents fb8ccdb + d27703b commit fc78273
Show file tree
Hide file tree
Showing 3 changed files with 195 additions and 0 deletions.
12 changes: 12 additions & 0 deletions HomeCafeRecipes/HomeCafeRecipes.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
1D7641492C831295002AC68F /* LoginService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7641482C831295002AC68F /* LoginService.swift */; };
1D8474562C6C917900323001 /* SearchFeedListUseCaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D8474552C6C917900323001 /* SearchFeedListUseCaseTests.swift */; };
1D8474592C6CCF6900323001 /* TestUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D8474582C6CCF6900323001 /* TestUtils.swift */; };
1D93B9992CA26EB80094277F /* LoginUseCaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D93B9982CA26EB80094277F /* LoginUseCaseTests.swift */; };
1D95A0A62C37C79500F09077 /* RecipeDetailError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D95A0A52C37C79500F09077 /* RecipeDetailError.swift */; };
1D96FDAA2C7F55E600EFC657 /* LoginInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D96FDA92C7F55E600EFC657 /* LoginInteractor.swift */; };
1DBB55062C8418490009E033 /* LoginRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DBB55052C8418490009E033 /* LoginRouter.swift */; };
Expand All @@ -98,6 +99,10 @@
1DBC63672C47D23000DA00C2 /* AddRecipeError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DBC63652C47D23000DA00C2 /* AddRecipeError.swift */; };
1DBD90B92C91BDAC00184F67 /* SignUpService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DBD90B82C91BDAC00184F67 /* SignUpService.swift */; };
1DBD90BB2C91DE1600184F67 /* EmptyResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DBD90BA2C91DE1600184F67 /* EmptyResponse.swift */; };
1DC373A72CA810BB00B2E831 /* LoginRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7641462C831192002AC68F /* LoginRepository.swift */; };
1DC373A82CA8169F00B2E831 /* LoginUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7641442C81BE90002AC68F /* LoginUseCase.swift */; };
1DC373A92CA81AD400B2E831 /* LoginError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DD4F7092C80C947003E9D9D /* LoginError.swift */; };
1DC373AA2CA81AD900B2E831 /* LoginService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7641482C831295002AC68F /* LoginService.swift */; };
1DC7CC322C283C0200796889 /* RecipeUploadImgaeCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DC7CC312C283C0200796889 /* RecipeUploadImgaeCell.swift */; };
1DC7CC342C294F9200796889 /* SelectImageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DC7CC332C294F9200796889 /* SelectImageCell.swift */; };
1DD4F70A2C80C947003E9D9D /* LoginError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DD4F7092C80C947003E9D9D /* LoginError.swift */; };
Expand Down Expand Up @@ -206,6 +211,7 @@
1D7641482C831295002AC68F /* LoginService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginService.swift; sourceTree = "<group>"; };
1D8474552C6C917900323001 /* SearchFeedListUseCaseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchFeedListUseCaseTests.swift; sourceTree = "<group>"; };
1D8474582C6CCF6900323001 /* TestUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestUtils.swift; sourceTree = "<group>"; };
1D93B9982CA26EB80094277F /* LoginUseCaseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginUseCaseTests.swift; sourceTree = "<group>"; };
1D95A0A52C37C79500F09077 /* RecipeDetailError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecipeDetailError.swift; sourceTree = "<group>"; };
1D96FDA92C7F55E600EFC657 /* LoginInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginInteractor.swift; sourceTree = "<group>"; };
1DBB55052C8418490009E033 /* LoginRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginRouter.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -388,6 +394,7 @@
1D5AEE802C61099900BBD5F0 /* RecipeListInteractorTests.swift */,
1D5AEF292C64730A00BBD5F0 /* FetchFeedListUseCaseTests.swift */,
1D8474552C6C917900323001 /* SearchFeedListUseCaseTests.swift */,
1D93B9982CA26EB80094277F /* LoginUseCaseTests.swift */,
);
path = HomeCafeRecipesTests;
sourceTree = "<group>";
Expand Down Expand Up @@ -837,6 +844,7 @@
1DF0D1992C7B92C500E2C94C /* DateFormatter+Extensions.swift in Sources */,
1D5AEF382C64794A00BBD5F0 /* CGSize+addButton.swift in Sources */,
1D6958D82C3D5A80008604B3 /* RecipeDeatilInteractorTests.swift in Sources */,
1DC373A82CA8169F00B2E831 /* LoginUseCase.swift in Sources */,
1D5AEE812C61099900BBD5F0 /* RecipeListInteractorTests.swift in Sources */,
1D60CC402C3EB76600D08FA3 /* APIConfig.swift in Sources */,
1D5AEF3A2C64795900BBD5F0 /* SearchFeedListRepository.swift in Sources */,
Expand All @@ -852,19 +860,23 @@
1D5AEF372C64791E00BBD5F0 /* RecipeUploadResponseDTO.swift in Sources */,
1D6958D92C3D5AF7008604B3 /* RecipeDetailInteractor.swift in Sources */,
1D166D0E2C4AD54E00A50963 /* AddRecipeViewModel.swift in Sources */,
1DC373A92CA81AD400B2E831 /* LoginError.swift in Sources */,
1D39729C2C45905700495014 /* MultipartFormDataRequest.swift in Sources */,
1D5AEF332C64790200BBD5F0 /* RecipeUploadDTO.swift in Sources */,
1DF0D1A22C7B92F800E2C94C /* User.swift in Sources */,
1DC373A72CA810BB00B2E831 /* LoginRepository.swift in Sources */,
1D2C16FD2BE532B800C04508 /* HomeCafeRecipesTests.swift in Sources */,
1D6958E42C3D5EA6008604B3 /* NetworkResponseDTO.swift in Sources */,
1D5AEF302C6478D800BBD5F0 /* RecipeFetchService.swift in Sources */,
1D5AEF362C64791300BBD5F0 /* RecipePageDTO.swift in Sources */,
1D5AEF322C6478FE00BBD5F0 /* RecipePostService.swift in Sources */,
1D6958DB2C3D5C91008604B3 /* Recipe.swift in Sources */,
1D6958E02C3D5E3D008604B3 /* RecipeDetailError.swift in Sources */,
1DC373AA2CA81AD900B2E831 /* LoginService.swift in Sources */,
1D6958DA2C3D5BA4008604B3 /* FetchRecipeDetailUseCase.swift in Sources */,
1D39729E2C46C57A00495014 /* FetchRecipeDetailUseCaseTests.swift in Sources */,
1D6958E22C3D5E99008604B3 /* RecipeImageDTO.swift in Sources */,
1D93B9992CA26EB80094277F /* LoginUseCaseTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
16 changes: 16 additions & 0 deletions HomeCafeRecipes/HomeCafeRecipes/Domain/Entities/User.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,19 @@ struct User {
let nickname: String
let createdAt: Date
}

extension User {
static func dummyUser(
id: Int = 1,
profileImage: String = "",
nickname: String = "testID",
createAt: Date = Date()
) -> User {
return User(
id: id,
profileImage: profileImage,
nickname: nickname,
createdAt: createAt
)
}
}
167 changes: 167 additions & 0 deletions HomeCafeRecipes/HomeCafeRecipesTests/LoginUseCaseTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
//
// LoginUseCaseTests.swift
// HomeCafeRecipesTests
//
// Created by 김건호 on 9/24/24.
//

import XCTest

import RxSwift

@testable
import HomeCafeRecipes

final class LoginUseCaseTests: XCTestCase {
var loginRepository: LoginRepositoryMock!
var disposeBag: DisposeBag!

final class LoginRepositoryMock: LoginRepository {
var loginCallCount: Int = 0
var loginStub: Single<User> = .just(User.dummyUser())
func login(
userID: String,
password: String
) -> Single<User> {
loginCallCount += 1
return loginStub
}
}

func createUsecase() -> LoginUseCase {
let usecase = LoginUseCaseImpl(repository: loginRepository)
return usecase
}

func assertLoginError(_ actual: Error, expectedError: LoginError, file: StaticString = #file, line: UInt = #line) {
if let actualError = actual as? LoginError {
switch (actualError, expectedError) {
case (.IDIsEmpty, .IDIsEmpty),
(.passwordIsEmpty, .passwordIsEmpty):
return
case (.genericError(let actual), .genericError(let expected)):
XCTAssertEqual(actual.localizedDescription, expected.localizedDescription, file: file, line: line)
default:
XCTFail("Expected \(expectedError) but got \(actualError)", file: file, line: line)
}
} else {
XCTFail("Expected \(expectedError) but got \(actual)", file: file, line: line)
}
}

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

extension LoginUseCaseTests {
func test_execute를_호출하면_loginRepository의_login을_호출합니다(){
let usecase = createUsecase()

usecase.execute(
userID: "testID",
password: "testPassword"
)
.subscribe()
.disposed(by: disposeBag)

XCTAssertEqual(loginRepository.loginCallCount, 1)
}

func test_excute를_호출할때_ID가_비워있으면_IDIsEmptyError을_return합니다() {
let usecase = createUsecase()

usecase.execute(
userID: "",
password: "testPassword"
)
.subscribe { result in
switch result {
case .success(let loginResult):
switch loginResult {
case .failure(let error):
self.assertLoginError(error, expectedError: .IDIsEmpty)
case .success:
XCTFail("Expected failure but got success")
}
case .failure:
XCTFail("Expected success but got failure")
}
}
.disposed(by: disposeBag)
}

func test_excute를_호출할때_password가_비워있으면_passwordIsEmpty을_return합니다() {
let usecase = createUsecase()

usecase.execute(
userID: "testID",
password: ""
)
.subscribe { result in
switch result {
case .success(let loginResult):
switch loginResult {
case .failure(let error):
self.assertLoginError(error, expectedError: .passwordIsEmpty)
case .success:
XCTFail("Expected failure but got success")
}
case .failure:
XCTFail("Expected success but got failure")
}
}
.disposed(by: disposeBag)
}

func test_excute를_호출할때_성공할경우_성공한User의_정보를_return합니다() {
let usecase = createUsecase()

usecase.execute(
userID: "testId",
password: "testPassword"
).subscribe(onSuccess: { loginResult in
switch loginResult {
case .success(let user):
print(user)
XCTAssertEqual(user.nickname, "testID")
case .failure:
XCTFail("Expected success but got failure")
}
}, onFailure: { error in
XCTFail("Expected success but got failure with error: \(error.localizedDescription)")
})
.disposed(by: disposeBag)
}

func test_excute를_호출할때_잘못된자격증명으로_실패를_return합니다() {
loginRepository.loginStub = .error(NSError(
domain: "TestErrorDomain",
code: -1,
userInfo: [NSLocalizedDescriptionKey: "Invalid credentials"]
))
let usecase = createUsecase()

usecase.execute(
userID: "wrongID@test.com",
password: "wrongPassword"
).subscribe(onSuccess: { loginResult in
switch loginResult {
case .success:
XCTFail("Expected failure but got success")
case .failure(let error):
self.assertLoginError(error, expectedError: .genericError(
NSError(
domain: "TestErrorDomain",
code: -1,
userInfo: [NSLocalizedDescriptionKey: "Invalid credentials"]
)
))
}
}, onFailure: { error in
XCTFail("Expected success but got failure with error: \(error.localizedDescription)")
})
.disposed(by: disposeBag)
}
}

0 comments on commit fc78273

Please sign in to comment.