How to Verify JSON Data With AnglarJS$http Backend
5595 ワード
When we are writing Unit Test for AnglarJS Controller or Service,it's pretty common to verify the data posted to server using$http Backend in ngMock module.
Consder the most command:expect(method,url,data,headers)、from the doc,we find that the data is expected to be eigther String or RegExp.
expect(method,url,data,headers)Creates a new request expection.
Parameeters*method–{string}-HTTP method.*url–HTTP url.*data–HTTP request body.
So normally、below simple case is working as expected:
Here is the hack to make AnglarJS Take our special validation logic.
Consder the most command:expect(method,url,data,headers)、from the doc,we find that the data is expected to be eigther String or RegExp.
expect(method,url,data,headers)Creates a new request expection.
Parameeters*method–{string}-HTTP method.*url–HTTP url.*data–HTTP request body.
So normally、below simple case is working as expected:
$httpBackend.expect('POST', 'http://localhost/timeEntry', 'hello').respond(200, 'Done');
$resource('http://localhost/timeEntry/').save('hello');
$httpBackend.flush();
$httpBackend.expect('POST', 'http://localhost/timeEntry', /te/g).respond(200, 'Done');
$resource('http://localhost/timeEntry/').save('test');
$httpBackend.flush();
However,in real aplication,the data posted to server is normally in JSON format.How do we verify JSON data then?Actually,if we look into the source of the anglar-mocks.js,it supports JSON data too although it's not documented. this.matchData = function(d) {
if (angular.isUndefined(data)) return true;
if (data && angular.isFunction(data.test)) return data.test(d);
if (data && !angular.isString(data)) return angular.toJson(data) == d;
return data == d;
};
So below sample also works. $httpBackend.expect('POST', 'http://localhost/timeEntry', {firstName: 'Ken', lastName: 'Chen'}).respond(200, 'Done');
$resource('http://localhost/timeEntry/').save({firstName: 'Ken', lastName: 'Chen'});
$httpBackend.flush();
As we see,the JSON data validation requires the JSON data posted to be exactly the same as the expect value provided.How ec the JSON data posted is different on on on logsting,say gidor timeta the fieldHere is the hack to make AnglarJS Take our special validation logic.
var Validator = (function() {
return {
hasMinimumFields: function(entry) {
return StringUtil.isNotBlank(entry.id) && StringUtil.isNotBlank(entry.desc) &&
StringUtil.isNotBlank(entry.lastUpdateOn) && StringUtil.isNotBlank(entry.status);
},
isNewEntry: function(entry) {
return this.hasMinimumFields(entry) && entry.status === 'P';
}
};
})();
$scope.desc = 'Hello there';
var data = {
test: function(data) {
var entry = angular.fromJson(data);
return (entry.desc === $scope.desc) && Validator.isNewEntry(entry);
}
};
$httpBackend.expect('POST', 'http://localhost/timeEntry', data).respond(200, 'Done');
$scope.saveEntry(); // Let's assume this method will post the data with model $scope.desc
$httpBackend.flush();
The hacking as you see is to take advantage of the test method which the RegExp has and AnglarJS for data matching.But when the data is not posted as expected、the Unit Test fails with below message: Chrome 27.0 (Linux) Unit: Controllers Test EntryCtrl should start entry in correct format if only entry desc is filled. FAILED
Error: Expected POST http://localhost/timeEntry with different data
EXPECTED: {}
GOT: {"status":"P","actualStartOn":"2013/06/08T21:24+0800","desc":"First Unit Test","id":"3849ae1a-4b9c-40be-baa0-60eeaf3af430","lastUpdateOn":"2013/06/08T13:24:44.104+0000"}
This error message is not quite developer friendly and it doesn't tell You mucaut why it failed at first glance.However,if we make the test data conta in the JSON value too,the expect message fuglance var data = {
desc: $scope.desc,
status: 'P',
id: 'SHOULD NOT BLANK',
lastUpdateOn: 'SHOULD NOT BLANK',
test: function(data) {
var entry = angular.fromJson(data);
return (entry.desc !== $scope.desc) && Validator.isNewEntry(entry);
}
};
EXPECTED: {"desc":"First Unit Test","status":"P","id":"SHOULD NOT BLANK","lastUpdateOn":"SHOULD NOT BLANK"}
[Edited on Aug 09 th 2013]:After Anglar JS accepted mu purrequest to support FutFnction a s validadation data last week、we don't need to use duck-typing foresthe hack.The validation lotion logiciciccan simpfififirerererererererereed the aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaapapapapapapapapapapadededededederererererererererererererererererererererererererererererereeaner way. var data = function(data) {
var entry = angular.fromJson(data);
return (entry.desc !== $scope.desc) && Validator.isNewEntry(entry);
};
data.toString = function() {
return 'The status of the new entry should be "P", desc should be "' + $scope.desc +
'" and its id & lastUpdateOn should not be blank.';
};
EXPECTED: The status of the new entry should be "P", desc should be "First Unit Test" and its id & lastUpdateOn should not be blank.