SlideShare una empresa de Scribd logo
1 de 61
Descargar para leer sin conexión
Bienvenido a la república
                       independiente de las pruebas
                            unitarias con Core Data
                             Jorge D. Ortiz Fuentes (@jdortiz)
                            Alfonso Alba Garcia (@aalbagarcia)




viernes, 8 de marzo de 13
Agenda
                     ★ MVC
                     ★ Implementación en   Core Data
                     ★ Pruebas Unitarias
                     ★ Desacoplamiento
                     ★ Conclusiones

                                   2
viernes, 8 de marzo de 13
El modelo a seguir
viernes, 8 de marzo de 13
MVC
                     ★      Las vistas las proporciona Apple (aunque
                            nosotros podemos crear lasque necesitemos).
                     ★      El modelo debe contener toda la lógica de
                            negocio.
                     ★      Atención: Modelo de datos vs modelo de
                            negocio.
                     ★      El controlador debería la conexión de las
                            vistas con el modelo de negocio.
                     ★      No es necesario que sea / NO debería ser un
                            singleton. Se pasa de un controlador a
                            otro. (Core Data: MOC o UIManagedDocument)


                                               4
viernes, 8 de marzo de 13
Modelo autocontenido
                     ★ La      forma más sencilla de evitar
                            duplicación de código y conseguir
                            un comportamiento consistente.
                     ★ Core      Data incluye restricciones.
                            P. ej., atributo opcional o no o
                            cardinalidad de una relación.
                     ★ Pero      para añadir otra
                            funcionalidad hay que añadir
                            métodos.

                                          5
viernes, 8 de marzo de 13
Usa Core Data, Luke
viernes, 8 de marzo de 13
Implementación del
                 modelo de negocio
                     ★ Modificar      modelo de datos ⇒
                            regenerar clases. Xcode
                            sobreescribe ⇒ métodos añadidos
                     ★ Soluciones:
                            ๏ Aprovechar el control   de versiones
                            ๏ mogenerator (http://
                              rentzsch.github.com/mogenerator/) de
                              W. Rentzsch
                            ๏ Categorías
                                             7
viernes, 8 de marzo de 13
Implementación del
                 modelo de negocio
                     ★ Modificar      modelo de datos ⇒
                            regenerar clases. Xcode
                            sobreescribe ⇒ métodos añadidos
                     ★ Soluciones:
                            ๏ Aprovechar el control   de versiones
                            ๏ mogenerator (http://
                              rentzsch.github.com/mogenerator/) de
                              W. Rentzsch
                            ๏ Categorías
                                             7
viernes, 8 de marzo de 13
Modelo NSCoderApp




viernes, 8 de marzo de 13
Group (Generado)
                      ★      #import <Foundation/Foundation.h>
                                                                                  #import "Group.h"
                                                                                  #import "Person.h"

                 #import <CoreData/CoreData.h>
                                                                                  @implementation Group
                 @class Person;
                                                                                  @dynamic   name;
                 @interface Group : NSManagedObject                               @dynamic   notes;
                                                                                  @dynamic   members;
                 @property   (nonatomic,   retain)   NSString * name;             @dynamic   meetings;
                 @property   (nonatomic,   retain)   NSString * notes;
                 @property   (nonatomic,   retain)   NSSet *members;              @end
                 @property   (nonatomic,   retain)   NSManagedObject *meetings;
                 @end

                 @interface Group (CoreDataGeneratedAccessors)

                 -   (void)addMembersObject:(Person *)value;
                 -   (void)removeMembersObject:(Person *)value;
                 -   (void)addMembers:(NSSet *)values;
                 -   (void)removeMembers:(NSSet *)values;

                 @end




viernes, 8 de marzo de 13
Categoría Group+Model
                     ★      #import "Group.h"   #import "Group+Model.h"

                                                @implementation Group (Model)

                                                #pragma mark - Detect duplicates
                 @interface Group (Model)
                                                /**
                 - (BOOL) isDuplicated;          Verify that this item doesn't exist yet (another section
                                                with the same name).
                 @end                            */
                                                - (BOOL) isDuplicated {
                                                    BOOL duplicated = NO;
                                                    NSFetchRequest *fetchRequest = [NSFetchRequest
                                                fetchRequestWithEntityName:@"Group"];

                                                    // Set the predicate to find if another one exists.
                                                    fetchRequest.predicate = [NSPredicate
                                                predicateWithFormat:@"name == %@", self.name];

                                                    NSError *error = nil;
                                                    NSUInteger sections = [self.managedObjectContext
                                                countForFetchRequest:fetchRequest

                                                error:&error];
                                                    // The first one is the one this one.
                                                    if (sections > 1) {
                                                        duplicated = YES;
                                                    }

                                                    return duplicated;
                                                }

                                                @end




viernes, 8 de marzo de 13
Pruebas
viernes, 8 de marzo de 13
La prueba del 3
                     ★ Incluir         pruebas:
                            ๏ Más exhaustivo y sistemático.
                            ๏ Refactorizar con mucho menos riesgo.
                            ๏ Verificar la resolución de bugs y evitar
                              regresiones.
                     ★ Lo      que proporciona el sistema
                            (frameworks) no se prueba.
                     ★ Como       mínimo:
                            ๏ Modelo   de negocio → Métodos añadidos


                                                12
viernes, 8 de marzo de 13
Implementación de las
                 pruebas
                     ★ OCUnit para no compicarse la vida
                     ★ Nombre explicativo
                     ★ Cobertura
                     ★ Casos relevantes
                     ★ Importante para Core Data: setUp y
                            tearDown
                            ๏   Carga del modelo
                            ๏   Preparación del Persistent Store en
                                memoria.


                                                   13
viernes, 8 de marzo de 13
Preparación
                     ★      - (void) setUp {


                     [super setUp];
                     // Create the Core Data stack.
                     NSBundle *bundle = [NSBundle bundleForClass:[self class]];
                     model = [NSManagedObjectModel mergedModelFromBundles:@[bundle]];
                     coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
                     store = [coordinator addPersistentStoreWithType: NSInMemoryStoreType
                                                       configuration: nil
                                                                 URL: nil
                                                             options: nil
                                                               error: NULL];
                     context = [[NSManagedObjectContext alloc] init];
                     [context setPersistentStoreCoordinator:coordinator];

                     // Instantiate three products for the tests.
                     mainGroup = [NSEntityDescription insertNewObjectForEntityForName:@"Group"
                                                               inManagedObjectContext:context];
                     mainGroup.name = @"A cool group";
                 }


                 - (void) tearDown {
                     context = nil;
                     store = nil;
                     coordinator = nil;
                     model = nil;

                     [super tearDown];
                 }




                                                                             14
viernes, 8 de marzo de 13
No duplicación
                     ★      #pragma mark - Detect duplication



                 - (void) testDuplicatedIsDetectedWhenTwoGroupsWithSameName {
                     Group *anotherGroup = [NSEntityDescription insertNewObjectForEntityForName:@"Group"
                                                                         inManagedObjectContext:context];
                     anotherGroup.name = @"A cool group";
                     STAssertTrue([mainGroup isDuplicated],
                                  @"If another group exists with the same name it is considered a duplicate");
                 }


                 - (void) testDuplicatedIsNotDetectedWhenTwoGroupsWithDifferentName {
                     Store *anotherStore = [NSEntityDescription insertNewObjectForEntityForName:@"Group"
                                                                         inManagedObjectContext:context];
                     anotherGroup.name = @"Another cool group";
                     STAssertFalse([mainGroup isDuplicated],
                                   @"If no other group exists with a different name it is not considered a
                 duplicate");
                 }




                                                                15
viernes, 8 de marzo de 13
Desacoplamiento
viernes, 8 de marzo de 13
This is an
                            open discussion



viernes, 8 de marzo de 13
Marco Arment

         “It’s so simple, I’ll just use plist”




viernes, 8 de marzo de 13
El problema
                     ★ Acoplamiento      fuerte entre los
                            componentes de la aplicación
                            (Models, Views, Controllers)
                     ★ Difícil      hacer mocks para
                            aplicar TDD
                            ๏ TDD = componentes independientes
                              que se testan de forma
                              independiente entre sí
                            ๏ (¿Mocking de
                              NSManagedObjectContext?)
                                            19
viernes, 8 de marzo de 13
El problema
                     ★ Para      testear un View Controller que
                            muestra en pantalla un listado de
                            Meetings tendría que:
                            ๏   Crear un NSManagedObjectContext
                            ๏   Cargar datos de prueba en la base de
                                datos
                            ๏   Hacer una búsqueda sobre los datos de
                                prueba
                            ๏   Generar un NSFetchedResultsController
                            ๏   ...y finalmente testear


                                                 20
viernes, 8 de marzo de 13
El problema
                     ★ ...y      después de hacer todo
                            esto, resulta que queremos
                            hacer una versión para Android
                            y compartir datos usando
                            Parse/RoR/PHP/DynamoDB
                     ★ ...o      prefieres usar plists
                            para no complicarte la vida
                            (como Marco Arment, pero al
                            revés)

                                         21
viernes, 8 de marzo de 13
El problema




                            http://www.confreaks.com/videos/759-rubymidwest2011-keynote-architecture-the-lost-years
viernes, 8 de marzo de 13
“The database is a DETAIL of our application”




viernes, 8 de marzo de 13
View Controller




            Model
                                              View
         (Core Data)

          Meeting.h


viernes, 8 de marzo de 13
Como la base de datos
                              es un detalle, la
                               podemos quitar


viernes, 8 de marzo de 13
Request:
          quiero ver todos los
            objetos Meeting
                                 View Controller




viernes, 8 de marzo de 13
Request:
          quiero ver todos los
            objetos Meeting
                                 View Controller


       Entidad: Objeto que contiene las            MeetingEntity

       reglas de negocio genéricas,
       aquellas que se pueden aplicar               GroupEntity

       siempre en cualquier contexto.
                                                   AttendeeEntity


       Por ejemplo: Si a un evento se
       inscriben tres personas, este
       queda automáticamente confirmado


viernes, 8 de marzo de 13
Request:
          quiero ver todos los
            objetos Meeting
                                         View Controller


                                                            MeetingEntity


                                 BrowseMeetingsInteractor    GroupEntity


                                                            AttendeeEntity

    Interactor: Contiene reglas de
    negocio específicas

    Por ejemplo: Dos eventos no
    pueden tener el mismo nombre
viernes, 8 de marzo de 13
¿Y la base de datos?




viernes, 8 de marzo de 13
Request:
          quiero ver todos los
            objetos Meeting
                                         View Controller


                                                            MeetingEntity


                                 BrowseMeetingsInteractor    GroupEntity


                                                            AttendeeEntity



                                    MeetingsGateway




                                            Model
                                         (Core Data)


viernes, 8 de marzo de 13
Request:
          quiero ver todos los
            objetos Meeting
                                         View Controller
                                           Request
                                           Object




                                                            MeetingEntity


                                 BrowseMeetingsInteractor    GroupEntity


                                                            AttendeeEntity



                                    MeetingsGateway




                                            Model
                                         (Core Data)


viernes, 8 de marzo de 13
Request:
          quiero ver todos los
            objetos Meeting
                                         View Controller


                                                            MeetingEntity


                                 BrowseMeetingsInteractor    GroupEntity
                                          Request
                                          Object


                                                            AttendeeEntity



                                    MeetingsGateway




                                            Model
                                         (Core Data)


viernes, 8 de marzo de 13
Request:
          quiero ver todos los
            objetos Meeting
                                         View Controller


                                                                                       MeetingEntity


                                 BrowseMeetingsInteractor                               GroupEntity


                                                                                      AttendeeEntity

                                          Request
                                          Object


                                    MeetingsGateway


                                                       ...accede a Core Data y busca los objetos que
                                                           cumplen los criterios del RequestObject
                                            Model
                                         (Core Data)


viernes, 8 de marzo de 13
Request:
          quiero ver todos los
            objetos Meeting
                                         View Controller


                                                                   MeetingEntity


                                 BrowseMeetingsInteractor           GroupEntity



                                                       Entidades   AttendeeEntity



                                    MeetingsGateway




                                            Model
                                         (Core Data)


viernes, 8 de marzo de 13
Request:
          quiero ver todos los
            objetos Meeting
                                         View Controller


                                                                   MeetingEntity
                                                  ResponseObject

                                 BrowseMeetingsInteractor           GroupEntity



                                                       Entidades   AttendeeEntity



                                    MeetingsGateway




                                            Model
                                         (Core Data)


viernes, 8 de marzo de 13
Request:
          quiero ver todos los
            objetos Meeting
                                         View Controller

   ResponseObject
                                                            MeetingEntity
           View


                                 BrowseMeetingsInteractor    GroupEntity


                                                            AttendeeEntity



                                    MeetingsGateway




                                            Model
                                         (Core Data)


viernes, 8 de marzo de 13
show me the code!!



viernes, 8 de marzo de 13
Duck Typing



viernes, 8 de marzo de 13
Request:
          quiero ver todos los
            objetos Meeting
                                          View Controller
                                       RequestObjectProtocol




   ResponseObject
                                                                     MeetingEntity
           View


                                 BrowseMeetingsInteractor             GroupEntity


                                                                     AttendeeEntity


                                                    ResponseObject

                                  MeetingsParseGateway




                                             Model
                                          (Core Data)


viernes, 8 de marzo de 13
QueryRequestProtocol

          @protocol QueryRequestProtocol

          @required
          @property (nonatomic, strong) NSString *queryString;
          @property (nonatomic, strong, readonly) NSDictionary *components;

          @end




viernes, 8 de marzo de 13
BrowseMeetingsInteractor


@interface BrowseMeetingsInteractor : NSObject

@property (nonatomic, strong) id<MeetingGatewayProtocol> gateway;

- (id<StandardResponseProtocol>) getResponseForRequest:
(id<QueryRequestProtocol >)request;
@end




viernes, 8 de marzo de 13
MeetingGateway

      @class MeetingEntity;

      @protocol MeetingGatewayProtocol <NSObject>

      @required
      - (id)processRequest:(id<QueryRequestProtocol> *)request;
      - (void)save:(MeetingEntity *)meeting error:(NSError **)error;
      @end




viernes, 8 de marzo de 13
viewDidLoad
               if (!self.fridgeResponse)
               {
                   IFCoreDataFridgeGateway *gateway = [[IFCoreDataFridgeGateway alloc] init];
                   gateway.shouldReturnFetchResultsController = false;
                   gateway.context = self.context;


                     self.fridgeInteractor = [[IFViewFridgeInteractor alloc] init];
                     self.fridgeInteractor.gateway = gateway;

                     self.fridgeResponse = [self.fridgeInteractor getResponseForRequest:self.request];
               }

               if (!self.fridgeItemsResponse)
               {
                   IFCoreDataFridgeItemGateway *fridgeItemGateway = [[IFCoreDataFridgeItemGateway alloc] init];
                   fridgeItemGateway.context = self.context;
                   fridgeItemGateway.shouldReturnFetchResultsController = YES;

                     self.fridgeItemsInteractor = [[IFBrowseFridgeItemsInteractor alloc] init];
                     self.fridgeItemsInteractor.gateway = fridgeItemGateway;
                     IFFridgeItemRequestObject *fridgeItemsRequest = [[IFFridgeItemRequestObject alloc] init];
                     ;


                 fridgeItemsRequest.queryString = [NSString stringWithFormat:@"fridge-slug=
         %@",self.request.components[@"slug"] ] ;
                 self.fridgeItemsResponse = [self.fridgeItemsInteractor getResponseForRequest:fridgeItemsRequest];
             }



viernes, 8 de marzo de 13
¿Cómo cambiamos de CoreData
          a Parse?



viernes, 8 de marzo de 13
Request:
          quiero ver todos los
            objetos Meeting
                                            View Controller
                                            RequestObject




   ResponseObject
                                                                               MeetingEntity
           View


                                 BrowseMeetingsInteractor                       GroupEntity


                                                                               AttendeeEntity


                                                  ResponseObject

                                  MeetingsParseGateway                  Mientras la clase
                                                                    MeetingsParseGateway y
                                                                   MeetingsGateway cumplan
                                                    Cache          el mismo protocolo ¡todo
                                    Parse
                                                 (Core Data)
                                                                           funciona!
viernes, 8 de marzo de 13
¡¡Podemos testearlo todo!!




viernes, 8 de marzo de 13
Request:
          quiero ver todos los
            objetos Meeting
                                            View Controller
                                            RequestObject




   ResponseObject
                                                                   MeetingEntity
           View


                                 BrowseMeetingsInteractor           GroupEntity


                                                                   AttendeeEntity


                                                  ResponseObject

                                  MeetingsParseGateway




                                                    Cache
                                    Parse
                                                 (Core Data)



viernes, 8 de marzo de 13
View Controller
                                        RequestObject




                                                  MockResponseObject



                              MockBrowseMeetingsInteractor




                            Para testear el view controller,
                             basta con tener un Mock del
                                      Interactor



viernes, 8 de marzo de 13
Request:
          quiero ver todos los
            objetos Meeting
                                            View Controller
                                            RequestObject




   ResponseObject
                                                                               MeetingEntity
           View


                                 BrowseMeetingsInteractor                       GroupEntity


                                                                               AttendeeEntity


                                                  ResponseObject

                                  MeetingsParseGateway                  Mientras la clase
                                                                    MeetingsParseGateway y
                                                                   MeetingsGateway cumplan
                                                    Cache          el mismo protocolo ¡todo
                                    Parse
                                                 (Core Data)
                                                                           funciona!
viernes, 8 de marzo de 13
Request:
          quiero ver todos los
            objetos Meeting

                            MockRequestObject
                                                  ResponseObject




                                                                   MeetingEntity


                                 BrowseMeetingsInteractor           GroupEntity


                                                                   AttendeeEntity



                                      MockGateway




viernes, 8 de marzo de 13
En la vida nada es
                 gratis...
                     ★ Hay      que escribir más código
                     ★ Hay      que pensar en interfaces
                            (protocolos)
                     ★ ¿Rendimiento?



                                        51
viernes, 8 de marzo de 13
¿Qué pensáis?




                            52
viernes, 8 de marzo de 13
¿Qué pensáis?
              ★        ¿Creéis que tener un sistema de componentes
                       realmente desacoplados es un buen sistema?




                                              52
viernes, 8 de marzo de 13
¿Qué pensáis?
              ★        ¿Creéis que tener un sistema de componentes
                       realmente desacoplados es un buen sistema?
              ★        ¿Pensáis que tener un sistema en el que puedo
                       testear sus componentes por separado, es un buen
                       sistema?




                                              52
viernes, 8 de marzo de 13
¿Qué pensáis?
              ★        ¿Creéis que tener un sistema de componentes
                       realmente desacoplados es un buen sistema?
              ★        ¿Pensáis que tener un sistema en el que puedo
                       testear sus componentes por separado, es un buen
                       sistema?
              ★        ¿Pensáis que tener un sistema flexible en el que
                       puedo posponer las decisiones sobre aspectos
                       fundamentales del mismo hasta que realmente las
                       necesito es un buen sistema?




                                              52
viernes, 8 de marzo de 13
¿Qué pensáis?
              ★        ¿Creéis que tener un sistema de componentes
                       realmente desacoplados es un buen sistema?
              ★        ¿Pensáis que tener un sistema en el que puedo
                       testear sus componentes por separado, es un buen
                       sistema?
              ★        ¿Pensáis que tener un sistema flexible en el que
                       puedo posponer las decisiones sobre aspectos
                       fundamentales del mismo hasta que realmente las
                       necesito es un buen sistema?
              ★        ¿Pensáis que poder sustituir unas componentes por
                       otras es un buen sistema?




                                              52
viernes, 8 de marzo de 13
¿Qué pensáis?
              ★        ¿Creéis que tener un sistema de componentes
                       realmente desacoplados es un buen sistema?
              ★        ¿Pensáis que tener un sistema en el que puedo
                       testear sus componentes por separado, es un buen
                       sistema?
              ★        ¿Pensáis que tener un sistema flexible en el que
                       puedo posponer las decisiones sobre aspectos
                       fundamentales del mismo hasta que realmente las
                       necesito es un buen sistema?
              ★        ¿Pensáis que poder sustituir unas componentes por
                       otras es un buen sistema?
              ★        ¿Pensáis que un sistema en el que una buena parte
                       del código se puede autogenerar o reutilizar es un
                       buen sistema?
                                              52
viernes, 8 de marzo de 13
Cuando no...
                     ★ Si      quieres hacer un prototipo
                            rápido de la applicación
                     ★ Si      no quieres hacer TDD, ni
                            desacoplar componentes ni
                            dormir más tranquilo por las
                            noches cuando tu app se la
                            descarguen miles de personas



                                        53
viernes, 8 de marzo de 13
¡Es una inversión de
                             futuro!

                            ¡Gracias!
viernes, 8 de marzo de 13
Recursos
                 recomendados
                     ★ Architecture: the lost years
                     ★ Test Driven iOS Development
                     ★ www.cleancoders.com/



                                   55
viernes, 8 de marzo de 13

Más contenido relacionado

La actualidad más candente

La actualidad más candente (12)

Metodologia para resolver problemas con Programacion orientada a Objetos
Metodologia para resolver problemas con Programacion orientada a ObjetosMetodologia para resolver problemas con Programacion orientada a Objetos
Metodologia para resolver problemas con Programacion orientada a Objetos
 
Multitarea e hilos en java con ejemplos
Multitarea e hilos en java con ejemplosMultitarea e hilos en java con ejemplos
Multitarea e hilos en java con ejemplos
 
Introduccion java
Introduccion javaIntroduccion java
Introduccion java
 
04 actions
04 actions04 actions
04 actions
 
Semana 6 Módulos Clases y Objetos
Semana 6   Módulos Clases y ObjetosSemana 6   Módulos Clases y Objetos
Semana 6 Módulos Clases y Objetos
 
Concurrencia en Java
Concurrencia en JavaConcurrencia en Java
Concurrencia en Java
 
Patrones de diseño de software
Patrones de diseño de softwarePatrones de diseño de software
Patrones de diseño de software
 
Workshop iOS 4: Closures, generics & operators
Workshop iOS 4: Closures, generics & operatorsWorkshop iOS 4: Closures, generics & operators
Workshop iOS 4: Closures, generics & operators
 
SpringFramework Overview
SpringFramework OverviewSpringFramework Overview
SpringFramework Overview
 
Guia4 java
Guia4 javaGuia4 java
Guia4 java
 
Java clases dictadas
Java clases dictadasJava clases dictadas
Java clases dictadas
 
Creación de plugins con Grails
Creación de plugins con GrailsCreación de plugins con Grails
Creación de plugins con Grails
 

Destacado

Profili social e reputazione digitale
Profili social e reputazione digitaleProfili social e reputazione digitale
Profili social e reputazione digitaleCaterina Policaro
 
Error messages
Error messagesError messages
Error messagesrtinkelman
 
Como hacer un plan de negocios
Como hacer un plan de negociosComo hacer un plan de negocios
Como hacer un plan de negociosXPINNERPablo
 
Schrijven voor het web
Schrijven voor het webSchrijven voor het web
Schrijven voor het webSimone Levie
 
3.Evidence: Getting to Bogota.ENGLISH DOT WORKS 2. SENA.semana 4 actividad 3.
3.Evidence: Getting to Bogota.ENGLISH DOT WORKS 2. SENA.semana 4 actividad 3.3.Evidence: Getting to Bogota.ENGLISH DOT WORKS 2. SENA.semana 4 actividad 3.
3.Evidence: Getting to Bogota.ENGLISH DOT WORKS 2. SENA.semana 4 actividad 3... ..
 
Estrategias competitivas básicas
Estrategias competitivas básicasEstrategias competitivas básicas
Estrategias competitivas básicasLarryJimenez
 
Evidence: Memorable moments.ENGLISH DOT WORKS 2. SENA. semana 2 actividad 2.
Evidence: Memorable moments.ENGLISH DOT WORKS 2. SENA. semana 2 actividad 2.Evidence: Memorable moments.ENGLISH DOT WORKS 2. SENA. semana 2 actividad 2.
Evidence: Memorable moments.ENGLISH DOT WORKS 2. SENA. semana 2 actividad 2... ..
 
Evidence: Describing my kitchen. ENGLISH DOT WORKS 2. SENA.
Evidence: Describing my kitchen. ENGLISH DOT WORKS 2. SENA.Evidence: Describing my kitchen. ENGLISH DOT WORKS 2. SENA.
Evidence: Describing my kitchen. ENGLISH DOT WORKS 2. SENA... ..
 
2. describing cities and places. ENGLISH DOT WORKS 2. SENA. semana 4 acitivda...
2. describing cities and places. ENGLISH DOT WORKS 2. SENA. semana 4 acitivda...2. describing cities and places. ENGLISH DOT WORKS 2. SENA. semana 4 acitivda...
2. describing cities and places. ENGLISH DOT WORKS 2. SENA. semana 4 acitivda..... ..
 
Evidence: Going to the restaurant . ENGLISH DOT WORKS 2. SENA.
Evidence: Going to the restaurant . ENGLISH DOT WORKS 2. SENA.Evidence: Going to the restaurant . ENGLISH DOT WORKS 2. SENA.
Evidence: Going to the restaurant . ENGLISH DOT WORKS 2. SENA... ..
 
Evidence: I can’t believe it.ENGLISH DOT WORKS 2. semana 3 actividad 1.SENA.
Evidence: I can’t believe it.ENGLISH DOT WORKS 2. semana 3 actividad 1.SENA.Evidence: I can’t believe it.ENGLISH DOT WORKS 2. semana 3 actividad 1.SENA.
Evidence: I can’t believe it.ENGLISH DOT WORKS 2. semana 3 actividad 1.SENA... ..
 
Evidence: Planning my trip. ENGLISH DOT WORKS 2. SENA. semana 4 actividad 1.
Evidence: Planning my trip. ENGLISH DOT WORKS 2. SENA. semana 4 actividad 1.Evidence: Planning my trip. ENGLISH DOT WORKS 2. SENA. semana 4 actividad 1.
Evidence: Planning my trip. ENGLISH DOT WORKS 2. SENA. semana 4 actividad 1... ..
 
Desarrollo local y regional
Desarrollo local y regionalDesarrollo local y regional
Desarrollo local y regionalPablo Ruiz
 
Evidence: What did I do yesterday?.ENGLISH DOT WORKS 2. SENA. SEMANA 2 ACTIVI...
Evidence: What did I do yesterday?.ENGLISH DOT WORKS 2. SENA. SEMANA 2 ACTIVI...Evidence: What did I do yesterday?.ENGLISH DOT WORKS 2. SENA. SEMANA 2 ACTIVI...
Evidence: What did I do yesterday?.ENGLISH DOT WORKS 2. SENA. SEMANA 2 ACTIVI..... ..
 

Destacado (20)

Profili social e reputazione digitale
Profili social e reputazione digitaleProfili social e reputazione digitale
Profili social e reputazione digitale
 
Error messages
Error messagesError messages
Error messages
 
Tears In The Rain
Tears In The RainTears In The Rain
Tears In The Rain
 
Como hacer un plan de negocios
Como hacer un plan de negociosComo hacer un plan de negocios
Como hacer un plan de negocios
 
Schrijven voor het web
Schrijven voor het webSchrijven voor het web
Schrijven voor het web
 
Cápsula 1. estudios de mercado
Cápsula 1. estudios de mercadoCápsula 1. estudios de mercado
Cápsula 1. estudios de mercado
 
Rodriguez alvarez
Rodriguez alvarezRodriguez alvarez
Rodriguez alvarez
 
3.Evidence: Getting to Bogota.ENGLISH DOT WORKS 2. SENA.semana 4 actividad 3.
3.Evidence: Getting to Bogota.ENGLISH DOT WORKS 2. SENA.semana 4 actividad 3.3.Evidence: Getting to Bogota.ENGLISH DOT WORKS 2. SENA.semana 4 actividad 3.
3.Evidence: Getting to Bogota.ENGLISH DOT WORKS 2. SENA.semana 4 actividad 3.
 
Estrategias competitivas básicas
Estrategias competitivas básicasEstrategias competitivas básicas
Estrategias competitivas básicas
 
Evidence: Memorable moments.ENGLISH DOT WORKS 2. SENA. semana 2 actividad 2.
Evidence: Memorable moments.ENGLISH DOT WORKS 2. SENA. semana 2 actividad 2.Evidence: Memorable moments.ENGLISH DOT WORKS 2. SENA. semana 2 actividad 2.
Evidence: Memorable moments.ENGLISH DOT WORKS 2. SENA. semana 2 actividad 2.
 
Evidence: Describing my kitchen. ENGLISH DOT WORKS 2. SENA.
Evidence: Describing my kitchen. ENGLISH DOT WORKS 2. SENA.Evidence: Describing my kitchen. ENGLISH DOT WORKS 2. SENA.
Evidence: Describing my kitchen. ENGLISH DOT WORKS 2. SENA.
 
2. describing cities and places. ENGLISH DOT WORKS 2. SENA. semana 4 acitivda...
2. describing cities and places. ENGLISH DOT WORKS 2. SENA. semana 4 acitivda...2. describing cities and places. ENGLISH DOT WORKS 2. SENA. semana 4 acitivda...
2. describing cities and places. ENGLISH DOT WORKS 2. SENA. semana 4 acitivda...
 
Capacitacion y adiestramiento
Capacitacion y adiestramientoCapacitacion y adiestramiento
Capacitacion y adiestramiento
 
Evidence: Going to the restaurant . ENGLISH DOT WORKS 2. SENA.
Evidence: Going to the restaurant . ENGLISH DOT WORKS 2. SENA.Evidence: Going to the restaurant . ENGLISH DOT WORKS 2. SENA.
Evidence: Going to the restaurant . ENGLISH DOT WORKS 2. SENA.
 
Evidence: I can’t believe it.ENGLISH DOT WORKS 2. semana 3 actividad 1.SENA.
Evidence: I can’t believe it.ENGLISH DOT WORKS 2. semana 3 actividad 1.SENA.Evidence: I can’t believe it.ENGLISH DOT WORKS 2. semana 3 actividad 1.SENA.
Evidence: I can’t believe it.ENGLISH DOT WORKS 2. semana 3 actividad 1.SENA.
 
Evidence: Planning my trip. ENGLISH DOT WORKS 2. SENA. semana 4 actividad 1.
Evidence: Planning my trip. ENGLISH DOT WORKS 2. SENA. semana 4 actividad 1.Evidence: Planning my trip. ENGLISH DOT WORKS 2. SENA. semana 4 actividad 1.
Evidence: Planning my trip. ENGLISH DOT WORKS 2. SENA. semana 4 actividad 1.
 
Desarrollo local y regional
Desarrollo local y regionalDesarrollo local y regional
Desarrollo local y regional
 
Modulo7gestion
Modulo7gestionModulo7gestion
Modulo7gestion
 
C:\Fakepath\Christie
C:\Fakepath\ChristieC:\Fakepath\Christie
C:\Fakepath\Christie
 
Evidence: What did I do yesterday?.ENGLISH DOT WORKS 2. SENA. SEMANA 2 ACTIVI...
Evidence: What did I do yesterday?.ENGLISH DOT WORKS 2. SENA. SEMANA 2 ACTIVI...Evidence: What did I do yesterday?.ENGLISH DOT WORKS 2. SENA. SEMANA 2 ACTIVI...
Evidence: What did I do yesterday?.ENGLISH DOT WORKS 2. SENA. SEMANA 2 ACTIVI...
 

Similar a Bienvenido a la republica independiente de las pruebas unitarias con Core Data

Rompiendo dependencias contenidas en ensamblados .NET mediante la refactoriza...
Rompiendo dependencias contenidas en ensamblados .NET mediante la refactoriza...Rompiendo dependencias contenidas en ensamblados .NET mediante la refactoriza...
Rompiendo dependencias contenidas en ensamblados .NET mediante la refactoriza...jaircazarin
 
Greach 2013 - Todo lo que me hubiera gustado saber cuando empecé a desarrolla...
Greach 2013 - Todo lo que me hubiera gustado saber cuando empecé a desarrolla...Greach 2013 - Todo lo que me hubiera gustado saber cuando empecé a desarrolla...
Greach 2013 - Todo lo que me hubiera gustado saber cuando empecé a desarrolla...Iván López Martín
 
Taller introduccion symfony2
Taller introduccion symfony2Taller introduccion symfony2
Taller introduccion symfony2Mario IC
 
cream code with objective-c
cream code with objective-ccream code with objective-c
cream code with objective-cidealistaimasd
 
Patrones de diseño II
Patrones de diseño IIPatrones de diseño II
Patrones de diseño IIkaolong
 
Testing efectivo con pytest
Testing efectivo con pytestTesting efectivo con pytest
Testing efectivo con pytestHector Canto
 
Manual analisis dominancia_1
Manual analisis dominancia_1Manual analisis dominancia_1
Manual analisis dominancia_1vilna2011
 
Creación de Builders y DSL's con Groovy
Creación de Builders y DSL's con GroovyCreación de Builders y DSL's con Groovy
Creación de Builders y DSL's con GroovyJose Juan R. Zuñiga
 
Jyoc java-cap05 metodos (funciones)
Jyoc java-cap05 metodos (funciones)Jyoc java-cap05 metodos (funciones)
Jyoc java-cap05 metodos (funciones)Jyoc X
 
Joomladay 2008 Madrid - desarrollo de extensiones
Joomladay 2008 Madrid - desarrollo de extensionesJoomladay 2008 Madrid - desarrollo de extensiones
Joomladay 2008 Madrid - desarrollo de extensionesdeivit86
 
Intro a cakephp
Intro a cakephpIntro a cakephp
Intro a cakephpbetabeers
 
Curso de programación iPhone: Cocoa-Touch
Curso de programación iPhone: Cocoa-TouchCurso de programación iPhone: Cocoa-Touch
Curso de programación iPhone: Cocoa-Touchfrr149
 
Drupal7 para desarrolladores
Drupal7 para desarrolladoresDrupal7 para desarrolladores
Drupal7 para desarrolladoresPedro Cambra
 
Intro a ANNs c/Keras
Intro a ANNs c/KerasIntro a ANNs c/Keras
Intro a ANNs c/KerasRodolfo Ferro
 
Look and feel java
Look and feel javaLook and feel java
Look and feel javatiburon_u2
 

Similar a Bienvenido a la republica independiente de las pruebas unitarias con Core Data (20)

Rompiendo dependencias contenidas en ensamblados .NET mediante la refactoriza...
Rompiendo dependencias contenidas en ensamblados .NET mediante la refactoriza...Rompiendo dependencias contenidas en ensamblados .NET mediante la refactoriza...
Rompiendo dependencias contenidas en ensamblados .NET mediante la refactoriza...
 
S4-PD1.pptx
S4-PD1.pptxS4-PD1.pptx
S4-PD1.pptx
 
Android Superstar - Buenas Prácticas
Android Superstar - Buenas PrácticasAndroid Superstar - Buenas Prácticas
Android Superstar - Buenas Prácticas
 
Greach 2013 - Todo lo que me hubiera gustado saber cuando empecé a desarrolla...
Greach 2013 - Todo lo que me hubiera gustado saber cuando empecé a desarrolla...Greach 2013 - Todo lo que me hubiera gustado saber cuando empecé a desarrolla...
Greach 2013 - Todo lo que me hubiera gustado saber cuando empecé a desarrolla...
 
Taller introduccion symfony2
Taller introduccion symfony2Taller introduccion symfony2
Taller introduccion symfony2
 
Semana 2 Configuración entorno de desarrollo
Semana 2   Configuración entorno de desarrolloSemana 2   Configuración entorno de desarrollo
Semana 2 Configuración entorno de desarrollo
 
cream code with objective-c
cream code with objective-ccream code with objective-c
cream code with objective-c
 
Patrones de diseño II
Patrones de diseño IIPatrones de diseño II
Patrones de diseño II
 
Testing efectivo con pytest
Testing efectivo con pytestTesting efectivo con pytest
Testing efectivo con pytest
 
Manual analisis dominancia_1
Manual analisis dominancia_1Manual analisis dominancia_1
Manual analisis dominancia_1
 
Creación de Builders y DSL's con Groovy
Creación de Builders y DSL's con GroovyCreación de Builders y DSL's con Groovy
Creación de Builders y DSL's con Groovy
 
Jyoc java-cap05 metodos (funciones)
Jyoc java-cap05 metodos (funciones)Jyoc java-cap05 metodos (funciones)
Jyoc java-cap05 metodos (funciones)
 
Jdbc
JdbcJdbc
Jdbc
 
Joomladay 2008 Madrid - desarrollo de extensiones
Joomladay 2008 Madrid - desarrollo de extensionesJoomladay 2008 Madrid - desarrollo de extensiones
Joomladay 2008 Madrid - desarrollo de extensiones
 
Intro a cakephp
Intro a cakephpIntro a cakephp
Intro a cakephp
 
Intro a cakephp
Intro a cakephpIntro a cakephp
Intro a cakephp
 
Curso de programación iPhone: Cocoa-Touch
Curso de programación iPhone: Cocoa-TouchCurso de programación iPhone: Cocoa-Touch
Curso de programación iPhone: Cocoa-Touch
 
Drupal7 para desarrolladores
Drupal7 para desarrolladoresDrupal7 para desarrolladores
Drupal7 para desarrolladores
 
Intro a ANNs c/Keras
Intro a ANNs c/KerasIntro a ANNs c/Keras
Intro a ANNs c/Keras
 
Look and feel java
Look and feel javaLook and feel java
Look and feel java
 

Más de Alfonso Alba

Persistencia de datos con Parse
Persistencia de datos con ParsePersistencia de datos con Parse
Persistencia de datos con ParseAlfonso Alba
 
Perl6 expresiones regulares
Perl6 expresiones regularesPerl6 expresiones regulares
Perl6 expresiones regularesAlfonso Alba
 
Plantillajornadasversion2 100708010347-phpapp01
Plantillajornadasversion2 100708010347-phpapp01Plantillajornadasversion2 100708010347-phpapp01
Plantillajornadasversion2 100708010347-phpapp01Alfonso Alba
 

Más de Alfonso Alba (10)

Persistencia de datos con Parse
Persistencia de datos con ParsePersistencia de datos con Parse
Persistencia de datos con Parse
 
Usuarios ipad
Usuarios ipadUsuarios ipad
Usuarios ipad
 
Git
GitGit
Git
 
Perl6 expresiones regulares
Perl6 expresiones regularesPerl6 expresiones regulares
Perl6 expresiones regulares
 
Perl5 hashes
Perl5 hashesPerl5 hashes
Perl5 hashes
 
Perl1 escalares
Perl1 escalaresPerl1 escalares
Perl1 escalares
 
Perl2 arrays
Perl2 arraysPerl2 arrays
Perl2 arrays
 
Perl3 subrutinas
Perl3 subrutinasPerl3 subrutinas
Perl3 subrutinas
 
Perl4 io
Perl4 ioPerl4 io
Perl4 io
 
Plantillajornadasversion2 100708010347-phpapp01
Plantillajornadasversion2 100708010347-phpapp01Plantillajornadasversion2 100708010347-phpapp01
Plantillajornadasversion2 100708010347-phpapp01
 

Último

Inteligencia Artificial. Matheo Hernandez Serrano USCO 2024
Inteligencia Artificial. Matheo Hernandez Serrano USCO 2024Inteligencia Artificial. Matheo Hernandez Serrano USCO 2024
Inteligencia Artificial. Matheo Hernandez Serrano USCO 2024u20211198540
 
CommitConf 2024 - Spring Boot <3 Testcontainers
CommitConf 2024 - Spring Boot <3 TestcontainersCommitConf 2024 - Spring Boot <3 Testcontainers
CommitConf 2024 - Spring Boot <3 TestcontainersIván López Martín
 
_Planificacion Anual NTICX 2024.SEC.21.4.1.docx.pdf
_Planificacion Anual NTICX 2024.SEC.21.4.1.docx.pdf_Planificacion Anual NTICX 2024.SEC.21.4.1.docx.pdf
_Planificacion Anual NTICX 2024.SEC.21.4.1.docx.pdfBetianaJuarez1
 
Trabajo de tecnología excel avanzado.pdf
Trabajo de tecnología excel avanzado.pdfTrabajo de tecnología excel avanzado.pdf
Trabajo de tecnología excel avanzado.pdfedepmariaperez
 
Guía de Registro slideshare paso a paso 1
Guía de Registro slideshare paso a paso 1Guía de Registro slideshare paso a paso 1
Guía de Registro slideshare paso a paso 1ivanapaterninar
 
TALLER DE ANALISIS SOLUCION PART 2 (1)-1.docx
TALLER DE ANALISIS SOLUCION  PART 2 (1)-1.docxTALLER DE ANALISIS SOLUCION  PART 2 (1)-1.docx
TALLER DE ANALISIS SOLUCION PART 2 (1)-1.docxobandopaula444
 
LUXOMETRO EN SALUD OCUPACIONAL(FINAL).ppt
LUXOMETRO EN SALUD OCUPACIONAL(FINAL).pptLUXOMETRO EN SALUD OCUPACIONAL(FINAL).ppt
LUXOMETRO EN SALUD OCUPACIONAL(FINAL).pptchaverriemily794
 
PLANEACION DE CLASES TEMA TIPOS DE FAMILIA.docx
PLANEACION DE CLASES TEMA TIPOS DE FAMILIA.docxPLANEACION DE CLASES TEMA TIPOS DE FAMILIA.docx
PLANEACION DE CLASES TEMA TIPOS DE FAMILIA.docxhasbleidit
 
Actividades de computación para alumnos de preescolar
Actividades de computación para alumnos de preescolarActividades de computación para alumnos de preescolar
Actividades de computación para alumnos de preescolar24roberto21
 
Trabajando con Formasy Smart art en power Point
Trabajando con Formasy Smart art en power PointTrabajando con Formasy Smart art en power Point
Trabajando con Formasy Smart art en power PointValerioIvanDePazLoja
 
Análisis de los artefactos (nintendo NES)
Análisis de los artefactos (nintendo NES)Análisis de los artefactos (nintendo NES)
Análisis de los artefactos (nintendo NES)JuanStevenTrujilloCh
 
Viguetas Pretensadas en concreto armado
Viguetas Pretensadas  en concreto armadoViguetas Pretensadas  en concreto armado
Viguetas Pretensadas en concreto armadob7fwtwtfxf
 
Agencia Marketing Branding Google Workspace Deployment Services Credential Fe...
Agencia Marketing Branding Google Workspace Deployment Services Credential Fe...Agencia Marketing Branding Google Workspace Deployment Services Credential Fe...
Agencia Marketing Branding Google Workspace Deployment Services Credential Fe...Marketing BRANDING
 
certificado de oracle academy cetrificado.pdf
certificado de oracle academy cetrificado.pdfcertificado de oracle academy cetrificado.pdf
certificado de oracle academy cetrificado.pdfFernandoOblitasVivan
 
LINEA DE TIEMPO LITERATURA DIFERENCIADO LITERATURA.pptx
LINEA DE TIEMPO LITERATURA DIFERENCIADO LITERATURA.pptxLINEA DE TIEMPO LITERATURA DIFERENCIADO LITERATURA.pptx
LINEA DE TIEMPO LITERATURA DIFERENCIADO LITERATURA.pptxkimontey
 
La tecnología y su impacto en la sociedad
La tecnología y su impacto en la sociedadLa tecnología y su impacto en la sociedad
La tecnología y su impacto en la sociedadEduardoSantiagoSegov
 
Slideshare y Scribd - Noli Cubillan Gerencia
Slideshare y Scribd - Noli Cubillan GerenciaSlideshare y Scribd - Noli Cubillan Gerencia
Slideshare y Scribd - Noli Cubillan Gerenciacubillannoly
 
#Tare10ProgramacionWeb2024aaaaaaaaaaaa.pptx
#Tare10ProgramacionWeb2024aaaaaaaaaaaa.pptx#Tare10ProgramacionWeb2024aaaaaaaaaaaa.pptx
#Tare10ProgramacionWeb2024aaaaaaaaaaaa.pptxHugoGutierrez99
 
Documentacion Electrónica en Actos Juridicos
Documentacion Electrónica en Actos JuridicosDocumentacion Electrónica en Actos Juridicos
Documentacion Electrónica en Actos JuridicosAlbanyMartinez7
 

Último (20)

El camino a convertirse en Microsoft MVP
El camino a convertirse en Microsoft MVPEl camino a convertirse en Microsoft MVP
El camino a convertirse en Microsoft MVP
 
Inteligencia Artificial. Matheo Hernandez Serrano USCO 2024
Inteligencia Artificial. Matheo Hernandez Serrano USCO 2024Inteligencia Artificial. Matheo Hernandez Serrano USCO 2024
Inteligencia Artificial. Matheo Hernandez Serrano USCO 2024
 
CommitConf 2024 - Spring Boot <3 Testcontainers
CommitConf 2024 - Spring Boot <3 TestcontainersCommitConf 2024 - Spring Boot <3 Testcontainers
CommitConf 2024 - Spring Boot <3 Testcontainers
 
_Planificacion Anual NTICX 2024.SEC.21.4.1.docx.pdf
_Planificacion Anual NTICX 2024.SEC.21.4.1.docx.pdf_Planificacion Anual NTICX 2024.SEC.21.4.1.docx.pdf
_Planificacion Anual NTICX 2024.SEC.21.4.1.docx.pdf
 
Trabajo de tecnología excel avanzado.pdf
Trabajo de tecnología excel avanzado.pdfTrabajo de tecnología excel avanzado.pdf
Trabajo de tecnología excel avanzado.pdf
 
Guía de Registro slideshare paso a paso 1
Guía de Registro slideshare paso a paso 1Guía de Registro slideshare paso a paso 1
Guía de Registro slideshare paso a paso 1
 
TALLER DE ANALISIS SOLUCION PART 2 (1)-1.docx
TALLER DE ANALISIS SOLUCION  PART 2 (1)-1.docxTALLER DE ANALISIS SOLUCION  PART 2 (1)-1.docx
TALLER DE ANALISIS SOLUCION PART 2 (1)-1.docx
 
LUXOMETRO EN SALUD OCUPACIONAL(FINAL).ppt
LUXOMETRO EN SALUD OCUPACIONAL(FINAL).pptLUXOMETRO EN SALUD OCUPACIONAL(FINAL).ppt
LUXOMETRO EN SALUD OCUPACIONAL(FINAL).ppt
 
PLANEACION DE CLASES TEMA TIPOS DE FAMILIA.docx
PLANEACION DE CLASES TEMA TIPOS DE FAMILIA.docxPLANEACION DE CLASES TEMA TIPOS DE FAMILIA.docx
PLANEACION DE CLASES TEMA TIPOS DE FAMILIA.docx
 
Actividades de computación para alumnos de preescolar
Actividades de computación para alumnos de preescolarActividades de computación para alumnos de preescolar
Actividades de computación para alumnos de preescolar
 
Trabajando con Formasy Smart art en power Point
Trabajando con Formasy Smart art en power PointTrabajando con Formasy Smart art en power Point
Trabajando con Formasy Smart art en power Point
 
Análisis de los artefactos (nintendo NES)
Análisis de los artefactos (nintendo NES)Análisis de los artefactos (nintendo NES)
Análisis de los artefactos (nintendo NES)
 
Viguetas Pretensadas en concreto armado
Viguetas Pretensadas  en concreto armadoViguetas Pretensadas  en concreto armado
Viguetas Pretensadas en concreto armado
 
Agencia Marketing Branding Google Workspace Deployment Services Credential Fe...
Agencia Marketing Branding Google Workspace Deployment Services Credential Fe...Agencia Marketing Branding Google Workspace Deployment Services Credential Fe...
Agencia Marketing Branding Google Workspace Deployment Services Credential Fe...
 
certificado de oracle academy cetrificado.pdf
certificado de oracle academy cetrificado.pdfcertificado de oracle academy cetrificado.pdf
certificado de oracle academy cetrificado.pdf
 
LINEA DE TIEMPO LITERATURA DIFERENCIADO LITERATURA.pptx
LINEA DE TIEMPO LITERATURA DIFERENCIADO LITERATURA.pptxLINEA DE TIEMPO LITERATURA DIFERENCIADO LITERATURA.pptx
LINEA DE TIEMPO LITERATURA DIFERENCIADO LITERATURA.pptx
 
La tecnología y su impacto en la sociedad
La tecnología y su impacto en la sociedadLa tecnología y su impacto en la sociedad
La tecnología y su impacto en la sociedad
 
Slideshare y Scribd - Noli Cubillan Gerencia
Slideshare y Scribd - Noli Cubillan GerenciaSlideshare y Scribd - Noli Cubillan Gerencia
Slideshare y Scribd - Noli Cubillan Gerencia
 
#Tare10ProgramacionWeb2024aaaaaaaaaaaa.pptx
#Tare10ProgramacionWeb2024aaaaaaaaaaaa.pptx#Tare10ProgramacionWeb2024aaaaaaaaaaaa.pptx
#Tare10ProgramacionWeb2024aaaaaaaaaaaa.pptx
 
Documentacion Electrónica en Actos Juridicos
Documentacion Electrónica en Actos JuridicosDocumentacion Electrónica en Actos Juridicos
Documentacion Electrónica en Actos Juridicos
 

Bienvenido a la republica independiente de las pruebas unitarias con Core Data

  • 1. Bienvenido a la república independiente de las pruebas unitarias con Core Data Jorge D. Ortiz Fuentes (@jdortiz) Alfonso Alba Garcia (@aalbagarcia) viernes, 8 de marzo de 13
  • 2. Agenda ★ MVC ★ Implementación en Core Data ★ Pruebas Unitarias ★ Desacoplamiento ★ Conclusiones 2 viernes, 8 de marzo de 13
  • 3. El modelo a seguir viernes, 8 de marzo de 13
  • 4. MVC ★ Las vistas las proporciona Apple (aunque nosotros podemos crear lasque necesitemos). ★ El modelo debe contener toda la lógica de negocio. ★ Atención: Modelo de datos vs modelo de negocio. ★ El controlador debería la conexión de las vistas con el modelo de negocio. ★ No es necesario que sea / NO debería ser un singleton. Se pasa de un controlador a otro. (Core Data: MOC o UIManagedDocument) 4 viernes, 8 de marzo de 13
  • 5. Modelo autocontenido ★ La forma más sencilla de evitar duplicación de código y conseguir un comportamiento consistente. ★ Core Data incluye restricciones. P. ej., atributo opcional o no o cardinalidad de una relación. ★ Pero para añadir otra funcionalidad hay que añadir métodos. 5 viernes, 8 de marzo de 13
  • 6. Usa Core Data, Luke viernes, 8 de marzo de 13
  • 7. Implementación del modelo de negocio ★ Modificar modelo de datos ⇒ regenerar clases. Xcode sobreescribe ⇒ métodos añadidos ★ Soluciones: ๏ Aprovechar el control de versiones ๏ mogenerator (http:// rentzsch.github.com/mogenerator/) de W. Rentzsch ๏ Categorías 7 viernes, 8 de marzo de 13
  • 8. Implementación del modelo de negocio ★ Modificar modelo de datos ⇒ regenerar clases. Xcode sobreescribe ⇒ métodos añadidos ★ Soluciones: ๏ Aprovechar el control de versiones ๏ mogenerator (http:// rentzsch.github.com/mogenerator/) de W. Rentzsch ๏ Categorías 7 viernes, 8 de marzo de 13
  • 10. Group (Generado) ★ #import <Foundation/Foundation.h> #import "Group.h" #import "Person.h" #import <CoreData/CoreData.h> @implementation Group @class Person; @dynamic name; @interface Group : NSManagedObject @dynamic notes; @dynamic members; @property (nonatomic, retain) NSString * name; @dynamic meetings; @property (nonatomic, retain) NSString * notes; @property (nonatomic, retain) NSSet *members; @end @property (nonatomic, retain) NSManagedObject *meetings; @end @interface Group (CoreDataGeneratedAccessors) - (void)addMembersObject:(Person *)value; - (void)removeMembersObject:(Person *)value; - (void)addMembers:(NSSet *)values; - (void)removeMembers:(NSSet *)values; @end viernes, 8 de marzo de 13
  • 11. Categoría Group+Model ★ #import "Group.h" #import "Group+Model.h" @implementation Group (Model) #pragma mark - Detect duplicates @interface Group (Model) /** - (BOOL) isDuplicated; Verify that this item doesn't exist yet (another section with the same name). @end */ - (BOOL) isDuplicated { BOOL duplicated = NO; NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Group"]; // Set the predicate to find if another one exists. fetchRequest.predicate = [NSPredicate predicateWithFormat:@"name == %@", self.name]; NSError *error = nil; NSUInteger sections = [self.managedObjectContext countForFetchRequest:fetchRequest error:&error]; // The first one is the one this one. if (sections > 1) { duplicated = YES; } return duplicated; } @end viernes, 8 de marzo de 13
  • 12. Pruebas viernes, 8 de marzo de 13
  • 13. La prueba del 3 ★ Incluir pruebas: ๏ Más exhaustivo y sistemático. ๏ Refactorizar con mucho menos riesgo. ๏ Verificar la resolución de bugs y evitar regresiones. ★ Lo que proporciona el sistema (frameworks) no se prueba. ★ Como mínimo: ๏ Modelo de negocio → Métodos añadidos 12 viernes, 8 de marzo de 13
  • 14. Implementación de las pruebas ★ OCUnit para no compicarse la vida ★ Nombre explicativo ★ Cobertura ★ Casos relevantes ★ Importante para Core Data: setUp y tearDown ๏ Carga del modelo ๏ Preparación del Persistent Store en memoria. 13 viernes, 8 de marzo de 13
  • 15. Preparación ★ - (void) setUp { [super setUp]; // Create the Core Data stack. NSBundle *bundle = [NSBundle bundleForClass:[self class]]; model = [NSManagedObjectModel mergedModelFromBundles:@[bundle]]; coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model]; store = [coordinator addPersistentStoreWithType: NSInMemoryStoreType configuration: nil URL: nil options: nil error: NULL]; context = [[NSManagedObjectContext alloc] init]; [context setPersistentStoreCoordinator:coordinator]; // Instantiate three products for the tests. mainGroup = [NSEntityDescription insertNewObjectForEntityForName:@"Group" inManagedObjectContext:context]; mainGroup.name = @"A cool group"; } - (void) tearDown { context = nil; store = nil; coordinator = nil; model = nil; [super tearDown]; } 14 viernes, 8 de marzo de 13
  • 16. No duplicación ★ #pragma mark - Detect duplication - (void) testDuplicatedIsDetectedWhenTwoGroupsWithSameName { Group *anotherGroup = [NSEntityDescription insertNewObjectForEntityForName:@"Group" inManagedObjectContext:context]; anotherGroup.name = @"A cool group"; STAssertTrue([mainGroup isDuplicated], @"If another group exists with the same name it is considered a duplicate"); } - (void) testDuplicatedIsNotDetectedWhenTwoGroupsWithDifferentName { Store *anotherStore = [NSEntityDescription insertNewObjectForEntityForName:@"Group" inManagedObjectContext:context]; anotherGroup.name = @"Another cool group"; STAssertFalse([mainGroup isDuplicated], @"If no other group exists with a different name it is not considered a duplicate"); } 15 viernes, 8 de marzo de 13
  • 18. This is an open discussion viernes, 8 de marzo de 13
  • 19. Marco Arment “It’s so simple, I’ll just use plist” viernes, 8 de marzo de 13
  • 20. El problema ★ Acoplamiento fuerte entre los componentes de la aplicación (Models, Views, Controllers) ★ Difícil hacer mocks para aplicar TDD ๏ TDD = componentes independientes que se testan de forma independiente entre sí ๏ (¿Mocking de NSManagedObjectContext?) 19 viernes, 8 de marzo de 13
  • 21. El problema ★ Para testear un View Controller que muestra en pantalla un listado de Meetings tendría que: ๏ Crear un NSManagedObjectContext ๏ Cargar datos de prueba en la base de datos ๏ Hacer una búsqueda sobre los datos de prueba ๏ Generar un NSFetchedResultsController ๏ ...y finalmente testear 20 viernes, 8 de marzo de 13
  • 22. El problema ★ ...y después de hacer todo esto, resulta que queremos hacer una versión para Android y compartir datos usando Parse/RoR/PHP/DynamoDB ★ ...o prefieres usar plists para no complicarte la vida (como Marco Arment, pero al revés) 21 viernes, 8 de marzo de 13
  • 23. El problema http://www.confreaks.com/videos/759-rubymidwest2011-keynote-architecture-the-lost-years viernes, 8 de marzo de 13
  • 24. “The database is a DETAIL of our application” viernes, 8 de marzo de 13
  • 25. View Controller Model View (Core Data) Meeting.h viernes, 8 de marzo de 13
  • 26. Como la base de datos es un detalle, la podemos quitar viernes, 8 de marzo de 13
  • 27. Request: quiero ver todos los objetos Meeting View Controller viernes, 8 de marzo de 13
  • 28. Request: quiero ver todos los objetos Meeting View Controller Entidad: Objeto que contiene las MeetingEntity reglas de negocio genéricas, aquellas que se pueden aplicar GroupEntity siempre en cualquier contexto. AttendeeEntity Por ejemplo: Si a un evento se inscriben tres personas, este queda automáticamente confirmado viernes, 8 de marzo de 13
  • 29. Request: quiero ver todos los objetos Meeting View Controller MeetingEntity BrowseMeetingsInteractor GroupEntity AttendeeEntity Interactor: Contiene reglas de negocio específicas Por ejemplo: Dos eventos no pueden tener el mismo nombre viernes, 8 de marzo de 13
  • 30. ¿Y la base de datos? viernes, 8 de marzo de 13
  • 31. Request: quiero ver todos los objetos Meeting View Controller MeetingEntity BrowseMeetingsInteractor GroupEntity AttendeeEntity MeetingsGateway Model (Core Data) viernes, 8 de marzo de 13
  • 32. Request: quiero ver todos los objetos Meeting View Controller Request Object MeetingEntity BrowseMeetingsInteractor GroupEntity AttendeeEntity MeetingsGateway Model (Core Data) viernes, 8 de marzo de 13
  • 33. Request: quiero ver todos los objetos Meeting View Controller MeetingEntity BrowseMeetingsInteractor GroupEntity Request Object AttendeeEntity MeetingsGateway Model (Core Data) viernes, 8 de marzo de 13
  • 34. Request: quiero ver todos los objetos Meeting View Controller MeetingEntity BrowseMeetingsInteractor GroupEntity AttendeeEntity Request Object MeetingsGateway ...accede a Core Data y busca los objetos que cumplen los criterios del RequestObject Model (Core Data) viernes, 8 de marzo de 13
  • 35. Request: quiero ver todos los objetos Meeting View Controller MeetingEntity BrowseMeetingsInteractor GroupEntity Entidades AttendeeEntity MeetingsGateway Model (Core Data) viernes, 8 de marzo de 13
  • 36. Request: quiero ver todos los objetos Meeting View Controller MeetingEntity ResponseObject BrowseMeetingsInteractor GroupEntity Entidades AttendeeEntity MeetingsGateway Model (Core Data) viernes, 8 de marzo de 13
  • 37. Request: quiero ver todos los objetos Meeting View Controller ResponseObject MeetingEntity View BrowseMeetingsInteractor GroupEntity AttendeeEntity MeetingsGateway Model (Core Data) viernes, 8 de marzo de 13
  • 38. show me the code!! viernes, 8 de marzo de 13
  • 39. Duck Typing viernes, 8 de marzo de 13
  • 40. Request: quiero ver todos los objetos Meeting View Controller RequestObjectProtocol ResponseObject MeetingEntity View BrowseMeetingsInteractor GroupEntity AttendeeEntity ResponseObject MeetingsParseGateway Model (Core Data) viernes, 8 de marzo de 13
  • 41. QueryRequestProtocol @protocol QueryRequestProtocol @required @property (nonatomic, strong) NSString *queryString; @property (nonatomic, strong, readonly) NSDictionary *components; @end viernes, 8 de marzo de 13
  • 42. BrowseMeetingsInteractor @interface BrowseMeetingsInteractor : NSObject @property (nonatomic, strong) id<MeetingGatewayProtocol> gateway; - (id<StandardResponseProtocol>) getResponseForRequest: (id<QueryRequestProtocol >)request; @end viernes, 8 de marzo de 13
  • 43. MeetingGateway @class MeetingEntity; @protocol MeetingGatewayProtocol <NSObject> @required - (id)processRequest:(id<QueryRequestProtocol> *)request; - (void)save:(MeetingEntity *)meeting error:(NSError **)error; @end viernes, 8 de marzo de 13
  • 44. viewDidLoad if (!self.fridgeResponse) { IFCoreDataFridgeGateway *gateway = [[IFCoreDataFridgeGateway alloc] init]; gateway.shouldReturnFetchResultsController = false; gateway.context = self.context; self.fridgeInteractor = [[IFViewFridgeInteractor alloc] init]; self.fridgeInteractor.gateway = gateway; self.fridgeResponse = [self.fridgeInteractor getResponseForRequest:self.request]; } if (!self.fridgeItemsResponse) { IFCoreDataFridgeItemGateway *fridgeItemGateway = [[IFCoreDataFridgeItemGateway alloc] init]; fridgeItemGateway.context = self.context; fridgeItemGateway.shouldReturnFetchResultsController = YES; self.fridgeItemsInteractor = [[IFBrowseFridgeItemsInteractor alloc] init]; self.fridgeItemsInteractor.gateway = fridgeItemGateway; IFFridgeItemRequestObject *fridgeItemsRequest = [[IFFridgeItemRequestObject alloc] init]; ; fridgeItemsRequest.queryString = [NSString stringWithFormat:@"fridge-slug= %@",self.request.components[@"slug"] ] ; self.fridgeItemsResponse = [self.fridgeItemsInteractor getResponseForRequest:fridgeItemsRequest]; } viernes, 8 de marzo de 13
  • 45. ¿Cómo cambiamos de CoreData a Parse? viernes, 8 de marzo de 13
  • 46. Request: quiero ver todos los objetos Meeting View Controller RequestObject ResponseObject MeetingEntity View BrowseMeetingsInteractor GroupEntity AttendeeEntity ResponseObject MeetingsParseGateway Mientras la clase MeetingsParseGateway y MeetingsGateway cumplan Cache el mismo protocolo ¡todo Parse (Core Data) funciona! viernes, 8 de marzo de 13
  • 48. Request: quiero ver todos los objetos Meeting View Controller RequestObject ResponseObject MeetingEntity View BrowseMeetingsInteractor GroupEntity AttendeeEntity ResponseObject MeetingsParseGateway Cache Parse (Core Data) viernes, 8 de marzo de 13
  • 49. View Controller RequestObject MockResponseObject MockBrowseMeetingsInteractor Para testear el view controller, basta con tener un Mock del Interactor viernes, 8 de marzo de 13
  • 50. Request: quiero ver todos los objetos Meeting View Controller RequestObject ResponseObject MeetingEntity View BrowseMeetingsInteractor GroupEntity AttendeeEntity ResponseObject MeetingsParseGateway Mientras la clase MeetingsParseGateway y MeetingsGateway cumplan Cache el mismo protocolo ¡todo Parse (Core Data) funciona! viernes, 8 de marzo de 13
  • 51. Request: quiero ver todos los objetos Meeting MockRequestObject ResponseObject MeetingEntity BrowseMeetingsInteractor GroupEntity AttendeeEntity MockGateway viernes, 8 de marzo de 13
  • 52. En la vida nada es gratis... ★ Hay que escribir más código ★ Hay que pensar en interfaces (protocolos) ★ ¿Rendimiento? 51 viernes, 8 de marzo de 13
  • 53. ¿Qué pensáis? 52 viernes, 8 de marzo de 13
  • 54. ¿Qué pensáis? ★ ¿Creéis que tener un sistema de componentes realmente desacoplados es un buen sistema? 52 viernes, 8 de marzo de 13
  • 55. ¿Qué pensáis? ★ ¿Creéis que tener un sistema de componentes realmente desacoplados es un buen sistema? ★ ¿Pensáis que tener un sistema en el que puedo testear sus componentes por separado, es un buen sistema? 52 viernes, 8 de marzo de 13
  • 56. ¿Qué pensáis? ★ ¿Creéis que tener un sistema de componentes realmente desacoplados es un buen sistema? ★ ¿Pensáis que tener un sistema en el que puedo testear sus componentes por separado, es un buen sistema? ★ ¿Pensáis que tener un sistema flexible en el que puedo posponer las decisiones sobre aspectos fundamentales del mismo hasta que realmente las necesito es un buen sistema? 52 viernes, 8 de marzo de 13
  • 57. ¿Qué pensáis? ★ ¿Creéis que tener un sistema de componentes realmente desacoplados es un buen sistema? ★ ¿Pensáis que tener un sistema en el que puedo testear sus componentes por separado, es un buen sistema? ★ ¿Pensáis que tener un sistema flexible en el que puedo posponer las decisiones sobre aspectos fundamentales del mismo hasta que realmente las necesito es un buen sistema? ★ ¿Pensáis que poder sustituir unas componentes por otras es un buen sistema? 52 viernes, 8 de marzo de 13
  • 58. ¿Qué pensáis? ★ ¿Creéis que tener un sistema de componentes realmente desacoplados es un buen sistema? ★ ¿Pensáis que tener un sistema en el que puedo testear sus componentes por separado, es un buen sistema? ★ ¿Pensáis que tener un sistema flexible en el que puedo posponer las decisiones sobre aspectos fundamentales del mismo hasta que realmente las necesito es un buen sistema? ★ ¿Pensáis que poder sustituir unas componentes por otras es un buen sistema? ★ ¿Pensáis que un sistema en el que una buena parte del código se puede autogenerar o reutilizar es un buen sistema? 52 viernes, 8 de marzo de 13
  • 59. Cuando no... ★ Si quieres hacer un prototipo rápido de la applicación ★ Si no quieres hacer TDD, ni desacoplar componentes ni dormir más tranquilo por las noches cuando tu app se la descarguen miles de personas 53 viernes, 8 de marzo de 13
  • 60. ¡Es una inversión de futuro! ¡Gracias! viernes, 8 de marzo de 13
  • 61. Recursos recomendados ★ Architecture: the lost years ★ Test Driven iOS Development ★ www.cleancoders.com/ 55 viernes, 8 de marzo de 13