iOS UI Unit Test


You may already be familiar with the concept of Unit Testing. However, usually Unit Tests are done for the logic of the application, but not so much for the visual aspects and the user interaction with the application itself. Making sure the user can interact correctly with the app is as important as what the logic of the app itself does, if not more. So how do we test this?


There are some ways to achieve this in different languages, platforms, and technologies. However, if you are developing a native iOS application, there is a simple and effective way to do it. UI unit testing.


UI unit testing is a kind of unit tests that can interact with the app as a user would, tapping on different elements and triggering gestures to ensure the flow of the app is as expected.


So let’s get started with UI unit testing, by creating our first tests and learning how to run them.



Incorporate UI unit testing to your project



First, let’s start by adding the unit tests to our project. If you are creating a new project from scratch, this is really easy to do. Actually, you don’t even have to do anything! By default, both unit tests and UI unit tests are added to a project when it is created on Xcode. You will see during the creation process that the check boxes corresponding to this tests are already marked:






If you wish to add UI unit testing for an existing project it is not much harder. Just go to File -> New -> Target. On this screen just look for “iOS UI Testing Bundle” and add it to your project. Doing so will add a new folder to your project where all UI tests will be included. Pretty simple!





Creating UI Unit Tests



UI Tests will usually be located in their own folder, which by default will be called “projectNameUITests”. Inside this folder, there should already be a file for UI tests. The class that is defined here uses XCTestCase, and should override both the “setUp” and “tearDown” functions. The first test file should come with some comments that explain what those are, but basically “setUp” is called before each test, and “tearDown” is called after each test. You use them for setting the state of the app where your tests should run and doing the cleanup afterward.


Now we come to the main part of UI Unit Test: the tests themselves. We will create a new function for each test we want to do. Note that all test functions should start with “test” since that is how they are recognized as test functions instead of just auxiliary functions.


To start with, it is recommended that you create a var to reference the app itself on the test class, since this will be used many times to retrieve screen elements. This can be done as following:


class TestExamplesUITests: XCTestCase {
   var app: XCUIApplication!
   override func setUp() {
       super.setUp()
       continueAfterFailure = false
       app = XCUIApplication()
       app.launch()
   }
}


You may notice “continueAfterFailure” in the code above. It pretty much does what it says on the tin. It is a boolean value which determines if a test should continue after it fails (and find everything that fails inside that test), or if it should stop and continue with the other tests.


Now we need to create the tests themselves. As with Unit Tests in general, we will create a certain flow for the test to follow and assert that what should happen has happened. The main difference is that, instead of testing pure logic and assert the results, we will interact with screen elements and assert that the screen is updated accordingly.


Here is a really simple example of a UI Unit Test, in which we will tap a button that is on the first screen (identified as “nextButton”) which should navigate to a second screen, and later check that a label (identified as “nextScreenLabel”) is on screen now that the navigation has been performed.


func testNavigateToNextScreen() {
       XCTAssertTrue(app.buttons["nextButton"].exists)
       XCTAssertFalse(app.staticTexts["nextScreenLabel"].exists)
       app.buttons["nextButton"].tap()
       XCTAssertTrue(app.staticTexts["nextScreenLabel"].exists)
   }


As you see, first we check that the button that we want to press exists. No purpose in continuing our test if there is no button to press, right? After that, we check that the label that should only be on the second screen does not currently exist (test should start in the first screen of the App). Then we tap the button and check again if the label is now present. If everything worked correctly, this test should succeed when we run it.


There are other events we can trigger, like gestures on the App itself. For example, to create a swipe event from the user in the app, we can call app.swipeLeft(). It is that simple!
And now let’s see how to run the test and check the results.



Running tests and checking screenshots



As you’d expect, this is not rocket science.





You just need to go to the tab shown in the image above on Xcode and you will see all tests you have created, UI or otherwise. Now hover over any of the tests (or the entire testing bundle) and a “run” icon will appear. Click on it, and there you go! Just a word of warning, UI tests take much longer to run than other Unit Tests since it has to compile the app an emulate it on real time as a user would. But that is a minor price to pay.


After all selected tests have run, you will get an icon with a tick or an x indicating which of them failed and which of them succeeded.


However, this is not where it ends. We can actually see exactly how the app looked in many steps along the way of each test. Just right click on the test you want to examine more carefully, and click on “Jump to report”. You will see something like the following:




Now you just need to click on the “eye” icon at the right of one of the steps that have it, and you will see a screenshot of the app exactly at that moment of the process. Normally screenshots are taken after each interaction, so you should be able to see everything you need.


And there you have it! Here are the basics of UI Unit Testing on iOS on Swift. You should be able to take this basic tutorial and adapt it to your needs with some minor digging to get the exact interactions you need. We also have an example on our GitHub linked down below of the test done above and one extra test using the swipe interaction. Feel free to check it!


Reference


Android services

Android Services

What is a service?



Normally, when trying to execute an operation in Android it is, in some way, related and linked to a user interface. However, sometimes it would be better to run some long operations on the background, and just notify the user at the end. Or maybe just keep something running all the time, such as a music player. For these cases we can use a Service.


A service is a component which runs in the background without a user interface. Services will continue running even if the user changes to another application, ensuring the long operations are not interrupted by mistake.


There are many kinds of services at our disposal on android, so let’s see what are the main differences.


Services types



Started service



This is the basic type of service. It is usually used to perform a single operation, without returning a final result to the caller. It is created when “startService” is called for the first time and will be destroyed when “stopService” is executed. While “startService” can be called many times while the service is still running (and it will execute the “onStartCommand” function every time), it will not be re-created and will be destroyed when the “stopService” is ran for the first time. It does not matter how many times “startService” is called, it will end when “stopService” is executed once.


Started services can either be Sticky or not Sticky. The difference between a sticky and a not sticky service is what happens when the system kills the service. If the service is not a sticky service, it will not be recreated unless there are pending intents to be delivered. Meanwhile, a sticky service will be recreated regardless of if there are pending intents or not. In case there are none, it will be recreated with a null intent.


Not sticky services should be used when the it is possible to re-start the operation if unfinished and necessary, so the system can manage it appropriately. If it is vital that the service keeps running until stopped manually, you can use a sticky service.


There is also a started service called “redeliver intent”, which is useful when doing long operations that shouldn’t be interrupted. In this type of service, when the system kills it it will be re-created using the last intent that was delivered, and will use the pending intents subsequently. This allows for operations to be continued with the same intent instead of cancelling them altogether.


Bound service



Another type of service is the bound service. In this, instead of calling “startService”, when an activity wants to use this service it “binds” to it. The service is created when the first bind is made, and it continues running. This service can be binded to multiple times by different activities. When this service is binded to it returns an object that implements the “IBinder” interface to be used.


When the service is no longer required by an activity that is binded to it, the activity should call “unbind” to that service. After all activities which were bound to the service call “unbind” (meaning there are no more activities binded to this service), the service is destroyed.


Note: Bound Started service



It is possible to have a service that is both bound and started. This can be useful for some really specific situations but it is not commonly used and it normally leads to more confusion and problems than it is worth. Consider if this is exactly what you want before using it.


Scheduled service



A scheduled service is basically what the name suggests. It is a service that is scheduled to run at a later time. This can be done by using the JobScheduler class, and it allows you to set when to run this service, and even conditions to see if the service should be executed or not depending on status of the device when the scheduled time is reached.


Life cycle



A service follows a simple life cycle during its use. This lifecycle is used in both started services and bound services, although they have some differences in the middle. However, the general concept is the same.


First, the service is created. This is done by calling “startService” or “bindService” depending on the type of service. At this point is when it calls the “onCreate” function which can be used for initial setup on either type of service.


Immediately after creation, it starts executing the “onStartCommand” or “onBind” function (depending the case). Here is where the main processing of the service is executed and where it will continue until the service is stopped. In case of bound services, “onBind” will be called every time a new activity binds itself to the service, and “onUnbind” will be called when any activity unbinds itself.


When the service is stopped (either by calling “stopService” or the last “unbind”), the function “onDestroy” is called. Finally the service is shut down and the life cycle comes to an end.


Creating a service



Now let’s see how to actually create a service. For this example we will create a started service, but creating a bound service is not really that different.


To create a service you need to create a new class that extends from “Service”. This will force us to override the method “onBind”, which is for bound services. Since we will now create a simple started service, we can return null here and move on.


Now we can implement the methods we wish. As explained earlier, we can implement “onCreate”, “onStartCommand”, or “onDestroy” depending on what we need. There are others that we could implement but those are not important for this basic tutorial. The one that we should implement to actually have a started service as we want is the “onStartCommand” one. Here is also where we can choose which type of started service we want to create. This is determined by what we return at the end. Return either “START_NOT_STICKY”, “START_STICKY”, or “START_REDELIVER_INTENT”, depending on what you wish to do.


Here you can see the code for creating a started not sticky service:

package com.servicesexample.innuy.servicesexample; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.support.annotation.Nullable; import android.widget.Toast; /** * Created by Innuy. */ public class ExampleService extends Service { @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(this, "Here the service is started", Toast.LENGTH_LONG).show(); return START_NOT_STICKY; } }
What we need to do now is add our new service to the Android manifest. Just add the following line changing the name of the service to yours:


<service android:name=".ExampleService"></service>
The last step is to call this service. For this you just need to create an appropriate intent and call “startService” from an activity as it is shown in the code below:

startService(new Intent(getBaseContext(), ExampleService.class));
And there it goes! If you use the above code you will see the Toast being shown whenever you start the service. To stop this service just call “endService” with an intent of the same service.


Sources

Services Documentation - Android Developers https://developer.android.com/guide/components/services.html


Secondary links:


Ionic - Secure Storage


This post is not meant as a guide nor as a tutorial on how to use storage with Ionic. This post will explain a possible problem you may have when using the Secure Storage plugin as described on Ionic docs. Also, this is a problem that only shows itself on Android and not on iOS, so if you are facing issues on an Apple device this is probably not the problem you are encountering.

‘Native Storage’ and ‘Secure Storage’ plugins



Native Storage and Secure Storage are the two main ways for you to store information on mobile with Ionic, without needing to setup your own database and instead delegating the handling to the OS.


As the name suggests, the latter is normally used when the information to be saved is really sensitive.


This doesn’t mean Native Storage by itself is insecure. Data stored in this way should only be accessible by your app, which leaves it pretty safe in its own right. However, it is still possible to access it if backup of the data is enabled or on an Android device if it is rooted. So, for cases in which security is a top priority, Secure Storage can shine.


But, when using the “Secure Storage” plugin on Android, sometimes it may fail when starting or when using it. It may even delete previously stored information. So now we have to make the decision on which one to use. Before that, however, it would be good to know why this happens, and how often it happens.


Secure Storage on Android



The “Secure Storage” plugin on Android only works correctly when the user has a block screen activated for their device. Be it with a pattern or with a code, the plugin uses the KeyStore associated with the lock to encrypt the data to be safely stored.


What this means for a user using our application with secure storage, is that it will only work if the device has this safety measures in place. If they don’t, the plugin will fail to initialize, and all storage or retrieval operations will subsequently fail.


And this is not the worst case scenario. The worst case scenario comes when the user removes or updates their password or pattern. If this happens, all previously stored information will be basically deleted since the key associated with it will change.


iOS, on the other hand, doesn’t have this problem since it uses KeyChain to store the information with this plugin, and this does not depend on the user actually having security enabled for their device.


Solutions



Now we need to make a decision on what to use, and the answer should change depending on what your App needs. Some options would be the following:


  • If the data to be stored is not sensitive enough, just use Native Storage. It is secure enough for many cases since it needs a special scenario to be compromised.
  • If data is really sensible, and its use can be avoided, you can use Secure Storage. You need to check before using it in case it was deleted, but this will ensure everything is secure.
  • If data is sensible but temporary (as a short session token) you can try using both. Start by using Secure Storage and just default to Native Storage when that fails. This will allow most users to have the full security without annoying the other users. You can also try migrating data from Native Storage to Secure Storage if it is detected through the App that the user activated their screen lock security.
  • If data is sensible, you could also use Secure Storage and actively ask the user to enable screen lock. This will make sure your data is safe and that your app can access it (unless the user later disables it), but it may annoy the user. You also need to check for possible disappearance of data in every storage operation.
  • You could also choose to use neither. You can try using your own database and handle its security on your own. This can be done either mobile or server side, depending on your needs, but remember that this will probably be more time consuming than just using one of the other plugins.

Conclusion



Unluckily there is not a definitive solution for your problem, but it is something important to have in mind when using these plugins. You just need to make sure you know the needs of your app, your users and the information to be stored and make an informed decision.

We hope this quick post was useful to you!




Sources

React Native: Using native code



In this tutorial, we will assume some basic knowledge of Swift and Java, but it is not necessary to follow along.


In my last post, we started with React Native, creating our first project and understanding the basic structure. However, we didn’t get into one of the best features of React Native: being able to easily write native code to get access to native features or simply upgrading the performance.


So we will try writing a small app which will take advantage of native code to add a new contact to the phone on either iOS or Android.

Let’s get started!

Updating from previous code (Ejecting)



First, let’s get a bad part out of the way. We can’t use native code directly if we created our app with “create-react-native-app”, at least not immediately. And that is exactly what we did in the last tutorial. However, this is easy to fix, so don’t worry! We just need to eject our previously created project and we will be good to go.


To eject your project, you will need to have react-native-cli installed, so just run the following command:
yarn global add react-native-cli
#Alternatively you could install this with npm instead if you wish with npm i -g react-native-cli

Once react-native-cli is installed, navigate to your project and run the following command to eject:
npm run eject
You will be prompted to answer some questions to guide the eject process. For this tutorial, we will choose a regular React Native project, and we will use “ContactsProject” as the name for the project.


Lastly just delete the node_modules folder and run “yarn install” and we will be all ready to continue.


One final word about ejecting your project. After doing this you won’t be able to use the QR code as explained in the other post for running the application. Instead, you will need to launch it from the console or from XCode / Android Studio. But this shouldn’t be too much of a deal while continuing your own project.

Connecting with native code



Now that we have our project ready, we can start focusing on the native part. For this tutorial, we will start with a fresh projected as created by create-react-native-app, and ejected as described above.

Connecting with iOS (Swift)



First, we will start by creating a new swift file (we will call it “ContactsManager.swift”) in your project folder that it’s inside the “ios” folder. It is recommended this is done with XCode since you will be immediately prompted to create a bridging header file (“ProjectName-Bridging-Header.h”), which we will need. If you don’t do it this way it can be added later, so don’t worry.

Inside “ContactsManager.swift” let’s add the following code:


import Foundation
import Contacts
@objc(ContactsManager)
class ContactsManager: NSObject {
 
}
We just created a new class called “ContactsManager” which will be where the logic for adding the contact will be done later. One thing to note is the “objc” modifier. React Native will communicate with Objective-C, so this is an extra step to pass Swift code to Objective-C. If you feel more comfortable with Objective-C you can code directly in Objective-C and skip this, but in this tutorial, we will continue with Swift.


Let’s add now add our function to add the new contact. I won’t go into how exactly this function works since we should concentrate more on linking the code than the adding of the contact, but it should be self-explanatory.


Add the following code inside that class:


@objc(addContact:familyName:number:)
 func addContact(name: NSString, familyName: NSString, number: NSString) -> Void {
   
   if #available(iOS 9.0, *) {
     let contact = CNMutableContact()
     
     contact.givenName = name as String
     contact.familyName = familyName as String
     
     contact.phoneNumbers = [CNLabeledValue(
       label:CNLabelPhoneNumberiPhone,
       value:CNPhoneNumber(stringValue:number as String))]
     
     // Saving the newly created contact
     let store = CNContactStore()
     let saveRequest = CNSaveRequest()
     saveRequest.add(contact, toContainerWithIdentifier:nil)
     try! store.execute(saveRequest)
     
   }
 }
We need to use “objc” in the function too. As you can see, the function itself is the same as how we would do it natively. Nothing too complex here.


Now we have all the native code that we would like to run in our React Native app, but how to do it? Well, first we need to indicate the classes and functions we would like to be accessed externally in the JavaScript. For this we will need a bridge file (“ContactsManagerBridge.m”) as follows:


#import <React/RCTBridgeModule.h>
@interface RCT_EXTERN_MODULE(ContactsManager, NSObject)
RCT_EXTERN_METHOD(addContact:(NSString *)name familyName:(NSString *)familyName number:(NSString *)number)

@end
In this, we indicate the class, the methods and the parameters that will be used by our JavaScript code.


The last piece of native code we need is in the bridging header which we created at the start of this section. In that file you just need to indicate that you will be using the Bridge module with this line:


#import <React/RCTBridgeModule.h>
And we are finished with the iOS part. Depending on the version of iOS you are using you may need to modify the .plist to include permission text for using Contact, but that should be easy to fix.


So let’s return to our “App.js” where the application will start. Here, we can use the following code:



import React from 'react';
import { StyleSheet, Button, View } from 'react-native';
import { NativeModules } from 'react-native';
export default class App extends React.Component {
render() {
  return (
    <View style={styles.container}>
        <Button onPress={addContact} title="Add contact"/>
    </View>
  );
}
}
function addContact(){
  let ContactsManager = NativeModules.ContactsManager;
  ContactsManager.addContact('John', 'Doe', '(555) 424-5920');
}
const styles = StyleSheet.create({
container: {
  flex: 1,
  backgroundColor: '#fff',
  alignItems: 'center',
  justifyContent: 'center',
},
});

As you can see, this will just display a simple screen with just one button, and when that button is pressed it will call the “addContact” function. This function is what calls the native code we have been implementing until now. It brings “ContactsManager” from the native modules and calls the function we created before.


And now you are ready! Just run this project, which you can easily do from XCode, and you will see the App. After clicking the button in the middle of the App, a new contact called “John Doe” should be added to the Contacts in your phone.


Connecting with Android (Java)



First, we will start by creating a new Java file in your android project folder (we will call it “ContactsManager.java”). This is where we will write our Java code to be executed by our application.


For our example, we will create a simple class called “ContactsManager”, which will extend ReactContextBaseJavaModule. This allows us to later export this class as a native module to our React Native JavaScript. This class should also override the “getName” method, returning the name by which we will access this module on the JavaScript, as it is shown in the following code:



public class ContactsManager extends ReactContextBaseJavaModule { public ContactsManager(ReactApplicationContext reactContext) { super(reactContext); } @Override public String getName() { return "ContactsManager"; } }


Now we can add our method that we wish to call from the JavaScript. This is done exactly as we would for a native android app. The only difference is that we need to add “@ReactMethod” before the declaration.


Just add the following code to the Java file:


@ReactMethod public void addContact(String firstName, String lastName, String phoneNumber) { Context contetx = getReactApplicationContext(); String strDisplayName = firstName + " " + lastName; String strNumber = phoneNumber; ArrayList<ContentProviderOperation> cntProOper = new ArrayList<ContentProviderOperation>(); int contactIndex = cntProOper.size(); cntProOper.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI) .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null) .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null).build()); cntProOper.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID,contactIndex) .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, strDisplayName) .build()); cntProOper.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI) .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID,contactIndex) .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE) .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, strNumber) .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE).build()); try { ContentProviderResult[] contentProresult = null; contentProresult = contetx.getContentResolver().applyBatch(ContactsContract.AUTHORITY, cntProOper); } catch (Exception exp) { }
}
Since we have finished with preparing the module we need to work on exporting it. For this, we will create a new file (we will call it “ContactsPackage.java”) where we will package modules to be later used in our React Native app. In this, we will create a new class which implements “ReactPackage”. We could add many modules on one package, but for this example, just the one we created before is enough.


Add the following code to the new package file:


public class ContactsPackage implements ReactPackage{ @Override public List<Class<? extends JavaScriptModule>> createJSModules() { return Collections.emptyList(); } @Override public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { return Collections.emptyList(); } @Override public List<NativeModule> createNativeModules( ReactApplicationContext reactContext) { List<NativeModule> modules = new ArrayList<>(); modules.add(new ContactsManager(reactContext)); return modules; } }
Lastly, we need to indicate that this package should be used in our React Native app. For this, we need to open the MainApplication.java file and add our package to the “getPackages” function. The code below shows how this would be done:


@Override protected List<ReactPackage> getPackages() { return Arrays.<ReactPackage>asList( new MainReactPackage(), new ContactsPackage() ); }
With this, we have finished doing everything on the Java side to export and use our custom native module. For this particular example, you should also add the following permission to your AndroidManifest, but this is obviously not needed for other purposes:


<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
So let’s return to our “App.js” where the application will start. Here, we can use the following code:

import React from 'react';
import { StyleSheet, Button, View } from 'react-native';
import { NativeModules } from 'react-native';
export default class App extends React.Component {
render() {
  return (
    <View style={styles.container}>
        <Button onPress={addContact} title="Add contact"/>
    </View>
  );
}
}
function addContact(){
  let ContactsManager = NativeModules.ContactsManager;
  ContactsManager.addContact('John', 'Doe', '(555) 424-5920');
}
const styles = StyleSheet.create({
container: {
  flex: 1,
  backgroundColor: '#fff',
  alignItems: 'center',
  justifyContent: 'center',
},
});
As you can see, this will just display a simple screen with just one button, and when that button is pressed it will call the “addContact” function. This function is what calls the native code we have been implementing until now. It brings “ContactsManager” from the native modules and calls the function we created before.


And now you are ready! Just run this project, which you can easily do from XCode, and you will see the App. After clicking the button in the middle of the App, a new contact called “John Doe” should be added to the Contacts in your phone.


Conclusion



As you can see, incorporating native code into your React Native application is not too complicated. You can write your native code as you normally would and just do some minor bridging inside the project to indicate which functionalities should be called from where.


You may also note (if you followed both the Android and iOS sections) that we have named the module the same in both cases. React Native plays nice enough to know exactly which module to use depending on where the code is running, so you don’t even need to handle the different use for the different platforms.
If you wish to see the example code in more detail, feel free to check our github project.