SlideShare una empresa de Scribd logo
1 de 39
Descargar para leer sin conexión
CocoaHeads Rennes #10
                              Quentin Arnault
     10 mai 2012




        Mock objects, théorie et
             application
Ce que vous allez apprendre


➡   ce que sont les mock objects,

➡   ce qu’ils vous apporteront,

➡   les utiliser grâce à OCMock.
Contexte et
regard sur la POO

                                                       Retour
                                                    d’expérience
                        Photo
                    d’identité et
                     photo de
                       famille
                                    Montre moi du
                                       code !
Contexte et regard sur la POO
plus facile
tests automatisés


                    Contexte ?
    plus efficace                                       outils

                      meilleure maintenabilité
3 niveaux de tests automatisés


       • unitaire,
       • intégration,
       • de bout en bout.                    unitaire
                                                                       intégration

                                                                    qualité du feeback           bout en bout
                                                                     qualité externe     qualité interne
Steve Freeman, Nat Pryce. Growing Object-oriented software, Guided by tests, p11
Back to basics (POO)

➡   Responsabilité : obligation d’accomplir une tâche ou de
    détenir une information

➡   Rôle : ensemble de responsabilités liées entre elles

➡   Objet : implémentation d’un ou plusieurs rôles

➡   Collaboration : interactions d’ objets ou de rôles
C’est à dire
                           Webservice Client


    Responsabilités                      Collaborateurs

➡   construire les requêtes HTTP    ➡    client HTTP

➡   traiter les erreurs HTTP/svc    ➡    parser

➡   informer du résultat            ➡    observateur
HTTP Client
Webservice Client
                    Webservice Client
   Delegate
                                          Parser
...                       ...     ...    ...
      ...


                                                  HTTP
                  ...
                                                   Cl.


                         observ.   W. Cl.



                                                  parser         ...         ...
                   ...



                          ...
...         ...                                                  ...


                                                                       ...
                          ...
...                       ...     ...    ...
      ...


                                                  HTTP
                                                   test
                  ...
                                                  object
                                                    Cl.


                           test
                         observ.   W. Cl.
                          object


                                                   test
                                                  parser         ...         ...
                   ...                            object



                          ...
...         ...                                                  ...


                                                                       ...
                          ...
Photo d’identité et photo de
          famille
objets factices (dummy object)


➡   vient remplacer «bêtement» l’objet de production

➡   mais pas de comportements
objets bouchon (stub object)


➡   vient remplacer un objet de production

➡   retourne des valeurs

➡   comportement souvent partiel
objets allégés (fake object)


➡   vient remplacer un objet de production

➡   contient une implémentation fonctionnelle mais non adaptée à
    la production
mocks objects (mock object)
➡ vient remplacer un objet de production
➡ peut retourner des valeurs (comme les objets bouchons)
➡ contrôle les messages reçus par rapport au contrat prévu
➡ Première phase : enregistrement du contrat
➡ Deuxième phase : enregistrement des messages pendant
     l’exécution du cas de test
Montre moi du code !
Une installation simple
1



2



3
Premiers pas
HTTPClient *httpClient = [[HTTPClient alloc] init];

WebServiceClient *client = [[WebServiceClient alloc] initWithHTTPClient:httpClient];
Premiers pas
id mockClient = [OCMockObject mockForClass:[HTTPClient class]];

WebServiceClient *client = [[WebServiceClient alloc] initWithHTTPClient:mockClient];


[[mockClient expect] prepare];              Enregistrement du contrat


[client fetchUsers];                        Enregistrement des messages

[mockClient verify];
expect
[[mock expect] aMethod];

[[mock expect] aMethodWithParameter:anObject];

[[mock expect] aMethodWithParameter:[OCMArg any]];

[[mock expect] aMethodWithParameter:[OCMArg anyPointer]];

[[mock expect] aMethodWithParameter:[OCMArg isNotEqual:aValue]];

[[mock expect] aMethodWithParameter:[OCMArg checkWithSelector:@selector()
                                                     onObject:anObject]];

[[mock expect] aMethodWithParameter:[OCMArg checkWithBlock:^BOOL(id value){}]];
verify
                                                [mock verify];

Test Suite 'Tests' started.
Starting TestIsLife/test_missing_call
2012-05-10 14:47:49.413 runTests[10490:13303]
! Name: NSInternalInconsistencyException
! File: Unknown
! Line: Unknown
! Reason: OCMockObject[HTTPClient]: expected method was not invoked: prepare
#0 0x1b9a022 __exceptionPreprocess() (/Applications/Xcode.app/Contents/Developer/Platforms/
iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.1.sdk/System/Library/Frameworks/
CoreFoundation.framework/CoreFoundation)
#1 0x1f76cd6 objc_exception_throw() (/Applications/Xcode.app/Contents/Developer/Platforms/
iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.1.sdk/usr/lib/libobjc.A.dylib)
#2 0x1b42a48 +[NSException raise:format:arguments:] (/Applications/Xcode.app/Contents/Developer/
Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.1.sdk/System/Library/Frameworks/
CoreFoundation.framework/CoreFoundation)
#3 0x1b429b9 +[NSException raise:format:] (/Applications/Xcode.app/Contents/Developer/Platforms/
iPhoneSimulator.platform/
...
Blah blah blah
stub
[[mock stub] aMethod];

[[[mock stub] andReturn:aValue] aMethod];

[[[mock stub] andThrow:anException] aMethod];

[[[mock stub] andPost:aNotification] aMethod];

[[[mock stub] andCall:@selector() onObject:anObject] aMethod];

[[[mock stub] andDo:^(NSInvocation *){}] aMethod];
stub
[[[mock stub] andReturn:aValue] aMethod];

[[[mock stub] andPost:aNotification] aMethod];

[[[[mock stub] andReturn:aValue] andPost:aNotification] aMethod];




[[[mock stub] andReturn:aValue] aMethodWithParameter:[OCMArg isNotNil]];

[[[mock stub] andThrow:anException] aMethodWithParameter:[OCMArg isNil]];
id mockClient = [OCMockObject mockForClass:[HTTPClient class]];




➡   permet de préciser les appels de méthodes que l’on attend

➡   ne supporte aucun appel en dehors de ceux définis


    [[mockClient expect] prepare];
    [[[mockClient stub] andReturn:@"tournament"] getBaseUrl];
    [[[mockClient stub] andReturn:@"HTTPS"] getProtocol];
    [[[mockClient stub] setTimeout:10];
id mockClient = [OCMockObject niceMockForClass:[HTTPClient class]];



➡   permet de préciser les appels de méthodes que l’on attend

➡   ignore tous les appels de méthodes non prévus


    [[mock expect] prepare]




    [[mock reject] badMethod]
id mockClient = [OCMockObject partialMockForObject:httpClient];




➡   permet de préciser les appels de méthodes que l’on attend

➡   tout en conservant le comportement de l’objet remplacé




    [[[mock expect] andForwardToRealObject] prepare]
id mockObserver = [OCMockObject observerMock];




➡   permet d’observer des notifications


    [notificationCenter addMockObserver:mockObserver
                                   name:notificationName
                                 object:nil];
    [[mockObserver expect] notificationWithName:notificationName
                                         object:[OCMArg any]]
Retour d’expérience
- (void)test_should_initilize_http_client {
    // arrange
    id mockClient = [OCMockObject mockForClass:[HTTPClient class]];
    [[mockClient stub] setTimeout:[OCMArg any]];
    [[mockClient expect] prepare];
    WebServiceClient *client = [[WebServiceClient alloc]
initWithHTTPClient:mockClient];

    // act
    [client fetchUsers];

    // assert
    [mockClient verify];
}
@property (nonatomic, readonly) id mockClient;

@synthesize mockClient = mockClient_;

- (void)test_should_initilize_http_client {
    // arrange
    [[self.mockClient expect] prepare];
    WebServiceClient *client = [[WebServiceClient alloc]
initWithHTTPClient:self.mockClient];

    // act
    [client fetchUsers];

    // verify
    [self.mockClient verify];
}


- (id)mockClient {
    if (!mockClient_)
        mockClient_ = [ OCMockObject mockForClass:[HTTPClient class]];
        [[mockClient_ stub] setTimeout:[OCMArg any]];
    }
    return mockClient_;
- (void)test_should_initilize_http_client {
    // arrange
    [[self.mockClient expect] prepare];
    WebServiceClient *client = [[WebServiceClient alloc]
initWithHTTPClient:self.mockClient];

    // act
    [client fetchUsers];

    // assert
    [self.mockClient verify];
}
- (void)test_should_initilize_http_client {
    // arrange
    [[self.mockClient expect] prepare];
    WebServiceClient *client = [[WebServiceClient alloc]
initWithHTTPClient:self.mockClient];

    // act
    [client fetchUsers];
}



- (void)setUp {
    [super setUp];

    mockClient_ = nil;
}

- (void)tearDown {
    [super tearDown];

    [self.mockClient verify];
}
Pourquoi les utiliser ?


➡   minimisation des interactions

➡   minimisation de l’exposition de l’état de l’objet testé

➡   tests plus rapide
Ce qu’il m’ont apporté ?

➡   différencier les tests d’état des tests de collaboration

➡   nouvel angle d’analyse d’un design : l’interaction VS la
    classification

➡   l’importance d’avoir des dépendances explicites
Références
➡   http://www.cocoaheads.fr

➡   Steve Freeman, Nat Pryce. Growing Object-oriented software,
    Guided by tests

➡   http:// www.mockobjects.com

➡   http://ocmock.org

➡   http://jamesmead.org/talks/2007-07-09-introduction-to-mock-
    objects-in-ruby-at-lrug/
Écrivez les tests que vous
      voudriez lire.
julien@cocoaheads.fr
  CocoaHeads #10                        thomas.dupont@cocoaheads.fr




Mock objects, théorie et application

   Mail   : quentin.arnault@gmail.com

Más contenido relacionado

La actualidad más candente

Javascript Json artchitecture
Javascript  Json artchitecture Javascript  Json artchitecture
Javascript Json artchitecture zaghir
 
#5 Java EE5 Client Lourd et Smart Client
#5 Java EE5  Client Lourd  et Smart Client#5 Java EE5  Client Lourd  et Smart Client
#5 Java EE5 Client Lourd et Smart ClientGuillaume Sauthier
 
Du JavaScript propre ? Challenge accepted ! @Devoxx France 2013
Du JavaScript propre ? Challenge accepted ! @Devoxx France 2013Du JavaScript propre ? Challenge accepted ! @Devoxx France 2013
Du JavaScript propre ? Challenge accepted ! @Devoxx France 2013Julien Jakubowski
 
Retours Devoxx France 2016
Retours Devoxx France 2016Retours Devoxx France 2016
Retours Devoxx France 2016Antoine Rey
 
Requêtes HTTP synchrones et asynchrones
Requêtes HTTPsynchrones et asynchronesRequêtes HTTPsynchrones et asynchrones
Requêtes HTTP synchrones et asynchronesAbdoulaye Dieng
 
JavaScript pour les développeurs .NET
JavaScript pour les développeurs .NETJavaScript pour les développeurs .NET
JavaScript pour les développeurs .NETThomas Conté
 
Javascript pour les développeurs Java : quels sont les pièges à éviter ?
Javascript pour les développeurs Java : quels sont les pièges à éviter ?Javascript pour les développeurs Java : quels sont les pièges à éviter ?
Javascript pour les développeurs Java : quels sont les pièges à éviter ?FlorianBoulay
 
Javascript ne se limite pas à jquery
Javascript ne se limite pas à jqueryJavascript ne se limite pas à jquery
Javascript ne se limite pas à jqueryneuros
 
Introduction à React JS
Introduction à React JSIntroduction à React JS
Introduction à React JSAbdoulaye Dieng
 

La actualidad más candente (13)

Javascript Json artchitecture
Javascript  Json artchitecture Javascript  Json artchitecture
Javascript Json artchitecture
 
Cours JavaScript
Cours JavaScriptCours JavaScript
Cours JavaScript
 
#5 Java EE5 Client Lourd et Smart Client
#5 Java EE5  Client Lourd  et Smart Client#5 Java EE5  Client Lourd  et Smart Client
#5 Java EE5 Client Lourd et Smart Client
 
Du JavaScript propre ? Challenge accepted ! @Devoxx France 2013
Du JavaScript propre ? Challenge accepted ! @Devoxx France 2013Du JavaScript propre ? Challenge accepted ! @Devoxx France 2013
Du JavaScript propre ? Challenge accepted ! @Devoxx France 2013
 
Retours Devoxx France 2016
Retours Devoxx France 2016Retours Devoxx France 2016
Retours Devoxx France 2016
 
Requêtes HTTP synchrones et asynchrones
Requêtes HTTPsynchrones et asynchronesRequêtes HTTPsynchrones et asynchrones
Requêtes HTTP synchrones et asynchrones
 
C5 Javascript
C5 JavascriptC5 Javascript
C5 Javascript
 
JavaScript pour les développeurs .NET
JavaScript pour les développeurs .NETJavaScript pour les développeurs .NET
JavaScript pour les développeurs .NET
 
Javascript pour les développeurs Java : quels sont les pièges à éviter ?
Javascript pour les développeurs Java : quels sont les pièges à éviter ?Javascript pour les développeurs Java : quels sont les pièges à éviter ?
Javascript pour les développeurs Java : quels sont les pièges à éviter ?
 
Javascript ne se limite pas à jquery
Javascript ne se limite pas à jqueryJavascript ne se limite pas à jquery
Javascript ne se limite pas à jquery
 
Introduction à React JS
Introduction à React JSIntroduction à React JS
Introduction à React JS
 
Spring Batch ParisJUG
Spring Batch ParisJUG Spring Batch ParisJUG
Spring Batch ParisJUG
 
De Java à .NET
De Java à .NETDe Java à .NET
De Java à .NET
 

Destacado

CocoaHeads Rennes #10 : Notifications
CocoaHeads Rennes #10 : NotificationsCocoaHeads Rennes #10 : Notifications
CocoaHeads Rennes #10 : NotificationsCocoaHeadsRNS
 
CocoaHeads Rennes #2 : Xcode 4
CocoaHeads Rennes #2 : Xcode 4CocoaHeads Rennes #2 : Xcode 4
CocoaHeads Rennes #2 : Xcode 4CocoaHeadsRNS
 
CocoaHeads Rennes #4 : la rotation sur iOS
CocoaHeads Rennes #4 : la rotation sur iOSCocoaHeads Rennes #4 : la rotation sur iOS
CocoaHeads Rennes #4 : la rotation sur iOSCocoaHeadsRNS
 
CocoaHeads Rennes #9 : Gestion mémoire, du débutant à l'expert
CocoaHeads Rennes #9 : Gestion mémoire, du débutant à l'expertCocoaHeads Rennes #9 : Gestion mémoire, du débutant à l'expert
CocoaHeads Rennes #9 : Gestion mémoire, du débutant à l'expertCocoaHeadsRNS
 
CocoaHeads Rennes #14: Programmation Responsive par Celedev
CocoaHeads Rennes #14: Programmation Responsive par CeledevCocoaHeads Rennes #14: Programmation Responsive par Celedev
CocoaHeads Rennes #14: Programmation Responsive par CeledevCocoaHeadsRNS
 
CocoaHeads Rennes #16: OHHTTPStubs
CocoaHeads Rennes #16: OHHTTPStubsCocoaHeads Rennes #16: OHHTTPStubs
CocoaHeads Rennes #16: OHHTTPStubsCocoaHeadsRNS
 
CocoaHeads Rennes #1 : Grand Central Dispatch
CocoaHeads Rennes #1 : Grand Central DispatchCocoaHeads Rennes #1 : Grand Central Dispatch
CocoaHeads Rennes #1 : Grand Central DispatchCocoaHeadsRNS
 

Destacado (7)

CocoaHeads Rennes #10 : Notifications
CocoaHeads Rennes #10 : NotificationsCocoaHeads Rennes #10 : Notifications
CocoaHeads Rennes #10 : Notifications
 
CocoaHeads Rennes #2 : Xcode 4
CocoaHeads Rennes #2 : Xcode 4CocoaHeads Rennes #2 : Xcode 4
CocoaHeads Rennes #2 : Xcode 4
 
CocoaHeads Rennes #4 : la rotation sur iOS
CocoaHeads Rennes #4 : la rotation sur iOSCocoaHeads Rennes #4 : la rotation sur iOS
CocoaHeads Rennes #4 : la rotation sur iOS
 
CocoaHeads Rennes #9 : Gestion mémoire, du débutant à l'expert
CocoaHeads Rennes #9 : Gestion mémoire, du débutant à l'expertCocoaHeads Rennes #9 : Gestion mémoire, du débutant à l'expert
CocoaHeads Rennes #9 : Gestion mémoire, du débutant à l'expert
 
CocoaHeads Rennes #14: Programmation Responsive par Celedev
CocoaHeads Rennes #14: Programmation Responsive par CeledevCocoaHeads Rennes #14: Programmation Responsive par Celedev
CocoaHeads Rennes #14: Programmation Responsive par Celedev
 
CocoaHeads Rennes #16: OHHTTPStubs
CocoaHeads Rennes #16: OHHTTPStubsCocoaHeads Rennes #16: OHHTTPStubs
CocoaHeads Rennes #16: OHHTTPStubs
 
CocoaHeads Rennes #1 : Grand Central Dispatch
CocoaHeads Rennes #1 : Grand Central DispatchCocoaHeads Rennes #1 : Grand Central Dispatch
CocoaHeads Rennes #1 : Grand Central Dispatch
 

Similar a CocoaHeads Rennes #10 : Mock Objects

Cocoaheads Paris Nombembre Test unitaires
Cocoaheads Paris Nombembre Test unitairesCocoaheads Paris Nombembre Test unitaires
Cocoaheads Paris Nombembre Test unitairesCocoaHeads France
 
CocoaHeads Toulouse - Xcode et les tests - Epitez
CocoaHeads Toulouse - Xcode et les tests - EpitezCocoaHeads Toulouse - Xcode et les tests - Epitez
CocoaHeads Toulouse - Xcode et les tests - EpitezCocoaHeads France
 
Conception émergente
Conception émergenteConception émergente
Conception émergenteazeau
 
Intégration continue des projets PHP avec Jenkins
Intégration continue des projets PHP avec JenkinsIntégration continue des projets PHP avec Jenkins
Intégration continue des projets PHP avec JenkinsHugo Hamon
 
Intégration Continue PHP avec Jenkins CI
Intégration Continue PHP avec Jenkins CIIntégration Continue PHP avec Jenkins CI
Intégration Continue PHP avec Jenkins CIHugo Hamon
 
Evolutions scub foundation 3.0 = 4.0
Evolutions scub foundation 3.0 =  4.0Evolutions scub foundation 3.0 =  4.0
Evolutions scub foundation 3.0 = 4.0adrienhautot
 
Présentation de Django @ Orange Labs (FR)
Présentation de Django @ Orange Labs (FR)Présentation de Django @ Orange Labs (FR)
Présentation de Django @ Orange Labs (FR)Martin Latrille
 
Démo Gatling au Performance User Group de Casablanca - 25 sept 2014
Démo Gatling au Performance User Group de Casablanca - 25 sept 2014Démo Gatling au Performance User Group de Casablanca - 25 sept 2014
Démo Gatling au Performance User Group de Casablanca - 25 sept 2014Benoît de CHATEAUVIEUX
 
Symfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 PerformantSymfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 PerformantHugo Hamon
 
Ou sont mes beans, contrats et workflows ? WOA et REST: Un changement de ment...
Ou sont mes beans, contrats et workflows ? WOA et REST: Un changement de ment...Ou sont mes beans, contrats et workflows ? WOA et REST: Un changement de ment...
Ou sont mes beans, contrats et workflows ? WOA et REST: Un changement de ment...Jean-Laurent de Morlhon
 
Tests Dinterface SWT
Tests Dinterface SWTTests Dinterface SWT
Tests Dinterface SWTEric Le Merdy
 
Usine logicielle à Orange Labs
Usine logicielle à Orange LabsUsine logicielle à Orange Labs
Usine logicielle à Orange LabsEmmanuel Hugonnet
 
Industrialiser le contrat dans un projet PHP
Industrialiser le contrat dans un projet PHPIndustrialiser le contrat dans un projet PHP
Industrialiser le contrat dans un projet PHPhalleck45
 
BordeauxJUG : Portails & Portlets Java
BordeauxJUG : Portails & Portlets JavaBordeauxJUG : Portails & Portlets Java
BordeauxJUG : Portails & Portlets JavaCamblor Frédéric
 
Softshake 2015 comment tester et optimiser la performance d'un si
Softshake 2015   comment tester et optimiser la performance d'un siSoftshake 2015   comment tester et optimiser la performance d'un si
Softshake 2015 comment tester et optimiser la performance d'un siMarc Bojoly
 
La qualité logicielle et l'intégration continue - Cas concret du projet Cytomine
La qualité logicielle et l'intégration continue - Cas concret du projet CytomineLa qualité logicielle et l'intégration continue - Cas concret du projet Cytomine
La qualité logicielle et l'intégration continue - Cas concret du projet CytomineInterface ULg, LIEGE science park
 

Similar a CocoaHeads Rennes #10 : Mock Objects (20)

Cocoaheads Paris Nombembre Test unitaires
Cocoaheads Paris Nombembre Test unitairesCocoaheads Paris Nombembre Test unitaires
Cocoaheads Paris Nombembre Test unitaires
 
Rapport tp2 j2ee
Rapport tp2 j2eeRapport tp2 j2ee
Rapport tp2 j2ee
 
CocoaHeads Toulouse - Xcode et les tests - Epitez
CocoaHeads Toulouse - Xcode et les tests - EpitezCocoaHeads Toulouse - Xcode et les tests - Epitez
CocoaHeads Toulouse - Xcode et les tests - Epitez
 
HTML5
HTML5HTML5
HTML5
 
Conception émergente
Conception émergenteConception émergente
Conception émergente
 
Intégration continue des projets PHP avec Jenkins
Intégration continue des projets PHP avec JenkinsIntégration continue des projets PHP avec Jenkins
Intégration continue des projets PHP avec Jenkins
 
Intégration Continue PHP avec Jenkins CI
Intégration Continue PHP avec Jenkins CIIntégration Continue PHP avec Jenkins CI
Intégration Continue PHP avec Jenkins CI
 
Evolutions scub foundation 3.0 = 4.0
Evolutions scub foundation 3.0 =  4.0Evolutions scub foundation 3.0 =  4.0
Evolutions scub foundation 3.0 = 4.0
 
Présentation de Django @ Orange Labs (FR)
Présentation de Django @ Orange Labs (FR)Présentation de Django @ Orange Labs (FR)
Présentation de Django @ Orange Labs (FR)
 
Démo Gatling au Performance User Group de Casablanca - 25 sept 2014
Démo Gatling au Performance User Group de Casablanca - 25 sept 2014Démo Gatling au Performance User Group de Casablanca - 25 sept 2014
Démo Gatling au Performance User Group de Casablanca - 25 sept 2014
 
Symfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 PerformantSymfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 Performant
 
Ou sont mes beans, contrats et workflows ? WOA et REST: Un changement de ment...
Ou sont mes beans, contrats et workflows ? WOA et REST: Un changement de ment...Ou sont mes beans, contrats et workflows ? WOA et REST: Un changement de ment...
Ou sont mes beans, contrats et workflows ? WOA et REST: Un changement de ment...
 
Tests Dinterface SWT
Tests Dinterface SWTTests Dinterface SWT
Tests Dinterface SWT
 
Usine logicielle à Orange Labs
Usine logicielle à Orange LabsUsine logicielle à Orange Labs
Usine logicielle à Orange Labs
 
Industrialiser le contrat dans un projet PHP
Industrialiser le contrat dans un projet PHPIndustrialiser le contrat dans un projet PHP
Industrialiser le contrat dans un projet PHP
 
BordeauxJUG : Portails & Portlets Java
BordeauxJUG : Portails & Portlets JavaBordeauxJUG : Portails & Portlets Java
BordeauxJUG : Portails & Portlets Java
 
Softshake 2015 comment tester et optimiser la performance d'un si
Softshake 2015   comment tester et optimiser la performance d'un siSoftshake 2015   comment tester et optimiser la performance d'un si
Softshake 2015 comment tester et optimiser la performance d'un si
 
Présentation PFE: SmartAudit
Présentation PFE: SmartAuditPrésentation PFE: SmartAudit
Présentation PFE: SmartAudit
 
La qualité logicielle et l'intégration continue - Cas concret du projet Cytomine
La qualité logicielle et l'intégration continue - Cas concret du projet CytomineLa qualité logicielle et l'intégration continue - Cas concret du projet Cytomine
La qualité logicielle et l'intégration continue - Cas concret du projet Cytomine
 
Javascript proprement
Javascript proprementJavascript proprement
Javascript proprement
 

Más de CocoaHeadsRNS

CocoaHeads Rennes #14: iOS7 Controllers Transitions
 CocoaHeads Rennes #14: iOS7 Controllers Transitions CocoaHeads Rennes #14: iOS7 Controllers Transitions
CocoaHeads Rennes #14: iOS7 Controllers TransitionsCocoaHeadsRNS
 
CocoaHeads Rennes #13 : Magical Record
CocoaHeads Rennes #13 : Magical RecordCocoaHeads Rennes #13 : Magical Record
CocoaHeads Rennes #13 : Magical RecordCocoaHeadsRNS
 
CocoaHeads Rennes #13 : CocoaPods
CocoaHeads Rennes #13 : CocoaPodsCocoaHeads Rennes #13 : CocoaPods
CocoaHeads Rennes #13 : CocoaPodsCocoaHeadsRNS
 
CocoaHeads Rennes #7 : Intégration continue pour les nuls
CocoaHeads Rennes #7 : Intégration continue pour les nulsCocoaHeads Rennes #7 : Intégration continue pour les nuls
CocoaHeads Rennes #7 : Intégration continue pour les nulsCocoaHeadsRNS
 
CocoaHeads Rennes #6
CocoaHeads Rennes #6CocoaHeads Rennes #6
CocoaHeads Rennes #6CocoaHeadsRNS
 
CocoaHeads Rennes #5 : iOS & Android
CocoaHeads Rennes #5 : iOS & AndroidCocoaHeads Rennes #5 : iOS & Android
CocoaHeads Rennes #5 : iOS & AndroidCocoaHeadsRNS
 
CocoaHeads Rennes #4 : Tests automatisés sur iOS
CocoaHeads Rennes #4 : Tests automatisés sur iOSCocoaHeads Rennes #4 : Tests automatisés sur iOS
CocoaHeads Rennes #4 : Tests automatisés sur iOSCocoaHeadsRNS
 
Cocoaheads Rennes #3 : Bien coder sur iOS
Cocoaheads Rennes #3 : Bien coder sur iOSCocoaheads Rennes #3 : Bien coder sur iOS
Cocoaheads Rennes #3 : Bien coder sur iOSCocoaHeadsRNS
 
CocoaHeads Rennes #3 : Bien débuter sur iOS
CocoaHeads Rennes #3 : Bien débuter sur iOSCocoaHeads Rennes #3 : Bien débuter sur iOS
CocoaHeads Rennes #3 : Bien débuter sur iOSCocoaHeadsRNS
 
CocoaHeads Rennes #2 : Pratiques de développement itératif
CocoaHeads Rennes #2 : Pratiques de développement itératifCocoaHeads Rennes #2 : Pratiques de développement itératif
CocoaHeads Rennes #2 : Pratiques de développement itératifCocoaHeadsRNS
 
CocoaHeads Rennes #1 : internationalisation
CocoaHeads Rennes #1 : internationalisationCocoaHeads Rennes #1 : internationalisation
CocoaHeads Rennes #1 : internationalisationCocoaHeadsRNS
 

Más de CocoaHeadsRNS (11)

CocoaHeads Rennes #14: iOS7 Controllers Transitions
 CocoaHeads Rennes #14: iOS7 Controllers Transitions CocoaHeads Rennes #14: iOS7 Controllers Transitions
CocoaHeads Rennes #14: iOS7 Controllers Transitions
 
CocoaHeads Rennes #13 : Magical Record
CocoaHeads Rennes #13 : Magical RecordCocoaHeads Rennes #13 : Magical Record
CocoaHeads Rennes #13 : Magical Record
 
CocoaHeads Rennes #13 : CocoaPods
CocoaHeads Rennes #13 : CocoaPodsCocoaHeads Rennes #13 : CocoaPods
CocoaHeads Rennes #13 : CocoaPods
 
CocoaHeads Rennes #7 : Intégration continue pour les nuls
CocoaHeads Rennes #7 : Intégration continue pour les nulsCocoaHeads Rennes #7 : Intégration continue pour les nuls
CocoaHeads Rennes #7 : Intégration continue pour les nuls
 
CocoaHeads Rennes #6
CocoaHeads Rennes #6CocoaHeads Rennes #6
CocoaHeads Rennes #6
 
CocoaHeads Rennes #5 : iOS & Android
CocoaHeads Rennes #5 : iOS & AndroidCocoaHeads Rennes #5 : iOS & Android
CocoaHeads Rennes #5 : iOS & Android
 
CocoaHeads Rennes #4 : Tests automatisés sur iOS
CocoaHeads Rennes #4 : Tests automatisés sur iOSCocoaHeads Rennes #4 : Tests automatisés sur iOS
CocoaHeads Rennes #4 : Tests automatisés sur iOS
 
Cocoaheads Rennes #3 : Bien coder sur iOS
Cocoaheads Rennes #3 : Bien coder sur iOSCocoaheads Rennes #3 : Bien coder sur iOS
Cocoaheads Rennes #3 : Bien coder sur iOS
 
CocoaHeads Rennes #3 : Bien débuter sur iOS
CocoaHeads Rennes #3 : Bien débuter sur iOSCocoaHeads Rennes #3 : Bien débuter sur iOS
CocoaHeads Rennes #3 : Bien débuter sur iOS
 
CocoaHeads Rennes #2 : Pratiques de développement itératif
CocoaHeads Rennes #2 : Pratiques de développement itératifCocoaHeads Rennes #2 : Pratiques de développement itératif
CocoaHeads Rennes #2 : Pratiques de développement itératif
 
CocoaHeads Rennes #1 : internationalisation
CocoaHeads Rennes #1 : internationalisationCocoaHeads Rennes #1 : internationalisation
CocoaHeads Rennes #1 : internationalisation
 

CocoaHeads Rennes #10 : Mock Objects

  • 1. CocoaHeads Rennes #10 Quentin Arnault 10 mai 2012 Mock objects, théorie et application
  • 2. Ce que vous allez apprendre ➡ ce que sont les mock objects, ➡ ce qu’ils vous apporteront, ➡ les utiliser grâce à OCMock.
  • 3. Contexte et regard sur la POO Retour d’expérience Photo d’identité et photo de famille Montre moi du code !
  • 4. Contexte et regard sur la POO
  • 5. plus facile tests automatisés Contexte ? plus efficace outils meilleure maintenabilité
  • 6. 3 niveaux de tests automatisés • unitaire, • intégration, • de bout en bout. unitaire intégration qualité du feeback bout en bout qualité externe qualité interne Steve Freeman, Nat Pryce. Growing Object-oriented software, Guided by tests, p11
  • 7. Back to basics (POO) ➡ Responsabilité : obligation d’accomplir une tâche ou de détenir une information ➡ Rôle : ensemble de responsabilités liées entre elles ➡ Objet : implémentation d’un ou plusieurs rôles ➡ Collaboration : interactions d’ objets ou de rôles
  • 8. C’est à dire Webservice Client Responsabilités Collaborateurs ➡ construire les requêtes HTTP ➡ client HTTP ➡ traiter les erreurs HTTP/svc ➡ parser ➡ informer du résultat ➡ observateur
  • 9. HTTP Client Webservice Client Webservice Client Delegate Parser
  • 10.
  • 11. ... ... ... ... ... HTTP ... Cl. observ. W. Cl. parser ... ... ... ... ... ... ... ... ...
  • 12. ... ... ... ... ... HTTP test ... object Cl. test observ. W. Cl. object test parser ... ... ... object ... ... ... ... ... ...
  • 13. Photo d’identité et photo de famille
  • 14. objets factices (dummy object) ➡ vient remplacer «bêtement» l’objet de production ➡ mais pas de comportements
  • 15. objets bouchon (stub object) ➡ vient remplacer un objet de production ➡ retourne des valeurs ➡ comportement souvent partiel
  • 16. objets allégés (fake object) ➡ vient remplacer un objet de production ➡ contient une implémentation fonctionnelle mais non adaptée à la production
  • 17. mocks objects (mock object) ➡ vient remplacer un objet de production ➡ peut retourner des valeurs (comme les objets bouchons) ➡ contrôle les messages reçus par rapport au contrat prévu ➡ Première phase : enregistrement du contrat ➡ Deuxième phase : enregistrement des messages pendant l’exécution du cas de test
  • 18. Montre moi du code !
  • 20. Premiers pas HTTPClient *httpClient = [[HTTPClient alloc] init]; WebServiceClient *client = [[WebServiceClient alloc] initWithHTTPClient:httpClient];
  • 21. Premiers pas id mockClient = [OCMockObject mockForClass:[HTTPClient class]]; WebServiceClient *client = [[WebServiceClient alloc] initWithHTTPClient:mockClient]; [[mockClient expect] prepare]; Enregistrement du contrat [client fetchUsers]; Enregistrement des messages [mockClient verify];
  • 22. expect [[mock expect] aMethod]; [[mock expect] aMethodWithParameter:anObject]; [[mock expect] aMethodWithParameter:[OCMArg any]]; [[mock expect] aMethodWithParameter:[OCMArg anyPointer]]; [[mock expect] aMethodWithParameter:[OCMArg isNotEqual:aValue]]; [[mock expect] aMethodWithParameter:[OCMArg checkWithSelector:@selector() onObject:anObject]]; [[mock expect] aMethodWithParameter:[OCMArg checkWithBlock:^BOOL(id value){}]];
  • 23. verify [mock verify]; Test Suite 'Tests' started. Starting TestIsLife/test_missing_call 2012-05-10 14:47:49.413 runTests[10490:13303] ! Name: NSInternalInconsistencyException ! File: Unknown ! Line: Unknown ! Reason: OCMockObject[HTTPClient]: expected method was not invoked: prepare #0 0x1b9a022 __exceptionPreprocess() (/Applications/Xcode.app/Contents/Developer/Platforms/ iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.1.sdk/System/Library/Frameworks/ CoreFoundation.framework/CoreFoundation) #1 0x1f76cd6 objc_exception_throw() (/Applications/Xcode.app/Contents/Developer/Platforms/ iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.1.sdk/usr/lib/libobjc.A.dylib) #2 0x1b42a48 +[NSException raise:format:arguments:] (/Applications/Xcode.app/Contents/Developer/ Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.1.sdk/System/Library/Frameworks/ CoreFoundation.framework/CoreFoundation) #3 0x1b429b9 +[NSException raise:format:] (/Applications/Xcode.app/Contents/Developer/Platforms/ iPhoneSimulator.platform/ ... Blah blah blah
  • 24. stub [[mock stub] aMethod]; [[[mock stub] andReturn:aValue] aMethod]; [[[mock stub] andThrow:anException] aMethod]; [[[mock stub] andPost:aNotification] aMethod]; [[[mock stub] andCall:@selector() onObject:anObject] aMethod]; [[[mock stub] andDo:^(NSInvocation *){}] aMethod];
  • 25. stub [[[mock stub] andReturn:aValue] aMethod]; [[[mock stub] andPost:aNotification] aMethod]; [[[[mock stub] andReturn:aValue] andPost:aNotification] aMethod]; [[[mock stub] andReturn:aValue] aMethodWithParameter:[OCMArg isNotNil]]; [[[mock stub] andThrow:anException] aMethodWithParameter:[OCMArg isNil]];
  • 26. id mockClient = [OCMockObject mockForClass:[HTTPClient class]]; ➡ permet de préciser les appels de méthodes que l’on attend ➡ ne supporte aucun appel en dehors de ceux définis [[mockClient expect] prepare]; [[[mockClient stub] andReturn:@"tournament"] getBaseUrl]; [[[mockClient stub] andReturn:@"HTTPS"] getProtocol]; [[[mockClient stub] setTimeout:10];
  • 27. id mockClient = [OCMockObject niceMockForClass:[HTTPClient class]]; ➡ permet de préciser les appels de méthodes que l’on attend ➡ ignore tous les appels de méthodes non prévus [[mock expect] prepare] [[mock reject] badMethod]
  • 28. id mockClient = [OCMockObject partialMockForObject:httpClient]; ➡ permet de préciser les appels de méthodes que l’on attend ➡ tout en conservant le comportement de l’objet remplacé [[[mock expect] andForwardToRealObject] prepare]
  • 29. id mockObserver = [OCMockObject observerMock]; ➡ permet d’observer des notifications [notificationCenter addMockObserver:mockObserver name:notificationName object:nil]; [[mockObserver expect] notificationWithName:notificationName object:[OCMArg any]]
  • 31. - (void)test_should_initilize_http_client { // arrange id mockClient = [OCMockObject mockForClass:[HTTPClient class]]; [[mockClient stub] setTimeout:[OCMArg any]]; [[mockClient expect] prepare]; WebServiceClient *client = [[WebServiceClient alloc] initWithHTTPClient:mockClient]; // act [client fetchUsers]; // assert [mockClient verify]; }
  • 32. @property (nonatomic, readonly) id mockClient; @synthesize mockClient = mockClient_; - (void)test_should_initilize_http_client { // arrange [[self.mockClient expect] prepare]; WebServiceClient *client = [[WebServiceClient alloc] initWithHTTPClient:self.mockClient]; // act [client fetchUsers]; // verify [self.mockClient verify]; } - (id)mockClient { if (!mockClient_) mockClient_ = [ OCMockObject mockForClass:[HTTPClient class]]; [[mockClient_ stub] setTimeout:[OCMArg any]]; } return mockClient_;
  • 33. - (void)test_should_initilize_http_client { // arrange [[self.mockClient expect] prepare]; WebServiceClient *client = [[WebServiceClient alloc] initWithHTTPClient:self.mockClient]; // act [client fetchUsers]; // assert [self.mockClient verify]; }
  • 34. - (void)test_should_initilize_http_client { // arrange [[self.mockClient expect] prepare]; WebServiceClient *client = [[WebServiceClient alloc] initWithHTTPClient:self.mockClient]; // act [client fetchUsers]; } - (void)setUp { [super setUp]; mockClient_ = nil; } - (void)tearDown { [super tearDown]; [self.mockClient verify]; }
  • 35. Pourquoi les utiliser ? ➡ minimisation des interactions ➡ minimisation de l’exposition de l’état de l’objet testé ➡ tests plus rapide
  • 36. Ce qu’il m’ont apporté ? ➡ différencier les tests d’état des tests de collaboration ➡ nouvel angle d’analyse d’un design : l’interaction VS la classification ➡ l’importance d’avoir des dépendances explicites
  • 37. Références ➡ http://www.cocoaheads.fr ➡ Steve Freeman, Nat Pryce. Growing Object-oriented software, Guided by tests ➡ http:// www.mockobjects.com ➡ http://ocmock.org ➡ http://jamesmead.org/talks/2007-07-09-introduction-to-mock- objects-in-ruby-at-lrug/
  • 38. Écrivez les tests que vous voudriez lire.
  • 39. julien@cocoaheads.fr CocoaHeads #10 thomas.dupont@cocoaheads.fr Mock objects, théorie et application Mail : quentin.arnault@gmail.com