Swift cannot test core data in Xcode tests?

前端 未结 5 625
失恋的感觉
失恋的感觉 2021-02-02 12:42

I am working on a iOS project that uses core data. I am using swift. The Core Data stack is setup right and all seems to be fine. I have created a class for an entity (NSManage

相关标签:
5条回答
  • 2021-02-02 13:34

    With Xcode 7, and @testable, you should no longer need to update the managedObjectClassName or use other hacks. Here's what I did to get it working in Xcode 7.2.

    1. Set your test target Host Application and check "Allow testing Host Applications APIs".

    1. Make sure none of your regular classes have a Target Membership pointing to the Test target. Only classes with unit test code should be set to the Test target.

    1. Add the @testable line to the top of all of your test classes:
    import XCTest
    @testable import MyApp
    
    class MyAppTests: XCTestCase {
    }
    

    If you're still having issues you may want to try these additional tips: https://forums.developer.apple.com/message/28773#28949

    I fought with this one for a while so I hope it helps someone else out.

    0 讨论(0)
  • 2021-02-02 13:35

    It's because the CoreData framework is still in Objective-C. Swift uses namespaced-classes, so for CoreData to find your swift classes you have to specify the Class name with it's namespace like this:

    enter image description here

    The problem your will have is that your App does not have the same namespace as when you are running you tests. <AppName>.<ClassName> vs <AppName>Tests.<ClassName>

    EDIT: Solution for running as App and Tests

    I just wrote a piece of code to solve the <AppName>.<ClassName> vs <AppName>Tests.<ClassName> issue. The solution I use at this time (Xcode 6.1) is to NOT fill the Class field in the CoreData UI (shown above), and to do it in code instead.

    This code will detect if you are running as App vs Tests and use the right module name and update the managedObjectClassName.

    lazy var managedObjectModel: NSManagedObjectModel = {
        // The managed object model for the application. This property is not optional...
        let modelURL = NSBundle.mainBundle().URLForResource("Streak", withExtension: "momd")!
        let managedObjectModel = NSManagedObjectModel(contentsOfURL: modelURL)!
    
        // Check if we are running as test or not
        let environment = NSProcessInfo.processInfo().environment as [String : AnyObject]
        let isTest = (environment["XCInjectBundle"] as? String)?.pathExtension == "xctest"
    
        // Create the module name
        let moduleName = (isTest) ? "StreakTests" : "Streak"
    
        // Create a new managed object model with updated entity class names
        var newEntities = [] as [NSEntityDescription]
        for (_, entity) in enumerate(managedObjectModel.entities) {
            let newEntity = entity.copy() as NSEntityDescription
            newEntity.managedObjectClassName = "\(moduleName).\(entity.name)"
            newEntities.append(newEntity)
        }
        let newManagedObjectModel = NSManagedObjectModel()
        newManagedObjectModel.entities = newEntities
    
        return newManagedObjectModel
    }()
    
    0 讨论(0)
  • 2021-02-02 13:36

    I think I'm getting similar results to you. I was unable to get my tests working with the line

    var newDept = NSEntityDescription.insertNewObjectForEntityForName("Department", inManagedObjectContext: moc) as Department
    

    But I could get the tests running with :

    let entity = NSEntityDescription.entityForName("Department", inManagedObjectContext: moc)
    let department = Department(entity: entity!, insertIntoManagedObjectContext: moc)
    

    My Entity looks like :

    @objc(Department)
    class Department: NSManagedObject {
    
        @NSManaged var department_description: String
        ...
    }
    
    0 讨论(0)
  • 2021-02-02 13:36

    The code example from Ludovic does not cover subentities. So when setting a parent entity in CoreData, the app crashes.

    Adapted the code to take subentities into account:

    private func createManagedObjectModel() {
    
        // Get module name
        var moduleName: String = "ModuleName"
        let environment = NSProcessInfo.processInfo().environment as! [String : AnyObject]
        let isTest = (environment["XCInjectBundle"] as? String)?.pathExtension == "xctest"
        if isTest { moduleName = "ModuleNameTests" }
    
        // Get model
        let modelURL = NSBundle.mainBundle().URLForResource(self.storeName, withExtension: "momd")!
        let model = NSManagedObjectModel(contentsOfURL: modelURL)!
    
        // Create entity copies
        var newEntities = [NSEntityDescription]()
        for (_, entity) in enumerate(model.entities) {
            let newEntity = entity.copy() as! NSEntityDescription
            newEntity.managedObjectClassName = "\(moduleName).\(entity.managedObjectClassName)"
            newEntities.append(newEntity)
        }
    
        // Set correct subentities
        for (_, entity) in enumerate(newEntities) {
            var newSubEntities = [NSEntityDescription]()
            for subEntity in entity.subentities! {
                for (_, entity) in enumerate(newEntities) {
                    if subEntity.name == entity.name {
                        newSubEntities.append(entity)
                    }
                }
            }
            entity.subentities = newSubEntities
        }
    
        // Set model
        self.managedObjectModel = NSManagedObjectModel()
        self.managedObjectModel.entities = newEntities
    }
    
    0 讨论(0)
  • 2021-02-02 13:37

    I also faced similar issue when I tried to write unit test cases for a sample app (MedicationSchedulerSwift3.0) written in Swift 3.0, apart from implementing solution provided by johnford I created a category on XCTestCase to setup an NSManagedObjectContext with in-memory store by using below code:

    //  XCTestCase+CoreDataHelper.swift
    
    import CoreData
    import XCTest
    @testable import Medication
    
    extension XCTestCase {
        func setUpInMemoryManagedObjectContext() -> NSManagedObjectContext {
            let managedObjectModel = NSManagedObjectModel.mergedModel(from: [Bundle.main])!
    
            let persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: managedObjectModel)
    
            do {
                try persistentStoreCoordinator.addPersistentStore(ofType: NSInMemoryStoreType, configurationName: nil, at: nil, options: nil)
            } catch {
                print("Adding in-memory persistent store failed")
            }
    
            let managedObjectContext = NSManagedObjectContext(concurrencyType:.privateQueueConcurrencyType)
            managedObjectContext.persistentStoreCoordinator = persistentStoreCoordinator
    
            return managedObjectContext
        }
    }
    

    And used it like this:

    //  NurseTests.swift
    
    import XCTest
    import CoreData
    @testable import Medication
    
    class NurseTests: XCTestCase {
        var managedObjectContext: NSManagedObjectContext?
    
        //MARK: Overriden methods
        override func setUp() {
            super.setUp()
            // Put setup code here. This method is called before the invocation of each test method in the class.
            if managedObjectContext == nil {
                managedObjectContext = setUpInMemoryManagedObjectContext()
            }
        }
    
    //MARK:- Testing functions defined in Nurse.swift
        // testing : class func addNurse(withEmail email: String, password: String, inManagedObjectContext managedObjectContext: NSManagedObjectContext) -> NSError?
        func testAddNurse() {
            let nurseEmail = "clara@gmail.com"
            let nursePassword = "clara"
    
            let error = Nurse.addNurse(withEmail: nurseEmail, password: nursePassword, inManagedObjectContext: managedObjectContext!)
            XCTAssertNil(error, "There should not be any error while adding a nurse")
        }
    }
    

    In case if someone needs more examples they can look at unit test cases over here - MedicationTests

    0 讨论(0)
提交回复
热议问题