使用CoreData进行单元测试DI无法正常工作

时间:2017-09-21 22:52:40

标签: ios swift unit-testing core-data dependency-injection

我尝试编写测试以确保我的视图模型的模型属性在设置时从模型调用我的fetchPlan方法然后设置我的计划'我的视图模型中的属性。它似乎是在设置属性,但缺少值...

这是我的观点模型

final class PlanProgressViewModel: PlanProgressViewModelView {

// MARK: - Properties
fileprivate var plan: PlanData?

// MARK: - PlanProgressViewModelView
weak var viewDelegate: PlanProgressViewModelViewDelegate?

var model: PlanModel? {
    didSet {
        model?.fetchCurrentPlan(completionHandler: { (plan) in
            guard let plan = plan else {return}
            self.plan = plan
        })
    }
}
// Testing this fails...
var planName: String! {
    guard let plan = plan else {return "No plan"}
    return plan.name
}

var planProgressionString: String! {
    return "\(Int(round(self.progress * 100)))%"
}

var progress: Double! {
    guard let plan = plan, let workouts = plan.workouts, let completedWorkouts = plan.completedWorkouts else {return 0}
    return Double(Int(completedWorkouts) / workouts.count)
}
}

这是我的测试套件,我使用模拟器从模型中返回硬编码数据。

var sut: PlanProgressViewModel!
var model: MockPlanModel!
var moc: NSManagedObjectContext!

override func setUp() {
    super.setUp()
    moc = setupInMemoryMOC()

    let mockModel = MockPlanModel(moc: moc)
    model = mockModel

    let viewModel = PlanProgressViewModel()
    viewModel.model = model
    sut = viewModel
}

override func tearDown() {
    moc = nil
    model = nil
    sut = nil
    super.tearDown()
}
// This passes
func testModelFetchesCurrentPlanOnce() {
    XCTAssertEqual(model.fetchPlanWasCalled, 1)
}

// This is failing
func testPlanName() {
    XCTAssertEqual(sut.planName, "Test plan")
}

这是我设置内存持久存储的方法......

public func setupInMemoryMOC() -> NSManagedObjectContext {
let mom = NSManagedObjectModel.mergedModel(from: [Bundle.main])
let psc = NSPersistentStoreCoordinator(managedObjectModel: mom!)

do {
    try psc.addPersistentStore(ofType: NSInMemoryStoreType, configurationName: nil, at: nil, options: nil)
} catch {
    fatalError()
}

let moc = NSManagedObjectContext.init(concurrencyType: .mainQueueConcurrencyType)
moc.persistentStoreCoordinator = psc

return moc }

这是我对模型的模拟,它返回硬编码数据......

public class MockPlanModel: MWPlanModel {
var fetchPlanWasCalled = 0

override public func fetchCurrentPlan(completionHandler: @escaping (_ plan: PlanData?) -> ()) {
    fetchPlanWasCalled += 1

    let moc = setupInMemoryMOC()
    let plan = createTestPlan(moc: moc)

    completionHandler(plan)
}}

这是我创建模型对象的辅助方法,(PlanData是我的'计划' NSManaged对象继承的协议)。

public func createTestPlan(moc: NSManagedObjectContext) -> PlanData {
let plan: Plan = Plan(context: moc)
plan.name = "Test plan"
plan.completedWorkouts = 5
plan.currentPlan = true

for _ in 0..<5 {
    plan.mutableOrderedSetValue(forKeyPath: #keyPath(Plan.workouts)).add(createTestCompletedWorkout(moc: moc))
}

return plan }

计划名称应为&#34;测试计划&#34;因为这是我设置硬编码值但它失败并返回一个空字符串而不是... enter image description here

真的坚持这一点,我是一个相当新的测试,所以我感谢任何帮助。感谢

1 个答案:

答案 0 :(得分:0)

@MartinR评论指出:

  

左侧"Test plan"上的非可选项会自动提升为可选项。因为sut.planName是可选的。更多检查Swift comparing Strings optionals vs non-optional

您需要解开sut.planName

if let planName = sut.planName{
   XCTAssertEqual(planName, "Test plan")
}

或者尝试这种方式:

 XCTAssertEqual((sut.planName ?? ""), "Test plan")

注意:如果您遇到同样的问题,请更新您的Xcode

// Using Apple XCTest (Xcode 7.3.1), this produces the output:
// "XCTAssertEqual failed: ("Optional(1)") is not equal to ("Optional(2)") - "
XCTAssertEqual(1, 2)

更多详情:Here Bug reported