para ios core-data swift

ios - xcode para windows



¿Swift no puede probar datos básicos en pruebas de Xcode? (5)

Con Xcode 7 y @testable , ya no debería necesitar actualizar el managedObjectClassName o usar otros hacks. Esto es lo que hice para que funcione en Xcode 7.2.

  1. Configure su aplicación de host objetivo de prueba y marque "Permitir la prueba de las API de aplicaciones de host".

  1. Asegúrese de que ninguna de sus clases regulares tenga una membresía de destino que apunte al objetivo de prueba. Sólo las clases con código de prueba de unidad deben establecerse en el objetivo de prueba.

  1. Agregue la línea @testable en la parte superior de todas sus clases de prueba:

import XCTest @testable import MyApp class MyAppTests: XCTestCase { }

Si aún tiene problemas, puede intentar estos consejos adicionales: https://forums.developer.apple.com/message/28773#28949

Luché con este por un tiempo, así que espero que ayude a alguien más.

Estoy trabajando en un proyecto de iOS que utiliza datos básicos. Estoy usando swift. La pila de Core Data está bien configurada y todo parece estar bien. He creado una clase para una entidad (NSManagedObject) llamada TestEntity. La clase se ve así:

import UIKit import CoreData class TestEntity: NSManagedObject { @NSManaged var name: NSString @NSManaged var age: NSNumber }

Entonces, trato de insertar una nueva TestEntity en el código usando esta línea de código:

let te: TestEntity = NSEntityDescription.insertNewObjectForEntityForName("TestEntity", inManagedObjectContext: ctx) as TestEntity

Entonces me sale este error:

He visto algunas respuestas en el desbordamiento de pila que dicen que debo preocuparme por el nombre del módulo. Entonces busqué en los documentos: https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/WritingSwiftClassesWithObjective-CBehavior.html

Luego entré en la entidad de datos central para TestEntity y en el campo de clase ingresé myAppName.TestEntity

Cuando corro la aplicación esta línea:

let te: TestEntity = NSEntityDescription.insertNewObjectForEntityForName("TestEntity", inManagedObjectContext: ctx) as TestEntity

Todavía me da el mismo error.

¿Qué otra cosa podría estar haciendo mal?

EDIT: Entonces, pude hacer que la aplicación no se bloquee más cambiando la clase TestEntity NSManagedObject para: importar UIKit importar CoreData

@objc(TestEntity) class TestEntity: NSManagedObject { @NSManaged var name: NSString @NSManaged var age: NSNumber }

Entonces, agregué el @objc (TestEntity) en él. Esto funciona con o sin agregar el nombre de la aplicación antes del nombre de la clase TestEntity en el inspector del modelo de datos de datos centrales.

Esto funciona, pero, cuando ejecuto pruebas, esta línea aún falla :

let te: TestEntity = NSEntityDescription.insertNewObjectForEntityForName("TestEntity", inManagedObjectContext: ctx) as TestEntity

Entonces, descubrí que este es un problema para otras personas: ¿Cómo acceder a las clases de Obj-C generadas por Core Data en los objetivos de prueba?

¿Cómo podemos obtener datos básicos para trabajar en las pruebas de forma rápida . NO estoy usando un encabezado puente en el destino de la aplicación y todo funciona muy bien. Sin embargo, el objetivo de prueba todavía se bloquea.

¿Cómo puedo corregir el objetivo de la prueba para que pueda ejecutar pruebas de datos centrales?


Creo que estoy obteniendo resultados similares a ustedes. No pude hacer mis pruebas trabajando con la línea

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

Pero podría hacer que las pruebas se ejecuten con:

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

Mi entidad se parece a:

@objc(Department) class Department: NSManagedObject { @NSManaged var department_description: String ... }


El ejemplo de código de Ludovic no cubre subentidades. Entonces, cuando se configura una entidad principal en CoreData, la aplicación se bloquea.

Adaptó el código para tener en cuenta las subentidades:

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 }


Es porque el marco CoreData todavía está en Objective-C. Swift utiliza las clases de espacio de nombre, por lo que para que CoreData encuentre sus clases de Swift, debe especificar el nombre de la Clase con su espacio de nombre como este:

El problema que tendrá es que su aplicación no tiene el mismo espacio de nombres que cuando ejecuta las pruebas. <AppName>.<ClassName> vs <AppName>Tests.<ClassName>

EDITAR: Solución para ejecutar como aplicación y pruebas

Acabo de escribir un fragmento de código para resolver el problema <AppName>.<ClassName> vs <AppName>Tests.<ClassName> . La solución que uso en este momento (Xcode 6.1) es NO rellenar el campo Class en la interfaz de usuario CoreData (que se muestra arriba), y hacerlo en el código.

Este código detectará si se está ejecutando como App vs Tests, usar el nombre correcto del módulo y actualizar el 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 }()


También tuve problemas similares cuando intenté escribir casos de prueba de unidad para una aplicación de muestra ( MedicationSchedulerSwift3.0 ) escrita en Swift 3.0, además de implementar la solución provista por johnford . utilizando el siguiente código:

// 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 } }

Y lo usé así:

// 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 = "[email protected]" 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") } }

En caso de que alguien necesite más ejemplos, puede ver los casos de prueba unitaria aquí - MedicationTests