Thursday, May 15, 2014

Testing without design footprint

Using OCMock for iOS test

Using mock libraries ease your unit testing in isolation. But as discussed in my previous post, we may end-up with a test oriented (over) layered design. Let's see how to test in isolation using mock but still leave a minimal footprint on your design.

Do your tests:

without checking everything


When a mock object receives a message that hasn't been either stubbed or expected, it throws an exception immediately and your test fails. This is called a strict mock behavior and this is just a pain...

Checking behavior rather than state, you want to write test easy to understand. Using nice mock, any type helps.

NOTE: What is the difference between expect and stub?
You may want to check the original post from Martin Fowler on Mock aren't Stubs.

TD;DR; You expect things that must happen, and stub things that might happen. In OCMock context, when you call verify on your mock (generally at the end of your test), it checks to make sure all of the methods you expected were actually called. If any were not, your test will fail. Methods that were stubbed are not verified.

Here we want to check the OAuth2 HTTP protocol.

        it(@"should issue a request for exchanging authz code for access token", ^{
            __block BOOL wasSuccessCallbackCalled = NO;
            void (^callbackSuccess)(id obj) = ^ void (id object) {wasSuccessCallbackCalled = YES;};
            void (^callbackFailure)(NSError *error) = ^ void (NSError *error) {};
            
            id mockAGHTTPClient = [OCMockObject mockForClass:[AGHttpClient class]]; // [1]
            NSString* code = @"CODE"; 
            
            AGRestOAuth2Module* myRestAuthzModule = [[AGRestOAuth2Module alloc] initWithConfig:config client:mockAGHTTPClient]; // [3]
            
            NSMutableDictionary* paramDict = [@{@"code":code, @"client_id":config.clientId, @"redirect_uri": config.redirectURL, @"grant_type":@"authorization_code"} mutableCopy];
            
            [[mockAGHTTPClient expect] POST:config.accessTokenEndpoint parameters:paramDict success:[OCMArg any] failure:[OCMArg any]]; // [2]
            
            [myRestAuthzModule exchangeAuthorizationCodeForAccessToken:code success:callbackSuccess failure:callbackFailure];
            
            [mockAGHTTPClient verify];
            [mockAGHTTPClient stopMocking];
        });


In [1], we create a mock with an expectation [2], the important part for the test is checking URL endpoint and parameters, for the other arguments I'll simply put any type: [OCMArg any].

without Dependency Injection


In the previous example, in [3] we see an example where we inject our mock within a real object. there is some cases where DI is not easy, could we still mock without injecting?

For example here I want to mock the following call [[UIApplication sharedApplication] openURL:url] within the method under test requestAuthorizationCodeSuccess:failure:, here is a way to
        it(@"should issue a request for authz code when no previous access grant was requested before", ^{
            __block BOOL wasSuccessCallbackCalled = NO;
            void (^callbackSuccess)(id obj) = ^ void (id object) {wasSuccessCallbackCalled = YES;};
            void (^callbackFailure)(NSError *error) = ^ void (NSError *error) {};
            
            //given a mock UIApplication
            id mockApplication = [OCMockObject mockForClass:[UIApplication class]];
            [[[mockApplication stub] andReturn:mockApplication] sharedApplication];
            [[mockApplication expect] openURL:[OCMArg any]];
            
            AGRestOAuth2Module* myRestAuthzModule = [[AGRestOAuth2Module alloc] initWithConfig:config];
            [myRestAuthzModule requestAuthorizationCodeSuccess:callbackSuccess failure:callbackFailure];

            [mockApplication verify];
            [mockApplication stopMocking];
        });


without splitting my classes in several layers


Without debating "one class should do one thing only" suppose, you have a class with several methods, you want to test one method and mock the other ones.

Here requestAccessSuccess:failure: method delegate its call to either refreshAccessTokenSuccess:failure: or exchangeAccessTokenSuccess:failure: depending if an access token and expiration date are present.

       
        it(@"should issue a refresh request when access token has expired", ^{
            
            void (^callbackSuccess)(id obj) = ^ void (id object) {};
            void (^callbackFailure)(NSError *error) = ^ void (NSError *error) {};
            
            restAuthzModule.session.accessTokens = @"ACCESS_TOKEN";
            restAuthzModule.session.refreshTokens = @"REFRESH_TOKEN";
            restAuthzModule.session.accessTokensExpirationDate = 0;
            
            // Create a partial mock of restAuthzModule
            id mock = [OCMockObject partialMockForObject:restAuthzModule];
            
            [[mock expect] refreshAccessTokenSuccess:[OCMArg any] failure:[OCMArg any]];
            
            [restAuthzModule requestAccessSuccess:callbackSuccess failure:callbackFailure];
            
            [mock verify];
            [mock stopMocking];
        });


I guess you got the idea. Test, whatever you need to test, don't go to close to the implementation.
Some may call it TDD vs. BDD, but I simply go: "Use what works best for you".

Wednesday, May 14, 2014

Is TDD dead for real?

After all the buzz around #isTDDDead on twitter, reading post from dhh, listening to RailsConf 2014 keynote, watching live streaming debate, I'm back coding. And I wonder...

After quite a few years spent in the trenches of XP, working with PowerMock/EasyMock/Mockito and all *Mock* pattern libraries, strong advocate of isolation testing, following test pyramid approach, automate testing at all layers as guide, what is this #isTDDDead all about?

It's not about automating test, it's not about unit test, both still seeing as a useful tool for developers. It's more about test first approach whatever your do, it's about 80% coverage criteria, it's about management measurement to make you feel sorry about your "dirty dirty code" (quoting dhh here). Wanting to unit test whatever it costs ie: overuse of mocks, dependency injection or single responsibility principle, refactoring code to make it testable. Test first approach and mockc overuse can lead to too-much layered design. Code where a class is doing just one single little thing and you need to dig deeper to eventually know what's it's all about. Cleaner code? Not so sure...

Back to code, today writing objective-C (I wish I can write french poetry too), I want to unit test my OAuth2 flow, guess what? I need to use mock. And you know what, I'll use OCMock, it might be in a different way though.

I can sleep happy, TDD is not dead or maybe it is but it's more like a Phoenix.

Back to code.

Sculpte, lime, cisèle;
Que ton rêve flottant
Se scelle
Dans le bloc résistant !


Friday, April 25, 2014

First edition of DevFest in Marseille

I always loved to be part of local events. We've got great speakers/developers in PACA too :) but DefFest wasn't just a local event, it also gathered people from abroad, travelling just to share with you their experience and passion.

DevFest started with a very very special keynote from Cedric Atangana. Martin Görner from Google took over. With a Google world map, and GDG groups pinned all over.

I sticked to the mobile sandbox stack, all presentations were great! Seen a few tricks and tips on Android and Android Studio. <3 <3 <3

It was also a great opportunity for me to meet two other Duchess: Isabelle from Limoges and Ludwine from Paris.

My only regret? I had to miss Ludwine's talk as mine was scheduled at the same time. And for those who missed mine, here the slides ;).



Thursday, April 3, 2014

New iOS7 love for AeroGear libs

AeroGear iOS 1.5.0 is out!

Bye bye iOS 5/6 (gone all the hooks to cater for version bugs), we love iOS7!

Spring cleaning obliged, another important shift for this release was the move from AFNetworking 1.x series to AFNetworking 2.x. Going forward, this move will allow us to take advantage some of the new capabilities provided by AFNet, such as the support of pluggable serializers. Although the move needed a significant internal refactoring on our libraries, the interfaces stay the same. The only minor noticeable change is the usage of progress bar in pipe. Check out our recipe Shoot on cookbook to see new usage.

Still internal refactoring, aerogear-push-ios-registration went lighter in its dependencies, removing its usage of AFNetworking and relying only on the native networking facilities provided by iOS (based on NSURLSession). The lighter the better :)

Last but not least, our aerogear-crypto-ios 0.2.3 also got its internal refactoring :) Symmetric encryption has moved away from Common Crypto to now rely on NaCl libs exclusively and is now in par with our asymmetric encryption support. Be aware though, the old crypto format is incompatible with the new version, and you will need to dump and reload the data on your encrypted store. We believe though, that moving forward and relying on NaCl, will offer us much greater crypto advantage. Check out the excellent blog post from my friend abstractj to know all the motivation behind this move.

Now you're impatient to check out all the new stuff, those are the links and numbers (you can find them on cocoapods):
  • aerogear-ios 1.5.0
  • aerogear-ios-xcode-template 1.5.0
  • aerogear-crypto-ios 0.2.3
  • aerogear-push-ios-registration 0.9.0
  • aerogear-otp-ios 1.0.1

  • And off course all the cookbook recipes associated to the libs have been updated.
    Stay tuned, check our roadmap, try it, use it and join the fun: contribute.

    ++
    Christos and Corinne are the guys behind it with the help of our crypto guy Abstractj and our bug-tracker Tadeas.

    Tuesday, April 1, 2014

    Greach 2014, a surprising edition !




    "Join the order of the Groovy knights" drawing is the first Greach sight I bumped into. It gives you the atmosphere of the conference ;)

    A bit sad that this year I had to miss the speakers diner (I've heard good feedback though)... But right on time to give our presentation "Hybrid mobile app in minutes, not day: fast and furious II" with Sebastien and Fabrice. The presentation is sub-titled fast and furious II, because it’s the second year, the 3 musketeers present a mobile talk at Greach.

    We demoed and delved into the details of:


  • AeroGear Scaffolding plugin: lightweight css with topcoat, MVC by Spring cujo, plumbing done with AeroGear Pipe, Store, including AeroGear Unified Push Server client registration.
  • Grails AeroGear UP plugin. A Grails Plugin for sending Push Notifications to the AeroGear UnifiedPush Server.
  • new lib: Sync lib

  • Waiting for Greach sessions to be available, here is a short screencast on how easy to use AeroGear Scaffolding plugin



    Great Greach again,
    Greach is over, but Greach will be back!
    ++ Corinne

    Sunday, March 23, 2014

    AeroGear hackergarten with RivieraJUG

    Last Saturday was hacker day for a bunch of geeks:

    Andrew,
    Arun,
    Yacine,
    Laurent,
    Przemyslaw - missing from the selfie :(
    Fabrice,
    Sebi,
    Gilles,
    Lulu and me.

    Start with a coffee and croissant: the French way. Great opportunity to make acquaintance. It's always a pleasure to meet new faces and greet old buddies.

    Going to meeting room with an introduction on AeroGear by Sebastien and a presentation of the different TODOs. Very interactive talk, with some live coding demo app.

    Forming the teams: whether your a Java dev, a JavaScript hacker or even an iOS lover, you'll find your way. That's part of fun with mobile dev.

    End of the day is always coming too soon but as a reward Push team managed to hack a Cordova what'sapp with Push notification using cordova push plugin. Really cool UI, using ionic fwk. Delving into KeyCloak using iOS AeroGear sdk was fun bit too.

    If you want to know more about those hackings, stay tuned, I've heard some details blog post should come...

    Big thanks to my friend Sebastien Blanc for taking care of all the organisation to and to Les Satellites for hosting us.

    Tuesday, February 25, 2014

    Mobile & Synchronisation - part 2 / 3

    Last blog post I talked about the different approaches to mobile synchronisation. In this article, I will focus on synchronisation without prior context. With two data sets, let's say my local data set (data on my offline mobile) and a remote data set (data from the remote server, changed by other users of my mobile app), that are out of sync after an offline period. I want to be able to get a difference from those two. In this approach, we don't have any prior context. Information like when was the last synchronisation, what happened during offline (logs etc...) is not available.

    Bloom Filter

    A Bloom filter is a data structure designed to tell you, rapidly and memory-efficiently, whether an element is present in a set. You basically compare 2 hashed codes, because of the nature of hash function you can tell an element is either definitely not in the set or may be in the set.

    Invertible Bloom Filter (IBF): Let Magic Happen

    For the purpose of synchronisation, we want to know which elements were added and which ones were removed. Replacing a set of hashed values by a more complete data structure we can achieve a clever filter. Instead of storing hashed values, we can use Bucket structure adding information like number of items, key of the item, and hashed value of the item. Using the magic XOR operator with its reversibility nature. We can xor a sum of element together.

    xor 2 elements together, xor again and you get our initial element!

    Hashing into buckets

    In a bucket, the number of items is increased by one, each time we add an item in the bucket. The key is xored with the other keys. A hash function is used to hash the key into an hashed value, itself xored to the hashed sum.

    With this same technique, you can spread hashed items into different buckets increasing odds to compare them. The bucket distribution should be uniform and reproducible on both sides (local client and remote server in our exemple).



    Using recursive approach, incrementing bucket numbers each time, we build buckets set locally and remotely. With 2 sets, we compute the difference subtracting number of items. In the difference, if the count of elements is 1, we know one element was added (similarly if the count is -1, one element was removed). From the key element, we can hash it, xor it to the hash sum bucket field and get the hashed sum without it (because of the xor reversibility).

    Compute difference

    The whole purpose of the algorithm is to get a difference with number of item -/+1. You can iterate until you get to that point increasing by 2^level.



    How to treat difference

    Let's say, I have an item "green circle" that was hashed and spread into 3 different buckets (3 being the default number of hashed functions used for distributing items into buckets). With this difference set, I'm looking for item number equal to 1. I know the green circle was added, so I can removed it from the buckets index 1, 4 and 6 and add it to the set of added items. In index 2, the number of items is 2, so we carry on to index 3. I can remove blue circles from index 3, 4 and 5. etc... At the end of iteration, if I get an empty difference set, I've retrieved of differences. If the set is not empty, I don't have enough information so I need to increase numbers of buckets.



    Implementation

    Using "What’s the Difference? Efficient Set Reconciliation without Prior Context" paper, 3musket33rs libraires implements the IBF algorithm in Java, JavaScript and iOS.

    The different players: Resolver is responsible of computing difference, increasing number of bucket (level) as needed. Set of buckets are called Summary. Summary comparaison produces Difference which hold removed and added set. BucketSelector produces a set of hash functions to uniformly distribute items with buckets. Bucket is the data structure to hold number of items, xored key and xored hashed value.

    Want to see it in action? See my next blog post for an example involving JavaScript backend and iOS client.