我正在尝试测试使用$http
var APIClient = function($http) {
this.send = function(data) {
$http({
method: data.method,
url: data.url,
headers: data.headers,
data: data.data
}).success(function(response, status) {
data.success(response, status);
}).error(function(response, status) {
data.error(response, status);
});
}
}
angular.module('api.client', []).factory('APIClient', ['$http'
function($http) {
var client = new APIClient($http);
return {
send: function(data) {
return client.send(data);
},
}
}
]);
和测试
describe('send', function() {
var apiClient, $httpBackend;
beforeEach(module('compare'));
beforeEach(inject(function($injector) {
$httpBackend = $injector.get('$httpBackend');
apiClient = $injector.get('APIClient');
}));
it('Should check if send() exists', function() {
expect(apiClient.send).toBeDefined();
});
it('Should send GET request', function(done) {
var url = '/';
$httpBackend.expect('GET', url).respond({});
apiClient.send({
url: url,
success: function(data, status) {
console.log(status);
done();
},
error: function(data, status) {
console.log(status);
done();
}
});
$httpBackend.flush();
});
});
但我总是有这个错误
PhantomJS 1.9.8 (Mac OS X) send Should send GET request FAILED
Error: Unexpected request: GET templates/test.html
Expected GET /
预期的网址始终是我app.js
中的最后一个状态
在这种情况下
// Ionic Starter App
// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
// 'starter.services' is found in services.js
// 'starter.controllers' is found in controllers.js
angular.module('compare',
[
'ionic',
'manager.user',
'api.client',
'api.user',
'api.compare',
'user.controllers',
'test.controllers'
]
)
.run(function ($ionicPlatform) {
$ionicPlatform.ready(function () {
// Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
// for form inputs)
if (window.cordova && window.cordova.plugins && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
}
if (window.StatusBar) {
// org.apache.cordova.statusbar required
StatusBar.styleLightContent();
}
});
})
.config(function ($stateProvider, $urlRouterProvider) {
// Ionic uses AngularUI Router which uses the concept of states
// Learn more here: https://github.com/angular-ui/ui-router
// Set up the various states which the app can be in.
// Each state's controller can be found in controllers.js
$stateProvider
// setup an abstract state for the tabs directive
.state('tab', {
url: "/tab",
abstract: true,
templateUrl: "templates/tabs.html"
})
// Each tab has its own nav history stack:
.state('tab.dash', {
url: '/dash',
views: {
'tab-dash': {
templateUrl: 'templates/tab-dash.html',
controller: 'DashCtrl'
}
}
})
.state('subscription', {
url: '/subscription',
templateUrl: 'templates/subscription.html',
controller: 'SubscriptionCtrl'
})
.state('login', {
url: '/login',
templateUrl: 'templates/login.html',
controller: 'LoginCtrl'
})
.state('test-compare', {
url: '/test/compare',
templateUrl: 'templates/test.html',
controller: 'TestCompareCtrl'
})
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/login');
});
我不明白为什么网址正在改变我正在提供/
并且测试templates/test.html
这始终是最后一个状态模板
答案 0 :(得分:6)
你的主要问题是这一行:
beforeEach(module('compare'));
您正在此处加载整个应用,而不仅仅是apiClient。从本质上讲,您正在进行全面的集成测试,而不是单元测试。
您应该只加载api.client
。
beforeEach(module('api.client'));
有用的东西要注意,你也可以这样做:
$httpBackend.whenGET(/templates\/(.*)/).respond('');
基本上忽略了由路由器,控制器或指令加载的所有模板。如果你这样做,它仍然不会被视为单元测试,因为你没有严格测试你的APIClient
。
另一个有用的说明:
你在.run
或.config
内执行的任何内容都不应该是匿名函数,这样你就可以嘲笑它。
这样做的一个例子是:
.config(CompareStateLoader);
CompareStateLoader.$inject = [
'$stateProvider',
'$urlRouterProvider'
];
function CompareStateLoader(
$stateProvider,
$urlRouterProvider
){
//configure states here
}
执行此操作将允许您模拟CompareStateLoader
并将其加载到测试运行器中。
有关这方面的更多信息,请参阅John Papa的角度风格指南here。
答案 1 :(得分:2)
我建议将所有模板编译成JS文件(例如使用grunt&#34; html2js &#34;任务或业力预处理器&#34; ng-html2js < / strong>&#34;)并且对GETing模板没有头痛。
或者您也可以使用 passThrough
$httpBackend.when('GET', /\.html$/).passThrough()
示例 - http://plnkr.co/edit/pbjcDl?p=preview
但我建议使用第一个选项。
答案 2 :(得分:0)
var apiClient, $httpBackend, $loc;
beforeEach(module('compare'));
beforeEach(inject(function($injector, $location) {
$httpBackend = $injector.get('$httpBackend');
apiClient = $injector.get('APIClient');
$loc = $location;
}));
it ('Should send GET request', function(done) {
expect($loc.path()).toEqual('');
var url = '/';
$httpBackend.expect('GET', $loc.path('/')).respond({});
apiClient.send({
url: url,
success: function(data, status) {
console.log(status);
done();
},
error: function(data, status) {
console.log(status);
done();
}
});
$httpBackend.flush();
});
修改强> 您应该使用angular-mock来使用$ location
beforeEach(inject(function(_$httpBackend_, APIClient) {
$httpBackend = _$httpBackend_;
apiClient = APIClient;
}));
答案 3 :(得分:0)
在每个块之前添加此行 - $ httpBackend.expect(&#39; GET&#39;,&#34; templates / test.html&#34;)。回复(200);