unit test patterns for mvc angularjs - agilethought

9
Unit Test Patterns For MVC AngularJS Presented by Michael Cooper, Senior Consultant

Upload: agilethought

Post on 27-Jul-2015

324 views

Category:

Technology


3 download

TRANSCRIPT

Page 1: Unit Test Patterns for MVC AngularJS - AgileThought

Unit Test Patterns For MVC AngularJSPresented by Michael Cooper, Senior Consultant

Page 2: Unit Test Patterns for MVC AngularJS - AgileThought

You know MVC testing patters.

• Sample test patterns assuming we use the MVC pattern (see our previous

slide show)

• Tests using grunt-karma/jasmine and frisby

• We show unit test patterns for Models, Controllers, Services and for testing

the API surface

MVC testing skills can make you an AngularJS expert!

2www.agilethought.com

Page 3: Unit Test Patterns for MVC AngularJS - AgileThought

Testing Models

3www.agilethought.com

RULE: Models are the easiest to test … We should have 100 % test coverage on all models (dto transforms and all functions)!

Another reason to have UI view-models, rather than being lazy and accepting models from the service! Stick to patterns that have stood the test of time!

Underscored convention.

Injects Animal type.

Model Angular Test

angular.module(‘app.models.animal’, []) describe(‘Animal’, function(){.factory(‘Animal’, function (){ var Animal,

animal;var Animal = function(){

this.name = “; beforeEach(‘module(‘app.models.animal’));this.speed = 2; // mph beforeEach(function(){

}; inject(function(_Animal_){Animal = _Animal_;

Animal.prototype.yardsPerSecond = function(){ });return this.speed * 1760 / (60 * 60); });

};return Animal; it(‘ should be fast’, function(){

var cheetah = new Animal();}); cheetah.speed = 40;

expect(cheetah.yardsPerSecond()).toBeCloseTo(19.55);})

});

Page 4: Unit Test Patterns for MVC AngularJS - AgileThought

Testing Controllers

4www.agilethought.com

We prefer ControllerAs syntax!

RULE: controller methods should not rely on $scope. Pass the object.

Controllers are harder to test.

Most injectable objects have to

be mocked.

The magic. We create the controller and substitute the items we mock.

Controller – form for entering animal details Angular Test

angular.module(‘app.newAnimal’, describe(‘NewAnimalController’, function(){[‘app.models.animal’, ‘app.services.zoo’]) var NewAnimalController,

$scope, whatWasSaved;.controller(‘NewAnimalController’,

function NewAnimalController ( $scope, beforeEach(‘module(‘app.newAnimal’));Animal, Zoo ) {

var mockAnimal = ‘goose’;$scope.animal = new Animal (); var mockZoo = {

save: function(animal){$scope.updateAnimal = function(animal){ whatWasSaved = animal;

Zoo.save(animal); }} ; };

});beforeEach(function(){

inject(function($rootScope, $controller){$scope = $rootScope.$new();NewAnimalController = $controller(‘NewAnimalController’,{

$scope: $scope,Zoo:mockZoo

});});

});

it(‘ make your tests here’, function(){Zoo.save(mockAnimal);expect(whatWasSaved ).toBe(mockAnimal );

})

});

Page 5: Unit Test Patterns for MVC AngularJS - AgileThought

Testing Services

5www.agilethought.com

Service – for saving animals by POSTing to a service Angular Test

angular.module(‘app.service.zoo’, describe(‘Zoo’, function(){[‘app.models.animal’, ] var Zoo,

.service(‘Zoo’, function($http){ $httpBackend;beforeEach(‘module(‘app.service.zoo’));

var save = function(animal){ var mockAnimal = ‘goose’;var animalString = angular.toJson(animal);var endpoint = ‘ /myzoo’; beforeEach(function(){

inject(function(_$httpBackend_, _Zoo_){var post = $http({ method: ‘POST’, url: endPoint, data : animalString }); Zoo = _Zoo_;return post; $httpBackend = _$httpBackend_;

};$httpBackend.whenPOST(‘ /myzoo’,

return { .respond(200, mockAnimal );save:save });

} });});

it(‘ Should have saved’, function(){var save = Zoo.save(mockAnimal);save.promise.then(function(response){

expect(response).toBe(mockAnimal );})$httpBackend.flush(); // to cause the post to return

}) ;afterEach(function() { /// this ensures we did not miss any promises

$httpBackend.verifyNoOutstandingExpectation();$httpBackend.verifyNoOutstandingRequest();

});});

});

This is async and will return a promise to the caller.

Services can be tricky to test. If

they call http services, we need

to mock them.

Underscores allows us to use the name we expect. They are stripped by the injector.

The magic. We intercept the $http Post and substitute our own response!

Page 6: Unit Test Patterns for MVC AngularJS - AgileThought

Testing the API Layer

6www.agilethought.com

API Service – for GET-ting animals from a service frisby test – run as a grunt task

/myZoo - gets an array of animals var frisby = require(‘frisby’);

frisby.create(‘Get animals from the dev endpoint’)Remember, an Animal is expect to return JSON like: .get(‘http:/dev/myZoo’)

.expectStatus(200)[

{ .expectHeaderContains(‘content-type’, ‘application/json’)“name”: “Cheetah”,“speed”: 30 .expectJSONTypes(“*”, {

} name: String,] speed; Number

})

.toss();

Lastly – we check that the API gives us the shapes we expect.

We use frisby.js

The magic. We defend the UI against API changes that we might

miss. This will loop through ALL instances in the returned array and check the shape and type of each

property.

Page 7: Unit Test Patterns for MVC AngularJS - AgileThought

Testing

Your MVC skills can make you an AngularJS expert!

References:

• grunt-karma / jasmine: http://jasmine.github.io/2.0/introduction.html

https://github.com/karma-runner/grunt-karma

• frisby: http://frisbyjs.com/

7www.agilethought.com

Page 9: Unit Test Patterns for MVC AngularJS - AgileThought

About Michael

9

Mike Cooper spent much of his career in software sales, development and general management,

with large firms like Reuters and Pitney Bowes, and a series of start-ups. His true love is making

great software, and he has built software for television, finance, construction and government, and

co-founded a number of veteran–owned businesses. He is a consultant at AgileThought,

specializing in AngularJS.

Thank You

@mbcoop

Questions about AngularJS? Email me at [email protected]

linkedin.com/in/michaelcooper