2009-12-09 8 views
18

Estoy usando OCMock para simular algunos objetos de Datos centrales. Anteriormente, había las propiedades implementado con Objective-C 1.0 estilo descriptores de acceso explícitas:Problema OCMock con propiedades dinámicas de Datos centrales

// -- Old Core Data object header 
@interface MyItem : NSManagedObject {} 
- (NSString *) PDFName; 
- (void) setPDFName:(NSString *)pdfName; 
@end 

// -- implementation provides generated implementations for both getter and setter 

Ahora me he movido el código de Objective-C 2.0 y quieren tomar ventaja de la nueva sintaxis @property, y la dinámica implementaciones de métodos -generated para los objetos de datos: Core

// -- New Core Data object header 
@interface MyItem : NSManagedObject {} 
@property (nonatomic, retain) NSString *PDFName; 
@end 

// -- Core Data object implementation 
@implementation MyItem 
@dynamic PDFName; 
@end 

sin embargo, ahora cuando se crea un elemento de simulacro, no parece para manejar las propiedades dinámicas:

// -- creating the mock item 
id mockItem = [OCMockObject mockForClass:[MyItem class]]; 
[[[mockItem stub] andReturn:@"fakepath.pdf"] PDFName]; // <-- throws exception here 

T El error se ve así:

Test Case '-[MyItem_Test testMyItem]' started. 
2009-12-09 11:47:39.044 MyApp[82120:903] NSExceptionHandler has recorded the following exception: 
NSInvalidArgumentException -- *** -[NSProxy doesNotRecognizeSelector:PDFName] called! 
Stack trace: 0x916a4d24 0x92115509 0x97879138 0x978790aa 0x9090cb09 0x97820db6 0x97820982 0x10d97ff 0x10d9834 0x9782005d 0x9781ffc8 0x20103d66 0x20103e8c 0x20103642 0x20107024 0x20103642 0x20107024 0x20103642 0x20105bfe 0x907fead9 0x977e4edb 0x977e2864 0x977e2691 0x90877ad9 0xbf565 0xbf154 0x107715 0x1076c3 0x1082e4 0x89d9b 0x8a1e5 0x894eb 0x907e81c7 0x978019a9 0x978013da 0x907dd094 0x907ea471 0x9478c7bd 0x9478c1b9 0x94784535 0x5ede 0x326a 0x5 
Unknown.m:0: error: -[MyItem_Test testMyItem] : *** -[NSProxy doesNotRecognizeSelector:PDFName] called! 

Estoy haciendo algo mal? ¿Hay alguna otra forma de burlarse de un objeto/datos básicos con @dynamic proyperties?

Respuesta

20

también respondió a su cruzada post en el OCMock Forum

Salida http://iamleeg.blogspot.com/2009/09/unit-testing-core-data-driven-apps.html.

Básicamente, sugiere abstraer la interfaz de su objeto Core Data a un protocolo, y usar ese protocolo en lugar de la clase donde pasa las instancias de su objeto de datos central.

Lo hago para mis objetos de datos principales. A continuación, puede utilizar mockForProtocol:

id mockItem = [OCMockObject mockForProtocol:@protocol(MyItemInterface)]; 
[[[mockItem expect] andReturn:@"fakepath.pdf"] PDFName]; 

Funciona muy bien! También sugiere la creación de un conjunto de datos no esenciales simulacro de implementación de la interfaz que acaba sintetiza las propiedades:

@implementation MockMyItem 
@synthesize PDFName; 
@end 

... 

id <MyItemInterface> myItemStub = [[MockMyItem alloc] init] autorelease]; 
[myItem setPDFName:@"fakepath.pdf"]; 

He usado esto también, pero no estoy seguro de que añade algo más de la mockForProtocol:/ramal : enfoque, y es una cosa más para mantener.

+1

Solo para completar, ¿podría volver a publicar su respuesta aquí, por favor? Esta no es la respuesta. ¿Qué pasa si ese enlace muere? – Bach

+1

Hecho ... Copié mi publicación del foro de OCMock –

+0

No lo entiendo, ¿por qué no simplemente utilizo un NSManagedObject real en su prueba? ¿Tiene otras pruebas que validan que el protocolo coincida con su modelo de objetos gestionados? – ImHuntingWabbits

11

La respuesta anterior no me satisfacía, porque no me gustaba crear un protocolo para eso. Entonces descubrí que hay una manera más fácil de hacer eso. En lugar de

[[[mockItem stub] andReturn:@"fakepath.pdf"] PDFName]; // <-- throws exception here 

Sólo tiene que escribir

[[[mockItem stub] andReturn:@"fakepath.pdf"] valueForKey:@"PDFName"]; 
+0

gracias! esa es una solución mucho mejor. – Sam

2

Una de las soluciones es el uso de un protocolo, que está destinado a sustituir su interfaz original, pero podría ser un poco pesado y conduce a la importante cantidad de código debes duplicar

Personalmente, he encontrado una manera para que sea liviano:

crear una categoría simple, por ejemplo, dentro de su archivo de pruebas de unidad, justo antes de su clase de la unidad de pruebas:

@implementation MyItem(UnitTesing) 
- (NSString *)PDFName{return nil;}; 
@end 

Además, puede mantenerlo en un archivo separado, pero asegúrese de que este archivo no sea parte de su objetivo de producción. Es por eso que prefiero mantenerlo en el mismo archivo de prueba, donde quiero usarlo.

La gran ventaja de este método es que no debe copiar métodos creados por XCode para admitir relaciones. También puede poner en esta categoría solo los métodos que va a llamar dentro de sus pruebas.

Hay algunas advertencias, sin embargo, por ejemplo, se debe añadir otros métodos dentro de la categoría, para apoyar a los emisores, cuando se va a comprobar, la forma correcta su código cambia las propiedades de su objeto administrado:

- (void)setPDFName:(NSString *)name{}; 
Cuestiones relacionadas