AppWorlds 2014

Overall Impression

Last year there were a lot of companies that concentrate on analytics and HTML5 while this year the trends seem to be more diverse. The companies that caught my eye were

  • Jumio (http://www.jumio.com/netswipe/). Their Netswipe product provides real time Credit/Debit Card number recognition. It’s a card scan by optical card recognition (vs magnetic strip swipe)
  • Appsee (http://www.appsee.com). This company concentrates on A/B testing and they have given me a comprehensive demo of what A/B testing is and what you can do with it
  • Moxtra (www.moxtra.com). This company presented MeetSDK which is an SDK for embedding online meeting experience into custom apps. The experience is similar to Goto meeting or Google hangouts, where in addition to video chat there is a screen sharing capability.

Attended talks

Use A/B testing to build better apps (Chris Beauchamp from Kii)

A/B testing seems to be the next evolutionary step for just collecting metrics. The idea is to control provide optional data, screen presentations and screen flows for real-time users and then collect metrics. A/B testing requires a slightly different development approach and thus most of the talk was broken down into pros and cons of A/B testing.

Pros:

  • Features can be turned on / off instantaneously. A real life example given by Chris describing how he accidentally released one of the features intended for demo purposes and the feature was only taken down 2 weeks later after AppStore approved patch release.
  • Better segmentation. If currently with KISSMetrics we collect data on ALL of the users, A/B testing platforms can only target certain segments of their user base without disrupting the core users.

Cons:

  • QA and dev overhead. When we release support with various flow and display options we must QA these beforehand. With iOS7 and autoupdates it seems like an alternative could be just having each bi-weekly release as an experiment

Agile development for mobile (Crashlytics and Twitter)

Quick and short list of takeaways

  • Releasing a new version of your mobile app bi-weekly is acceptable amongst users. More frequent updates are not.
  • Dogfooding. Using your company employees as beta testers.  While your app is awaiting approval in the app store, you can have a local dogfood release to your fellow coworkers. So, once the app is in the App Store , you might already know the top 10 issues with it and start working on a patch release immediately.
  • In the experience of Twitter mobile dev top most frequent bugs compose 90% of the issues.

Tips on UI Automation of iOS Applications

Automation support for iOS apps is still a relatively new technology and like all other technologies that are still quite not mature it has a lot of challenges. Below I would like to discuss one of such challenges, identifying and accessing individual custom cells inside a UITableView

Let’s say we create a new phone book application and let’s say that the 3 pieces of information that this application stores are: the last and the first name of the contact along with the type of contact that this person is (family, friend, work). The contact type would be displayed in a non-text form (an icon for instance). Let’s also assume that there would be a screen that lists all the contacts that we have in our phone book and that is the screen that we are going to test.

As of right now every table cell is identified via all the text field values augmented inside of them. For example, a cell for John Smith can be accessed via the following statement:

target.frontMostApp().mainWindow().tableViews()["Empty list"].cells()["John Smith"];

The problem with this identification scheme is that potentially it lacks uniqueness. if we have 2 John Smiths we would not be able to distinguish between the two cells. Moreover, what if one John Smith is classified as family while the other one is a friend, we cannot query how these contacts are classified since these values are non textual

This is when accessibilityLabel property comes to our rescue. In our example, we want to encode 2 non-textual values in the accessibilityLabel. By using the following formula to generate accessibilityLabel for {record unique id},{contact type description} not only do we generate unique identifiers for the table cells but we can now query the contact type of the corresponding record for the cell. In our example the two accessibilityLabel values for the 2 John Smiths (assuming their unique record ids are 1 and 2 respectively) could be accessed via the following statements:

   target.frontMostApp().mainWindow().tableViews()["Empty list"].cells()["1,family"]; 
   target.frontMostApp().mainWindow().tableViews()["Empty list"].cells()["2,friend"];

The native code for creation of cells would look something like this

-(UITableViewCell *) tableView:(UITableView *) tableView cellForRowAtIndexPath:(NSindexPath *) indexPath  
{ 
   UITableViewCell * res = … 
   Contact * c = … 

   //initialize an instance of UITableViewCell 
   //get an instance of Contact that corresponds to the indexPath 
   NSMutableString * accessibilityLabel = [[NSMutableString alloc] init]; 
   [accessibilityLabel appendFormat:@"%d", c.contactId]; 
   if(c.contactType == ContactTypeFriend) 
   { 
      [accessibilityLabel appendString:@",friend"]; 
      res.imageView.image  = [UIImage imageNamed:@"friendsIcon"]; 
   } 
   else if(c.contactType == ContactTypeFamily) 
   { 
     [accessibilityLabel appendString:@",family"]; 
     res.imageView.image  = [UIImage imageNamed:@"familyIcon"]; 
   } 
   else 
   { 
     [accessibilityLabel appendString:@",work"]; 
     res.imageView.image  = [UIImage imageNamed:@"workIcon"]; 
   } 
   res.acessibilityLabel  = accessibilityLabel; 
   [accessibilityLabel release]; 

   return res; 
}

If we want to access a cell for a contact with a known record id but unknown status we would need to write some additional JavaScript code

function findCellByRecordId(recordId)
{
   var cells = target.frontMostApp().mainWindow().tableViews()["Empty list"].cells();
   for(var i=0; i < cells.length; i++) 
   { 
      var cell = cells[i]; 

      //parse the name and check the first part 
      var cellNameParts = cell.name().split(","); 
      if(cellNameParts[0] == ("" + recordId)) 
      { 
         return cell; 
      } 
   } 

   //at this point we did not find anything 
   return null; 
}

Now we have means to locate cells based on contact unique record id, we would want to have an ability to see query what kind of contact type this cell shows

function getRecordTypeFromCell(cell)
{
   return cell.name().parts[1];
}

Now that you can access cells based on the unique record id of the contact that these cells represent as well as the ability to query the status of the contact, you can start writing automated tests for this screen. Happy unit testing!

Note: download sample Phone Book project