如何调整我的视图模型以实现依赖注入 swiftui(用于以后的单元测试)
Posted
技术标签:
【中文标题】如何调整我的视图模型以实现依赖注入 swiftui(用于以后的单元测试)【英文标题】:How to adapt my viewmodel to implement dependancy injection swiftui (to later unit test) 【发布时间】:2021-04-25 09:13:48 【问题描述】:目前我有多个 ViewModel,在阅读了一些其他帖子并获得了帮助之后,我被建议在我的班级中实现依赖注入,以便对我的逻辑进行单元测试。
但是我不确定如何使我的以下类适应依赖注入,我不确定是否也需要更改我的 DataManager 类。
这是我的 ViewModel 的一个示例:
class CalorieProgressViewModel: ObservableObject
@Published var calorieProgress = [CalorieProgressEntity]()
init()
//Creating the data
func addCalorieProgressData(id: UUID, calorieProgress: Double, fatProgress: Double, carbProgress: Double, proteinPogress: Double, created: Date)
CoreDataManager.shared.addCalorieProgressData(id: id, calorieProgress: calorieProgress, fatProgress: fatProgress, proteinProgress: proteinPogress, carbProgress: carbProgress, created: created) (isAdded, error) in
if let error = error
print(error)
else
print("Data has been added from addCalorieProgress VM")
如您所见,我只是使用 datamanger 类将数据添加到我的核心数据:
import Foundation
import UIKit
import CoreData
class CoreDataManager
static let shared: CoreDataManager =
let appDelegate = AppDelegate.instance!
let instance = CoreDataManager(managedObjectContext: appDelegate.persistanceContainer.viewContext)
return instance
()
var managedContext: NSManagedObjectContext
private init(managedObjectContext: NSManagedObjectContext)
managedContext = managedObjectContext
//MARK:- CalorieTracker Insert/Update/Delete
extension CoreDataManager
func addCalorieProgressData(id: UUID, calorieProgress: Double, fatProgress: Double, proteinProgress: Double, carbProgress: Double, created: Date, completionHandler: @escaping (_ succeed: Bool, _ error: Error?) -> Void)
let calorieProgressEntity = NSEntityDescription.insertNewObject(forEntityName: "CalorieProgressEntity", into: managedContext) as? CalorieProgressEntity
calorieProgressEntity?.id = id
calorieProgressEntity?.calorieProgress = calorieProgress
calorieProgressEntity?.fatProgress = fatProgress
calorieProgressEntity?.proteinProgress = proteinProgress
calorieProgressEntity?.carbProgress = carbProgress
calorieProgressEntity?.created = created
do
try managedContext.save()
print("context saved for add calorieGoal")
completionHandler(true, nil)
catch let error
completionHandler(false, error)
func fetchCalorieProgressData(completionHandler: @escaping (_ succeed: Any?, _ error: Error?) -> Void)
var goals = [CalorieProgressEntity]()
let calorieGoalRequest: NSFetchRequest<CalorieProgressEntity> = NSFetchRequest<CalorieProgressEntity>(entityName: "CalorieProgressEntity")
do
goals = try managedContext.fetch(calorieGoalRequest)
completionHandler(goals, nil)
catch let error
completionHandler(nil, error)
任何帮助将不胜感激:)
【问题讨论】:
这不是和你的previous question重复吗? 【参考方案1】:在 Swift 中有不同的依赖注入方式。您可以通过init()
完成此操作,然后在创建 ViewModel 时传递您的 CoreDataManager。
class CalorieProgressViewModel: ObservableObject
@Published var calorieProgress = [CalorieProgressEntity]()
let manager: CoreDataManager
init(manager: CoreDataManager)
self.manager = manager
//Creating the data
func addCalorieProgressData(id: UUID, calorieProgress: Double, fatProgress: Double, carbProgress: Double, proteinPogress: Double, created: Date)
//<< here don't use your singleton, instead use the manager injected via dependency injection
manager.addCalorieProgressData(id: id, calorieProgress: calorieProgress, fatProgress: fatProgress, proteinProgress: proteinPogress, carbProgress: carbProgress, created: created) (isAdded, error) in
if let error = error
然后,当您创建 ViewModel 时,您将传递 CoreDataManager 作为参数。在这里你可以使用你的 Singleton。
我建议为 CoreDataManager 创建一个协议。然后,您可以轻松地将您的 MockManager 或实际的 CoreDataManager 传递到 ViewModel 以便稍后对其进行测试。
protocol CoreDataManager
func addCalorieProgressData(id: UUID, calorieProgress: Double, fatProgress: Double, proteinProgress: Double, carbProgress: Double, created: Date, completionHandler: @escaping (_ succeed: Bool, _ error: Error?) -> Void)
class MainCoreDataManager: CoreDataManager
...
class MockCoreDataManager: CoreDataManager
... mocked here
【讨论】:
以上是关于如何调整我的视图模型以实现依赖注入 swiftui(用于以后的单元测试)的主要内容,如果未能解决你的问题,请参考以下文章
使用 Unity 进行 MVVM 依赖注入,用于分层视图模型
如何将我的 SwiftUI 视图的 @State 交换为我的视图模型 @Published 变量?
你如何在 UIKit 视图控制器和它呈现的 SwiftUI 视图之间共享数据模型?