## Unit Testing Guidelines A unit tests has 3 goals that it should accomplish to test a javascript object: * Checks success, error, and edge cases * Tests as few objects as possible * Demonstrates how an object should be used

With those 3 goals in mind, its important to realize that the variety of AngularJS object types means that the same approach won’t work for each and every object. Since the OpenLMIS-UI coding conventions layout patterns for different types of AngularJS objects, it’s also possible to illustrate how to unit test objects that follow those conventions.

Check out [AngularJS’s unit testing guide](https://docs.angularjs.org/guide/unit-testing), its well written and many of out tests follow their styles.

Here are some general rules to keep in mind while writing any unit tests: * Keep beforeEach statements short and to the point, which will help other’s read your statements * Understand how to use [Spies in Jasmine,](https://jasmine.github.io/1.3/introduction.html#section-Spies) they can help isolate objects and provide test cases

### Defining variables

The version of Jasmine we’re using discourages using the define-block scoped variables as they might be causing memory leaks. In order to prevent that, it is suggested to use ‘this’ as a way of sharing variables between beforeEach, afterEach, inject and it blocks. Keep in mind that closures inside those block will have a different context and thus ‘this’ will refer to a different object. Below are two examples on how to and how to not write unit tests for OpenLMIS.

#### Do

```Javascript describe(‘CustomResource’, function() {

beforeEach(function() {

module(‘custom’);

inject(function($injector) {

this.subjectUnderTest = $injector.get(‘subjectUnderTest’); this.$rootScope = $injector.get(‘$rootScope’);

});

this.expected = ‘expectedString’;

});

describe(‘returnSomething’, function() {

beforeEach(function() {

this.subjectUnderTest.prepareForTest();

});

it(‘should return something’, function() {

var result; this.subjectUnderTest.returnSomething()

.then(function(something) {

result = something; //this.subjectUnderTest won’t be available as we have a different context here

});

this.$rootScope.$apply();

expect(result).toEqual(this.expected)

});

});

afterEach(function() {

this.subjectUnderTest.clearAfterTest();

});

});

#### Don’t

```Javascript describe(‘CustomResource’, function() {

var expected, subjectUnderTest, $rootScope;

beforeEach(function() {

module(‘custom’);

inject(function($injector) {

subjectUnderTest = $injector.get(‘subjectUnderTest’); $rootScope = $injector.get(‘$rootScope’);

});

expected = ‘expectedString’;

});

describe(‘returnSomething’, function() {

beforeEach(function() {

subjectUnderTest.prepareForTest();

});

it(‘should return something’, function() {

var result; subjectUnderTest.returnSomething()

.then(function(something) {

result = something;

});

$rootScope.$apply();

expect(result).toEqual(expected)

});

});

afterEach(function() {

this.subjectUnderTest.clearAfterTest();

});

});