Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] 화이트 보드 오브젝트/도구 관리 유즈케이스 추가 #86

Merged
merged 11 commits into from
Nov 16, 2024
Merged
37 changes: 37 additions & 0 deletions Domain/Domain.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@
0080E91A2CE4B0880095B958 /* DrawObjectUseCaseInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0080E9182CE4B0880095B958 /* DrawObjectUseCaseInterface.swift */; };
0080E9502CE4D8700095B958 /* Domain.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B7C6E262CDB6A010024704A /* Domain.framework */; platformFilter = ios; };
0080E9582CE4D8760095B958 /* DrawObjectUseCaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0080E9562CE4D8760095B958 /* DrawObjectUseCaseTests.swift */; };
00D2DD842CE8864B0089F0BA /* ManageWhiteboardObjectUseCaseInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00D2DD832CE8864B0089F0BA /* ManageWhiteboardObjectUseCaseInterface.swift */; };
00D2DD862CE887540089F0BA /* ManageWhiteboardObjectUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00D2DD852CE887540089F0BA /* ManageWhiteboardObjectUseCase.swift */; };
00D2DD882CE88BD80089F0BA /* ManageWhiteboardToolUseCaseInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00D2DD872CE88BD80089F0BA /* ManageWhiteboardToolUseCaseInterface.swift */; };
00D2DD8F2CE88C640089F0BA /* WhiteboardTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00D2DD8E2CE88C640089F0BA /* WhiteboardTool.swift */; };
00D2DD912CE88D260089F0BA /* ManageWhiteboardToolUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00D2DD902CE88D260089F0BA /* ManageWhiteboardToolUseCase.swift */; };
00D2DD932CE88EC70089F0BA /* ManageWhiteboardToolUseCaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00D2DD922CE88EC70089F0BA /* ManageWhiteboardToolUseCaseTests.swift */; };
00D2DD952CE88EDA0089F0BA /* ManageWhiteboardObjectsUseCaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00D2DD942CE88EDA0089F0BA /* ManageWhiteboardObjectsUseCaseTests.swift */; };
5B6542482CE44631000168AD /* WhiteboardUseCaseInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6542472CE44631000168AD /* WhiteboardUseCaseInterface.swift */; };
5B7C6EB02CDB6C040024704A /* AirplaINFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B7C6EAF2CDB6C040024704A /* AirplaINFoundation.framework */; };
5B7C6EB12CDB6C040024704A /* AirplaINFoundation.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5B7C6EAF2CDB6C040024704A /* AirplaINFoundation.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
Expand Down Expand Up @@ -62,6 +69,13 @@
0080E9182CE4B0880095B958 /* DrawObjectUseCaseInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DrawObjectUseCaseInterface.swift; sourceTree = "<group>"; };
0080E94C2CE4D8700095B958 /* DomainTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DomainTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
0080E9562CE4D8760095B958 /* DrawObjectUseCaseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DrawObjectUseCaseTests.swift; sourceTree = "<group>"; };
00D2DD832CE8864B0089F0BA /* ManageWhiteboardObjectUseCaseInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManageWhiteboardObjectUseCaseInterface.swift; sourceTree = "<group>"; };
00D2DD852CE887540089F0BA /* ManageWhiteboardObjectUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManageWhiteboardObjectUseCase.swift; sourceTree = "<group>"; };
00D2DD872CE88BD80089F0BA /* ManageWhiteboardToolUseCaseInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManageWhiteboardToolUseCaseInterface.swift; sourceTree = "<group>"; };
00D2DD8E2CE88C640089F0BA /* WhiteboardTool.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WhiteboardTool.swift; path = Domain/Sources/Interface/UseCase/WhiteboardTool.swift; sourceTree = SOURCE_ROOT; };
00D2DD902CE88D260089F0BA /* ManageWhiteboardToolUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManageWhiteboardToolUseCase.swift; sourceTree = "<group>"; };
00D2DD922CE88EC70089F0BA /* ManageWhiteboardToolUseCaseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManageWhiteboardToolUseCaseTests.swift; sourceTree = "<group>"; };
00D2DD942CE88EDA0089F0BA /* ManageWhiteboardObjectsUseCaseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManageWhiteboardObjectsUseCaseTests.swift; sourceTree = "<group>"; };
5B6542472CE44631000168AD /* WhiteboardUseCaseInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WhiteboardUseCaseInterface.swift; sourceTree = "<group>"; };
5B7C6E262CDB6A010024704A /* Domain.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Domain.framework; sourceTree = BUILT_PRODUCTS_DIR; };
5B7C6EAF2CDB6C040024704A /* AirplaINFoundation.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AirplaINFoundation.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -105,13 +119,16 @@
A8E97C062CE5E45500B28063 /* WhiteboardObjectSendUseCase.swift */,
A85260222CE343B20089DA5E /* ProfileUseCase.swift */,
5BDFD9392CE2EE3100DA4F5B /* WhiteboardUseCase.swift */,
00D2DD852CE887540089F0BA /* ManageWhiteboardObjectUseCase.swift */,
00D2DD902CE88D260089F0BA /* ManageWhiteboardToolUseCase.swift */,
);
path = UseCase;
sourceTree = "<group>";
};
0080E8592CE19EBD0095B958 /* Sources */ = {
isa = PBXGroup;
children = (
00D2DD8A2CE88C380089F0BA /* Model */,
0080E8CB2CE4461F0095B958 /* Interface */,
0080E8B92CE2ECB50095B958 /* Entity */,
00683D702CE3A72F000D28E4 /* UseCase */,
Expand Down Expand Up @@ -166,6 +183,8 @@
A8E97C042CE5E3AB00B28063 /* ProfileUseCaseInterface.swift */,
6FBC909A2CE5A52B000FEB5A /* WhiteObjectSendUseCaseInterface.swift */,
5B6542472CE44631000168AD /* WhiteboardUseCaseInterface.swift */,
00D2DD832CE8864B0089F0BA /* ManageWhiteboardObjectUseCaseInterface.swift */,
00D2DD872CE88BD80089F0BA /* ManageWhiteboardToolUseCaseInterface.swift */,
);
path = UseCase;
sourceTree = "<group>";
Expand All @@ -174,10 +193,21 @@
isa = PBXGroup;
children = (
0080E9562CE4D8760095B958 /* DrawObjectUseCaseTests.swift */,
00D2DD922CE88EC70089F0BA /* ManageWhiteboardToolUseCaseTests.swift */,
00D2DD942CE88EDA0089F0BA /* ManageWhiteboardObjectsUseCaseTests.swift */,
);
path = DomainTests;
sourceTree = "<group>";
};
00D2DD8A2CE88C380089F0BA /* Model */ = {
isa = PBXGroup;
children = (
00D2DD8E2CE88C640089F0BA /* WhiteboardTool.swift */,
);
name = Model;
path = ../../../Presentation/Presentation/Sources/Whiteboard/Model;
sourceTree = "<group>";
};
5B7C6E1C2CDB6A010024704A = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -344,7 +374,9 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
00D2DD952CE88EDA0089F0BA /* ManageWhiteboardObjectsUseCaseTests.swift in Sources */,
0080E9582CE4D8760095B958 /* DrawObjectUseCaseTests.swift in Sources */,
00D2DD932CE88EC70089F0BA /* ManageWhiteboardToolUseCaseTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -362,12 +394,17 @@
5BDFD9342CE1F7DB00DA4F5B /* Whiteboard.swift in Sources */,
5BDFD9372CE2E6BC00DA4F5B /* WhiteboardRepositoryInterface.swift in Sources */,
5B6542482CE44631000168AD /* WhiteboardUseCaseInterface.swift in Sources */,
00D2DD842CE8864B0089F0BA /* ManageWhiteboardObjectUseCaseInterface.swift in Sources */,
00D2DD882CE88BD80089F0BA /* ManageWhiteboardToolUseCaseInterface.swift in Sources */,
0080E8CE2CE4463B0095B958 /* WhiteboardObjectRepositoryInterface.swift in Sources */,
0080E8BB2CE2ECD80095B958 /* WhiteboardObject.swift in Sources */,
6FBC909B2CE5A6AE000FEB5A /* WhiteObjectSendUseCaseInterface.swift in Sources */,
6F21477B2CE4CEAE00B55E2C /* TextObject.swift in Sources */,
00683D722CE3A74A000D28E4 /* DrawObjectUseCase.swift in Sources */,
00D2DD8F2CE88C640089F0BA /* WhiteboardTool.swift in Sources */,
0080E91A2CE4B0880095B958 /* DrawObjectUseCaseInterface.swift in Sources */,
00D2DD912CE88D260089F0BA /* ManageWhiteboardToolUseCase.swift in Sources */,
00D2DD862CE887540089F0BA /* ManageWhiteboardObjectUseCase.swift in Sources */,
00683D692CE37F2F000D28E4 /* DrawingObject.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,32 @@
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5B25A3E32CDB68E500CB7B34"
BuildableName = "AirplaIN.app"
BlueprintName = "AirplaIN"
ReferencedContainer = "container:../AirplaIN/AirplaIN.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5B25A3E32CDB68E500CB7B34"
BuildableName = "AirplaIN.app"
BlueprintName = "AirplaIN"
ReferencedContainer = "container:../AirplaIN/AirplaIN.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
Expand Down
6 changes: 5 additions & 1 deletion Domain/Domain/Sources/Entity/WhiteboardObject.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
//
import Foundation

public class WhiteboardObject {
public class WhiteboardObject: Equatable {
public let id: UUID
public var position: CGPoint
public var size: CGSize
Expand All @@ -20,4 +20,8 @@ public class WhiteboardObject {
self.position = position
self.size = size
}

public static func == (lhs: WhiteboardObject, rhs: WhiteboardObject) -> Bool {
return lhs.id == rhs.id
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//
// ManageWhiteboardObjectUseCaseInterface.swift
// Domain
//
// Created by 이동현 on 11/16/24.
//

import Combine

public protocol ManageWhiteboardObjectUseCaseInterface {
/// 화이트보드 객체가 추가될 때 이벤트를 방출합니다.
var addedWhiteboardObject: AnyPublisher<WhiteboardObject, Never> { get }

/// 화이트보드 객체가 수정될 때 이벤트를 방출합니다.
var updatedWhiteboardObject: AnyPublisher<WhiteboardObject, Never> { get }

/// 화이트보드 객체가 제거될 때 이벤트를 방출합니다.
var removedWhiteboardObject: AnyPublisher<WhiteboardObject, Never> { get }

/// 현재 존재하는 모든 화이트보드 객체들을 가져옵니다.
/// - Returns: 화이트보드 위에 존재하는 화이트보드 객체들
func fetchObjects() -> [WhiteboardObject]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

구현체와 주석을 같이 본 바로는 본인이 갖고 있는 화이트보드 오브젝트들을 가져오는 메소드로 보이는데요,
혹시 언제 어떻게 사용될지 알 수 있을까요?

어떻게 사용될지, 필요한지 예상이 되지 않아서 코멘트 남깁니다 :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

앗 이 부분 사용될 일이 없을것 같습니다!! 삭제하도록 하겠습니다!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

692d764 에서 반영하였습니다.


/// 화이트보드 객체를 추가하는 메서드
/// - Parameter whiteboardObject: 추가할 화이트보드 객체
/// - Returns: 추가 성공 여부
func addObject(whiteboardObject: WhiteboardObject) -> Bool

/// 화이트보드 객체를 수정하는 메서드
/// - Parameter whiteboardObject: 수정할 화이트보드 객체
/// - Returns: 추가 성공 여부
func updateObject(whiteboardObject: WhiteboardObject) -> Bool

/// 화이트보드를 제거하는 메서드
/// - Returns: 추가 성공 여부
func removeObject(whiteboardObject: WhiteboardObject) -> Bool
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// ManageWhiteboardToolUseCaseInterface.swift
// Domain
//
// Created by 이동현 on 11/16/24.
//

import Combine

public protocol ManageWhiteboardToolUseCaseInterface {
/// 화이트보드 도구 선택/선택 해제 시 이벤트를 방출합니다.
var currentToolPublisher: AnyPublisher<WhiteboardTool?, Never> { get }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ManageWhiteboardObjectUseCaseInterface 와 공통으로 코멘트 남깁니다!

목요일에 나눴던 얘기와 이어서 진행이 될 것 같은데요,

메소드의 반환 값으로 Publisher를 반환하는 방법이 생각나는데, 해당 방법 말고 따로 인터페이스에 추가해주신 이유가 있을까요??

Copy link
Collaborator Author

@taipaise taipaise Nov 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

하나의 퍼블리셔를 단발성으로 사용하지 않고 지속적으로 사용하게 되지 않을까 하여 위와 같이 구현했습니다.
또한 메서드의 반환 값으로 Publisher를 반환하게 되면, 해당 퍼블리셔를 매번 새로 구독해야할 것 같습니다!
이렇게 되면 Cancellable에 실제로는 사용하지 않는 구독이 점점 많이 쌓이게 될 것이라 생각합니다. (Tool을 바꿀 때마다 새로 구독해야 함) 이는 곧 메모리 누수로 이어지지 않을까 합니다!! 혹시라도 제가 잘못 알고 있는게 있다면 알려주시면 감사하겠습니다!!!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

설명 감사합니다!!
많은 고민이 담겨있는 코드였군요!!
역시..구욷
좋은 방법이라고 생각합니다 :)


/// 현재 사용중인 화이트보드 도구를 반환합니다.
/// - Returns: 사용중인 화이트보드 도구
func currentTool() -> WhiteboardTool?

/// 화이트보드 도구를 선택합니다.
/// - Parameter tool: 선택할 화이트보드 도구
func selectTool(tool: WhiteboardTool)

/// 화이트보드 도구 사용을 완료합니다.
func finishUsingTool()
}
15 changes: 15 additions & 0 deletions Domain/Domain/Sources/Interface/UseCase/WhiteboardTool.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// WhiteboardTool.swift
// Domain
//
// Created by 이동현 on 11/16/24.
//

@frozen
public enum WhiteboardTool: CaseIterable {
case drawing
case text
case photo
case game
case chat
}
2 changes: 1 addition & 1 deletion Domain/Domain/Sources/UseCase/DrawObjectUseCase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public final class DrawObjectUseCase: DrawObjectUseCaseInterface {
public private(set) var points: [CGPoint]
public private(set) var origin: CGPoint?

public init(repository: WhiteboardObjectRepositoryInterface) {
public init() {
points = []
}

Expand Down
56 changes: 56 additions & 0 deletions Domain/Domain/Sources/UseCase/ManageWhiteboardObjectUseCase.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//
// ManageWhiteboardObjectUseCase.swift
// Domain
//
// Created by 이동현 on 11/16/24.
//

import Combine

public final class ManageWhiteboardObjectUseCase: ManageWhiteboardObjectUseCaseInterface {
public var addedWhiteboardObject: AnyPublisher<WhiteboardObject, Never>
public var updatedWhiteboardObject: AnyPublisher<WhiteboardObject, Never>
public var removedWhiteboardObject: AnyPublisher<WhiteboardObject, Never>
private var whiteboardObjects: [WhiteboardObject]

private let addedWhiteboardSubject: PassthroughSubject<WhiteboardObject, Never>
private let updatedWhiteboardSubject: PassthroughSubject<WhiteboardObject, Never>
private let removedWhiteboardSubject: PassthroughSubject<WhiteboardObject, Never>

public init() {
addedWhiteboardSubject = PassthroughSubject<WhiteboardObject, Never>()
updatedWhiteboardSubject = PassthroughSubject<WhiteboardObject, Never>()
removedWhiteboardSubject = PassthroughSubject<WhiteboardObject, Never>()

whiteboardObjects = []

addedWhiteboardObject = addedWhiteboardSubject.eraseToAnyPublisher()
updatedWhiteboardObject = updatedWhiteboardSubject.eraseToAnyPublisher()
removedWhiteboardObject = removedWhiteboardSubject.eraseToAnyPublisher()
}

public func fetchObjects() -> [WhiteboardObject] {
return whiteboardObjects
}

public func addObject(whiteboardObject: WhiteboardObject) -> Bool {
guard !whiteboardObjects.contains(whiteboardObject) else { return false }
whiteboardObjects.append(whiteboardObject)
addedWhiteboardSubject.send(whiteboardObject)
return true
}

public func updateObject(whiteboardObject: WhiteboardObject) -> Bool {
guard let index = whiteboardObjects.firstIndex(where: { $0 == whiteboardObject }) else { return false }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

업데이트 한 whiteboardObject를 비교해야하기 때문에,
WhiteboardObject 의 equatable메소드에서 id만 비교한 부분이 인상 깊어요!

whiteboardObjects[index] = whiteboardObject
updatedWhiteboardSubject.send(whiteboardObject)
return true
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updateObject에는 이후에 추가적인 로직이 작성된다고 이해해도 될까요?
Result type을 활용하는 것 대신 Bool을 반환하고, subject를 통해 send해주는 방식을 선택한 이유도 궁금합니다!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵 맞습니다! 아직 해당 에픽까지 진행하지 않아 뼈대만 구현한 상태입니다.

Result 타입이 아닌 Bool을 반환한 이유는
1. 아직 error 케이스를 정의하지 않았고 (실패 정책이 없어서)
2. 성공 실패만 따지면 되지 않을까?
하여 Result 타입 대신 Bool을 return 하도록 했습니다.

subject를 send하는 방식은 유즈케이스를 사용하는 쪽에게 '업데이트 된 객체' 라는 이벤트를 발행하기 위함입니다!


public func removeObject(whiteboardObject: WhiteboardObject) -> Bool {
guard whiteboardObjects.contains(whiteboardObject) else { return false }
whiteboardObjects.removeAll { $0 == whiteboardObject }
removedWhiteboardSubject.send(whiteboardObject)
return true
}
}
30 changes: 30 additions & 0 deletions Domain/Domain/Sources/UseCase/ManageWhiteboardToolUseCase.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// ManageWhiteboardToolUseCase.swift
// Domain
//
// Created by 이동현 on 11/16/24.
//

import Combine

public final class ManageWhiteboardToolUseCase: ManageWhiteboardToolUseCaseInterface {
public var currentToolPublisher: AnyPublisher<WhiteboardTool?, Never>
private let currentToolSubject: CurrentValueSubject<WhiteboardTool?, Never>

public init() {
currentToolSubject = CurrentValueSubject<WhiteboardTool?, Never>(nil)
currentToolPublisher = currentToolSubject.eraseToAnyPublisher()
}

public func currentTool() -> WhiteboardTool? {
return currentToolSubject.value
}

public func selectTool(tool: WhiteboardTool) {
currentToolSubject.send(tool)
}

public func finishUsingTool() {
currentToolSubject.send(nil)
}
}
5 changes: 1 addition & 4 deletions Domain/DomainTests/DrawObjectUseCaseTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,12 @@ import XCTest

final class DrawObjectUseCaseTests: XCTestCase {
var useCase: DrawObjectUseCaseInterface!
var mockRepository: WhiteboardObjectRepositoryInterface!

override func setUpWithError() throws {
mockRepository = MockWhiteboardObjectRepository()
useCase = DrawObjectUseCase(repository: mockRepository)
useCase = DrawObjectUseCase()
}

override func tearDownWithError() throws {
mockRepository = nil
useCase = nil
}

Expand Down
Loading