Skip to content

Commit

Permalink
Merge pull request #117 from Team-Ampersand/101-massage-feature-impl
Browse files Browse the repository at this point in the history
🔀 :: 안마의자 Feature 구현
  • Loading branch information
baekteun authored Jul 26, 2023
2 parents 2519965 + 5eb3ce4 commit 24f968b
Show file tree
Hide file tree
Showing 45 changed files with 745 additions and 80 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ public protocol RemoteMassageDataSource {
func fetchMassageInfo() async throws -> MassageInfoEntity
func applyMassage() async throws
func cancelMassage() async throws
func fetchMassageRankList() async throws -> [MassageRankEntity]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import BaseDomainInterface
import Foundation

public struct MassageRankEntity: Equatable {
public let id: Int
public let rank: Int
public let stuNum: String
public let memberName: String
public let gender: GenderType

public init(id: Int, rank: Int, stuNum: String, memberName: String, gender: GenderType) {
self.id = id
self.rank = rank
self.stuNum = stuNum
self.memberName = memberName
self.gender = gender
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
public typealias MassageRankModel = MassageRankEntity
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ public protocol MassageRepository {
func fetchMassageInfo() async throws -> MassageInfoEntity
func applyMassage() async throws
func cancelMassage() async throws
func fetchMassageRankList() async throws -> [MassageRankEntity]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
public protocol FetchMassageRankListUseCase {
func callAsFunction() async throws -> [MassageRankModel]
}
4 changes: 3 additions & 1 deletion Projects/Domain/MassageDomain/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import DependencyPlugin
let project = Project.module(
name: ModulePaths.Domain.MassageDomain.rawValue,
targets: [
.interface(module: .domain(.MassageDomain)),
.interface(module: .domain(.MassageDomain), dependencies: [
.domain(target: .BaseDomain, type: .interface)
]),
.implements(module: .domain(.MassageDomain), dependencies: [
.domain(target: .MassageDomain, type: .interface),
.domain(target: .BaseDomain)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,9 @@ public final class MassageDomainAssembly: Assembly {
container.register(CancelMassageUseCase.self) { resolver in
CancelMassageUseCaseImpl(massageRepository: resolver.resolve(MassageRepository.self)!)
}

container.register(FetchMassageRankListUseCase.self) { resolver in
FetchMassageRankListUseCaseImpl(massageRepository: resolver.resolve(MassageRepository.self)!)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import BaseDomainInterface
import MassageDomainInterface
import Foundation

struct FetchMassageRankListResponseDTO: Decodable {
let list: [MassageRankResponseDTO]

struct MassageRankResponseDTO: Decodable {
let id: Int
let rank: Int
let stuNum: String
let memberName: String
let gender: GenderType
}
}

extension FetchMassageRankListResponseDTO {
func toDomain() -> [MassageRankEntity] {
self.list
.map { $0.toDomain() }
}
}

extension FetchMassageRankListResponseDTO.MassageRankResponseDTO {
func toDomain() -> MassageRankEntity {
MassageRankEntity(id: id, rank: rank, stuNum: stuNum, memberName: memberName, gender: gender)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public enum MassageEndpoint {
case fetchMassageInfo
case applyMassage
case cancelMassage
case fetchMassageRankList
}

extension MassageEndpoint: DotoriEndpoint {
Expand All @@ -24,6 +25,9 @@ extension MassageEndpoint: DotoriEndpoint {

case .cancelMassage:
return .delete("")

case .fetchMassageRankList:
return .get("/rank")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,12 @@ final class RemoteMassageDataSourceImpl: RemoteMassageDataSource {
func cancelMassage() async throws {
try await networking.request(MassageEndpoint.cancelMassage)
}

func fetchMassageRankList() async throws -> [MassageRankEntity] {
try await networking.request(
MassageEndpoint.fetchMassageRankList,
dto: FetchMassageRankListResponseDTO.self
)
.toDomain()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,8 @@ final class MassageRepositoryImpl: MassageRepository {
func cancelMassage() async throws {
try await remoteMassageDataSource.cancelMassage()
}

func fetchMassageRankList() async throws -> [MassageRankEntity] {
try await remoteMassageDataSource.fetchMassageRankList()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import MassageDomainInterface

struct FetchMassageRankListUseCaseImpl: FetchMassageRankListUseCase {
private let massageRepository: any MassageRepository

init(massageRepository: any MassageRepository) {
self.massageRepository = massageRepository
}

func callAsFunction() async throws -> [MassageRankModel] {
try await massageRepository.fetchMassageRankList()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,11 @@ final class RemoteMassageDataSourceSpy: RemoteMassageDataSource {
func cancelMassage() async throws {
cancelMassageCallCount += 1
}

var fetchMassageRankListCallCount = 0
var fetchMassageRankListHandler: () async throws -> [MassageRankEntity] = { [] }
func fetchMassageRankList() async throws -> [MassageRankEntity] {
fetchMassageRankListCallCount += 1
return try await fetchMassageRankListHandler()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,11 @@ final class MassageRepositorySpy: MassageRepository {
func cancelMassage() async throws {
cancelMassageCallCount += 1
}

var fetchMassageRankListCallCount = 0
var fetchMassageRankListHandler: () async throws -> [MassageRankEntity] = { [] }
func fetchMassageRankList() async throws -> [MassageRankEntity] {
fetchMassageRankListCallCount += 1
return try await fetchMassageRankListHandler()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import MassageDomainInterface

final class FetchMassageRankListUseCaseSpy: FetchMassageRankListUseCase {
var fetchMassageRankListCallCount = 0
var fetchMassageRankListHandler: () async throws -> [MassageRankEntity] = { [] }
func callAsFunction() async throws -> [MassageRankModel] {
fetchMassageRankListCallCount += 1
return try await fetchMassageRankListHandler()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import MassageDomainInterface
import XCTest
@testable import MassageDomain
@testable import MassageDomainTesting

final class FetchMassageRankListUseCaseTests: XCTestCase {
var massageRepository: MassageRepositorySpy!
var sut: FetchMassageRankListUseCaseImpl!

override func setUp() {
massageRepository = .init()
sut = .init(massageRepository: massageRepository)
}

override func tearDown() {
massageRepository = nil
sut = nil
}

func testFetchMassageInfo() async throws {
XCTAssertEqual(massageRepository.fetchMassageRankListCallCount, 0)
let expected = [
MassageRankModel(id: 1, rank: 2, stuNum: "1111", memberName: "김시훈", gender: .man)
]
massageRepository.fetchMassageRankListHandler = { expected }

let actual = try await sut()

XCTAssertEqual(massageRepository.fetchMassageRankListCallCount, 1)
XCTAssertEqual(actual, expected)
}
}
20 changes: 20 additions & 0 deletions Projects/Domain/MassageDomain/Tests/MassageRepositoryTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,24 @@ final class MassageRepositoryTests: XCTestCase {

XCTAssertEqual(remoteMassageDataSource.applyMassageCallCount, 1)
}

func testCancelMassage() async throws {
XCTAssertEqual(remoteMassageDataSource.cancelMassageCallCount, 0)
try await sut.cancelMassage()

XCTAssertEqual(remoteMassageDataSource.cancelMassageCallCount, 1)
}

func testFetchMassageRankList() async throws {
XCTAssertEqual(remoteMassageDataSource.fetchMassageRankListCallCount, 0)
let expected = [
MassageRankModel(id: 1, rank: 2, stuNum: "3218", memberName: "전승원", gender: .man)
]
remoteMassageDataSource.fetchMassageRankListHandler = { expected }

let actual = try await sut.fetchMassageRankList()

XCTAssertEqual(remoteMassageDataSource.fetchMassageRankListCallCount, 1)
XCTAssertEqual(actual, expected)
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import BaseDomainInterface
import Foundation

public struct FetchSelfStudyRankSearchRequestDTO {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import BaseDomainInterface
import Foundation

public struct SelfStudyRankEntity: Equatable {
Expand Down
4 changes: 3 additions & 1 deletion Projects/Domain/SelfStudyDomain/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import DependencyPlugin
let project = Project.module(
name: ModulePaths.Domain.SelfStudyDomain.rawValue,
targets: [
.interface(module: .domain(.SelfStudyDomain)),
.interface(module: .domain(.SelfStudyDomain), dependencies: [
.domain(target: .BaseDomain, type: .interface)
]),
.implements(module: .domain(.SelfStudyDomain), dependencies: [
.domain(target: .SelfStudyDomain, type: .interface),
.domain(target: .BaseDomain)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import BaseDomainInterface
import Foundation
import SelfStudyDomainInterface

Expand Down
1 change: 0 additions & 1 deletion Projects/Feature/BaseFeature/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ let project = Project.module(
name: ModulePaths.Feature.BaseFeature.rawValue,
targets: [
.implements(module: .feature(.BaseFeature), product: .framework, dependencies: [
.SPM.MSGLayout,
.SPM.Moordinator,
.SPM.Store,
.SPM.IQKeyboardManagerSwift,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>
35 changes: 35 additions & 0 deletions Projects/Feature/MassageFeature/Demo/Sources/AppDelegate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import UIKit
import Inject
@testable import MassageFeature
@testable import MassageDomainTesting
@testable import UserDomainTesting

@main
final class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?

func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
let fetchMassageRankListUseCase = FetchMassageRankListUseCaseSpy()
fetchMassageRankListUseCase.fetchMassageRankListHandler = {
[
.init(id: 1, rank: 1, stuNum: "1234", memberName: "대충이름", gender: .man),
.init(id: 2, rank: 2, stuNum: "1235", memberName: "대이충름", gender: .man),
.init(id: 3, rank: 3, stuNum: "1236", memberName: "이름대충", gender: .woman)
]
}
let store = MassageStore(
fetchMassageRankListUseCase: fetchMassageRankListUseCase
)
let viewController = Inject.ViewControllerHost(
UINavigationController(rootViewController: MassageViewController(store: store))
)
window?.rootViewController = viewController
window?.makeKeyAndVisible()

return true
}
}
12 changes: 10 additions & 2 deletions Projects/Feature/MassageFeature/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,18 @@ let project = Project.module(
targets: [
.implements(module: .feature(.MassageFeature), dependencies: [
.feature(target: .BaseFeature),
.domain(target: .AuthDomain, type: .interface)
.domain(target: .MassageDomain, type: .interface),
.domain(target: .UserDomain, type: .interface)
]),
.tests(module: .feature(.MassageFeature), dependencies: [
.feature(target: .MassageFeature)
.feature(target: .MassageFeature),
.domain(target: .MassageDomain, type: .testing),
.domain(target: .UserDomain, type: .testing)
]),
.demo(module: .feature(.MassageFeature), dependencies: [
.feature(target: .MassageFeature),
.domain(target: .MassageDomain, type: .testing),
.domain(target: .UserDomain, type: .testing)
])
]
)
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import MassageDomainInterface
import Swinject
import UserDomainInterface

public final class MassageAssembly: Assembly {
public init() {}
public func assemble(container: Container) {
container.register(MassageFactory.self) { _ in
MassageFactoryImpl()
container.register(MassageFactory.self) { resolver in
MassageFactoryImpl(
fetchMassageRankListUseCase: resolver.resolve(FetchMassageRankListUseCase.self)!
)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
import MassageDomainInterface
import Moordinator
import UserDomainInterface

struct MassageFactoryImpl: MassageFactory {
private let fetchMassageRankListUseCase: any FetchMassageRankListUseCase

init(
fetchMassageRankListUseCase: any FetchMassageRankListUseCase
) {
self.fetchMassageRankListUseCase = fetchMassageRankListUseCase
}

func makeMoordinator() -> Moordinator {
MassageMoordinator()
let store = MassageStore(
fetchMassageRankListUseCase: fetchMassageRankListUseCase
)
let viewController = MassageViewController(store: store)
return MassageMoordinator(massageViewController: viewController)
}
}
Loading

0 comments on commit 24f968b

Please sign in to comment.