How To Write Automated Tests For Your Ionic App - Part 1

25 July 2015AngularJS, Ionic, Testing, Karma, Jasmine, Protractor

Have you ever wasted hours trying to fix something you broke in your code because you made a change, didn't test it properly, and only find out it's broken days later?

That happened to me recently while working on an Ionic app. I am a big fan of automated testing, but I kept putting it off for my Ionic project because I didn't have time to get familiar with the testing frameworks for Angular. But as these things always go, you'll end up wasting a lot more time trying to fix bugs in the end.

So, to prevent future head-banging-against-desk, I finally took the time to learn how to write and run automated tests for Ionic/Angular apps.

####This tutorial is split up in 3 parts: Part 1 - Introduction to Automated Testing & Frameworks (this post)
Part 2 - Unit Tests With Jasmine & Karma
Part 3 - End-To-End Tests With Jasmine & Protractor

Let's have a look at the types of tests you can write for your apps.

###Unit Tests This kind of test allows you to focus on testing individual units in your code.

Now, what does that mean exactly?

Have a look at the code below, we have a function doLogin that calls a dinnerService and based on the output displays another view or an error message.

function LoginController($state, $ionicPopup, dinnerService) {
    var vm = this;
    vm.doLogin = function () {

        var onSuccess = function () {
            $state.go('my-dinners');
        };

        var onError = function () {
            $ionicPopup.alert({
                 title: 'Login failed :(',
                 template: 'Please try again.'
               });
        };

        dinnerService.login(vm.username, vm.password)
                     .then(onSuccess, onError);
    }
}

We can write 2 tests for this function: one to test a successful login and the other one to test an unsuccessful login.

However, since we are writing Unit Tests, we should make sure that we're not calling dinnerService or any other external dependency. These should be mocked, so that we can focus on only testing the code in the doLogin function.

You should write these tests at the same time you're building the functionality, or even before you start building anything (see Test-Driven-Development).

Unit Tests are fast and reliable because you're testing small pieces of code without external dependencies.

###Integration Tests Integration Tests are useful for testing if your individual units of code are working together as expected.

In the example for Unit Tests we saw that we need to mock the dependencies. For Integration Tests, depending on which units you want to test together, you could still mock certain dependencies, or none at all.

Integration Tests can be slower, and unreliable if you're connecting to external dependencies that are out of your control.

###UI Tests / End-To-End Tests UI tests are a special kind of Integration Test and allow you to test the User Interface of your app through a browser. You can choose to mock the backend, so you can focus on only testing the frontend.

If you want to test all the way from the frontend to the backend of the app, it's called End-To-End testing.

These tests are the slowest to run because you're using the browser and backend services.

It's really up to yourself to decide which tests you want to use and how much of your code should be covered by these tests, but here is a recommendation from Google based on their own experiences.


Next up, let's look at an overview of the frameworks and tools that will help us write and run our tests.

###Jasmine Jasmine is the most popular framework for testing Angular apps. It provides functions to define what we are going to test: describe(), what we expect to happen: it(), and how we check that it was successful or not: expect().

Here is an example of what a unit test in Jasmine would look like. This example is incomplete and simplified, we'll write real unit tests later.

describe("LoginController", function() {
  it("should call login on dinnerService", function () {
      loginController.doLogin();
	  expect(dinnerService.login).toHaveBeenCalled();
  });
});

###ngMock The ngMock (angular-mocks) library is required for injecting modules, services and controllers that need to be tested.

###Karma Karma is a tool built by the Angular team for running unit tests. It launches a browser, reads the tests from a config file, executes them and shows a report in the terminal.

###Protractor

Protractor is an end-to-end test framework for AngularJS applications. Protractor runs tests against your application running in a real browser, interacting with it as a user would.

Protractor is built on top of WebDriverJS and Selenium to automate the browser. You might be familiar with these if you've done UI testing on websites before, but don't worry if you're not, we'll have a look at how to set everything up in Part 3 (coming soon).

In Part 2 of this tutorial we'll have a look at setting up Jasmine and Karma and write some Unit Tests.

WRITTEN BY
profile
Ashteya Biharisingh

Full stack developer who likes to build mobile apps and read books.