2011-04-14 9 views
16

He creado un proyecto con un modelo de datos básicos. La aplicación busca el archivo de modelo (.momd) y funciona perfectamente.Unidad de prueba no puede encontrar el archivo de modelo de Datos básicos

Por desgracia, la prueba de la unidad sigue regresando nulo:

NSURL *dataModelURL = [[NSBundle mainBundle] URLForResource:@"myDataModel" withExtension:@"momd"]; 

puedo ver la carpeta y el archivo myDataModel.xdatamodeld tanto en el objetivo principal y el directorio de fuentes de compilación del objetivo de las pruebas unitarias - pero eso no parece ser suficiente. ¿Qué más me estoy perdiendo en el objetivo de la prueba de unidad?

Gracias, -Luther

+1

Gracias por mencionar que debe agregar su modelo de datos al listado de * Fuentes compiladas * del proyecto de prueba. Eso es lo que me estaba perdiendo. – d512

Respuesta

32

Desafortunadamente, un objetivo de prueba de unidades no utiliza el paquete principal de la aplicación, pero crea un paquete UnitTest especial. Por lo tanto, si necesita utilizar recursos agrupados (como un modelo de Datos centrales) dentro de sus pruebas, debe solucionar ese problema.

La solución más simple y más flexible sería utilizar el método bundleForClass: de NSBundle dentro del código de prueba. El parámetro para ese método puede simplemente darse por [self class] dentro de sus pruebas. De esta forma, puede reutilizar este código sin tener que ajustar los identificadores de paquetes en múltiples proyectos.

Ejemplo:

- (void)testBundleLocation 
{ 
    NSBundle *bundle = [NSBundle bundleForClass:[self class]]; 
    NSURL *url = [bundle URLForResource:@"myDataModel" withExtension:@"momd"]; 
    ... 
} 
+2

¡Finalmente! ¡La respuesta correcta!:) –

+1

@LutherBaker Si bien esta parece ser la mejor solución entre todas las soluciones por ahora, no creo que esta sea la * respuesta * correcta. Las pruebas unitarias no deberían requerir una para modificar la fuente de la aplicación. Así que mientras accedes al paquete en el caso de prueba, hacer un 'paqueteForClass:' parece estar bien, pero si tienes algún código de aplicación que hace un '[NSBundle mainBundle]' (un modismo suficientemente común, y no desaprobado AFAIK) , esa clase no puede ser probada en una unidad. – Manav

+0

Muchas gracias. ¡Perdió dos días sólidos tratando de resolver esto! – user798719

6

La respuesta tiene que ver con el paquete. Un objetivo de prueba de unidad no usa el paquete 'principal'. Crea su propio paquete que, en mi caso, dejó de forma predeterminada 'com.yourcompany.UnitTest' - directamente del [Target] -info.plist.

La solución corregido tendrá el aspecto siguiente:

NSBundle *bundle = [NSBundle bundleWithIdentifier:@"com.yourcompany.UnitTests"]; 
NSURL *url = [bundle URLForResource:@"myDataModel" withExtension:@"momd"]; 

Gracias

+0

¡Gracias, solo la información que necesitaba! – theory

+0

Esta respuesta también es buena, ya que proporciona toda la información que necesita para comprender y solucionar el problema. –

2

Este método hará que su paquete de cualquier objetivo. Sin embargo, para cada objetivo que agregue, debe agregar manualmente el identificador del conjunto plist a la matriz identifiers, porque no hay forma de obtenerlo mediante programación. La ventaja es que puede usar el mismo código para probar o ejecutar la aplicación.

+(NSBundle*) getBundle 
{ 
    NSBundle *bundle = nil; 

    // try your manually set bundles 
    NSArray *identifiers = [NSArray arrayWithObjects: @"com.your.application", 
                 @"com.your.test", 
                 nil]; 
    for(NSString *bundleId in identifiers) { 
     bundle = [NSBundle bundleWithIdentifier:bundleId]; 
     if (bundle!=nil) break; 
    } 

    // try the main bundle 
    if (bundle==nil) bundle = [NSBundle mainBundle]; 

    // abort 
    assert(bundle!=nil && "Missing bundle. Check the Bundle identifier on 
      the plist of this target vs the identifiers array in this class."); 

    return bundle; 
} 
3

tenido un problema similar, lo solucioné utilizando el marco OCMock, por lo que no necesita cambiar el código de la aplicación

@interface TestCase() 
    @property (nonatomic, strong) id bundleMock; 
@end 

@implementation TestCase 

- (void)setUp 
{ 
    self.bundleMock = [OCMockObject mockForClass:[NSBundle class]]; 
    [[[self.bundleMock stub] andReturn:[NSBundle bundleForClass:[self class]]] mainBundle]; 
    [super setUp]; 
} 

- (void)tearDown 
{ 
    [self.bundleMock stopMocking]; 
    [super tearDown]; 
} 
0

Mi problema era de hecho el paquete equivocado ! Como estaba tratando de usar una base de datos desde/dentro de un Framework I 'simplemente' tiene que cargar el db del correspondiente Bundle!

Aquí hay un código en Swift4 usando MagicalRecord:

// Load the bundle 
let frameworkBundle = Bundle(for: AClassFromTheFramework.self) 
let managedObjectModel = NSManagedObjectModel.mergedModel(from: [frameworkBundle]) 
// Use the new `managedObjectModel` by default 
MagicalRecord.setShouldAutoCreateManagedObjectModel(false) 
NSManagedObjectModel.mr_setDefaultManagedObjectModel(managedObjectModel) 
// Load the database 
MagicalRecord.setupCoreDataStack(withAutoMigratingSqliteStoreNamed: "db.sqlite") 

y listo!

Cuestiones relacionadas