palmer_TF_00 By Jesse Palmer

This article was excerpted from Testing Angular 2 Applications

In this article, we are going to cover some basic concepts that can be applied to testing Angular 2 applications or any other applications really.

First, let’s briefly discuss why we write tests in the first place.

 

THE BENEFITS OF TESTING

Writing tests helps us maintain and develop our application. It helps us understand the inns and outs of our code better. Writing tests can also expose weaknesses that we didn’t know were there.

Unfortunately, bugs will occur in most software projects. Fixing the code that caused the bug is great, but writing a test as well as fixing the bug helps ensure that the bug does not reappear.

While it may be impossible to have a test for every single test case imaginable, having an appropriate amount of test coverage gives you some reassurance that the application is working properly. Having a decent amount of your code covered also gives you a certain amount of confidence when it comes to refactoring any code in the future.

Not only is it important to write tests, it’s also important to automate those tests.

WHY AUTOMATED TESTING IS IMPORTANT

Manual testing is becoming less common as automated testing has improved in recent years. Automated testing provides a fast and cost effective way to ensure that an application stays fully functional with a high degree of confidence.

Manual testing is good, but it is very expensive. Manual testers often have to follow lengthy scripts that detail each step that must be taken to test a feature. This method of testing scripts is very cumbersome and can be a hassle to maintain. With the benefits of automated testing outweighing the benefits of manual testing, this article will only cover automated testing.

So now that we have some understanding of automated testing, let’s take a look at different software methodologies in order to see which ones would be appropriate for our Angular 2 testing adventures.

ARE WE USING TDD?

Test-Driven Development (TDD) is a software development methodology where you follow the practice of writing tests first before you ever write your first line of code. The idea is that using TDD forces you to write higher quality code because you have to understand the requirements of the feature before you start coding. Whether or not to use TDD is a hot button topic in the software development world.

For rapidly changing, heavily front-end oriented software development, like creating Angular 2 applications, I find it better to write high quality, testable code instead of using TDD. However, I encourage you to try to use TDD in your career and see if it works for you.

HOW ABOUT BDD?

Behavioral Driven Development (BDD) is a style of software development where you are writing your tests in a manor that you expect a user to interact with your software. BDD actually emerged from the practice of TDD. The BDD syntax reads very close to English. An example of a BDD style test case would look something like this:

...
it('clicking on the button should open a new tab', (() => { ...

The test case “clicking on the button should open a new tab” describes the behavior. Don’t worry if this doesn’t mean much to you right now, you will get lots of practice with writing test BDD style. The key takeaway is that we write tests describing an expected behavior.

OVERVIEW OF THE ANGULAR 2 TESTING PROCESS

Let’s explore the testing concepts of Angular 2.


palmer_TF_01

Figure 1 Angular 2 Testing Flow Chart


ANGULAR 2 COMPONENTS

I use the term components in a generic sense to describe each of the different building blocks that Angular 2 includes. These can include components, services, pipes, and directives, forms and more.


Unit Tests and End-to-End Tests

The majority of Angular 2 testing involves two types of tests, Unit Tests and End-to-End Tests (E2E).

UNIT TESTS

Unit tests are written to test the functionality of basic parts or units of code. We can test functions, methods, objects, types, values, and more all with unit tests. The advantages of using unit tests is that they tend to be fast, reliable, and repeatable if they are written correctly and run in a proper environment.

The name of the framework that we will be using to write our unit tests is called Jasmine. Jasmine is a behavior-driven development framework for testing JavaScript code.

Listing 1 shows the code for a very basic unit test written in TypeScript and using the Angular 2 testing module, which includes Jasmine.


Listing 1 Example of Simple Unit Test

import { describe, it, expect } from 'angular2/testing';
describe('super basic test', () => { it('true is true', () => {
 expect(true).toEqual(true); #A
 }
});

#A Sanity check to see if true equals true equals true.


All we are doing in Listing 1 is checking to see that the Boolean value trueis equal to the Boolean value true. This test serves as a Sanity check and nothing more. A Sanity check is a test to see if all of the parts of your testing enivornment are set-up correctly and you are just attempting to get a test to pass. We would not want to add a test this simple to a production application.

An example of a better unit test is if you had a class written and you wanted to test out the getters and setters where updating an instance variable like name; in that case, testing for the getters and setter would be appropriate.

In Listing 2 we write a slightly more sophisticated unit test that tests out the Cat class that we created in our earlier example found in Listing 1.

 


Listing 2 Better example of a Unit Test

import { describe, it, expect } from 'angular2/testing'; import { Cat } from './cat';
describe('Test Cat getters and setters.', () => { it('cat name should be Gracie', () => {
 let cat = new Cat(); cat.setName('Gracie'); let catName = cat.getName();
 expect(catName).toEqual('Gracie');
 }
});

The strengths to writing unit tests tend to be reliable, but are not the best type of test for reproducing user interactions. Each unit test should only test a single repsonibility of the source code.

END-TO-END TESTS

End-to-End tests are used to test the functionality of an application by simulating the behavior of an end user. For example, we may have an end-to-end test that tests whether a modal correctly appears after a form is submitted or a page renders certain elements on page load, such as buttons or text.

End-to-end tests do a very good job with testing the application for an end user’s standpoint, but the performance of end-to-end tests can be slow. Because of this, end-to-end tests can be the source of false positive failing tests due to timing out issues.

Since end-to-end tests are prone to timing issues, it is generally preferred to write unit tests in lieu of end-to-end tests whenever possible.

In testing Angular 2 applications, we use Protractor which is an end-to-end test framework for testing web applications developed by the Angular team. The main benefit of using Protractor is that it allows you to test your application automatically as an end user would in the broweser.

Listing 3 contains a sample end-to-end test written using Protractor that checks the Angular website, angular.io, and ensures that the title of the page is equal to “Angular is a development platform for building mobile and desktop applications – Angular,” which is its current title as of this publication.

 


Listing 3 Example of Simple End-to-End

import { describe, it, expect } from 'angular2/testing'; import { browser } from 'angular2/src/testing/e2e_util';
describe('Angular.io home page test', () => { #A
 it('Title should be correct', (() => { #B
 const angularTitle = 'One Framework. – Angular 2'; expect(browser.get('angular.io').toEqual(angularTitle); #C
 }
}

#A The suite of test that we want to run. In this case, the test involves the Angular home page.

#B The specific test case that we are trying to prove as true.

#C The logic of the test.


If you understand these two types of tests, you will understand the majority of Angular 2 testing.#A The suite of test that we want to run. In this case, the test involves the Angular home page. #B The specific test case that we are trying to prove as true. #C The logic of the test.


Automating the testing process

We will want to automate the process of running all of our tests to make our lives easier. Otherwise we would have to manually execute each script. That might not be hard when you have four or five tests, but when you have hundreds of tests this would be a very cumbersome process.

You can automate the executing of test by using a tool called Karma. Karma was originially developed by the Angular team. Using Karma helps you add testing to the continuous integration / continuous delivery process which saves your organization time and money.

_