如何使用angular度平移进行unit testing

我从这里使用angular度翻译( http://pascalprecht.github.io/angular-translate/ ),它只是工作正常,但它打破了我的控制器的unit testingwhith错误:

Unexpected request: GET scripts/i18n/locale-en.json 

我不明白为什么?

我使用自我testing和业力。

app.js:

 'use strict'; (function() { angular.module('wbApp', ['authService', 'authUserService', 'checkUserDirective', 'ui.bootstrap', 'pascalprecht.translate']) .config(function($routeProvider) { $routeProvider .when('/', { templateUrl: 'views/login.html', controller: 'LoginCtrl', access: { isFree: true } }) .when('/main', { templateUrl: 'views/main.html', controller: 'MainCtrl', access: { isFree: false } }) .otherwise({ redirectTo: '/' }); }); })(); 

configTranslate.js:

 'use strict'; (function() { angular.module('wbApp') .config(['$translateProvider', function($translateProvider) { $translateProvider.useStaticFilesLoader({ prefix: 'scripts/i18n/locale-', suffix: '.json' }); $translateProvider.preferredLanguage('en'); }]); })(); 

karma.conf.js:

 files = [ ... 'app/bower_components/angular-translate/angular-translate.js', 'app/bower_components/angular-translate-loader-static-files/angular-translate-loader-static-files.js', ... ]; 

控制器testing:

 'use strict'; describe('Controller: LoginCtrl', function() { // load the controller's module beforeEach(module('wbApp')); var LoginCtrl, scope, location, httpMock, authUser; // Initialize the controller and a mock scope beforeEach(inject(function($controller, $rootScope, $location, $httpBackend, AuthUser) { authUser = AuthUser; location = $location; httpMock = $httpBackend; scope = $rootScope.$new(); LoginCtrl = $controller('LoginCtrl', { $scope: scope }); httpMock.when('GET', 'scripts/i18n/locale-en.json').passThrough(); })); it(...); ... }); 

如果我在testing控制器中添加这个,产品同样的错误:

 httpMock.when('GET', 'scripts/i18n/locale-en.json').respond(200); httpMock.flush(); 

要么

 httpMock.when('GET', 'scripts/i18n/locale-en.json').passThrough(); httpMock.flush(); 

我发现这篇文章我如何testing控制器angular度翻译初始化在应用程序configuration? 但没有帮助我:/

我广泛使用$ httpBackend在我的testing,它工作正常,但在这种情况下,它是无效的。 如果我评论这一行:

 $translateProvider.preferredLanguage('en'); 

显然是一个错误,如果我添加运行时(在我的控制器)

 $translate.uses(local); 

我结束了同样的错误?

所以我转向翻译configuration(configTranslate.js)或在运行时是相同的结果:

 Unexpected request: GET scripts/i18n/locale-en.json 

这里是我testing的语法,在“beforeEach(inject(function(…});”

或者在testing中“it('…',function(){…});”

 httpMock.expectGET('scripts/i18n/locale-en.json'); httpMock.when('GET', 'scripts/i18n/locale-en.json').passThrough(); httpMock.when('GET', 'scripts/i18n/locale-en.json').respond(data); 

与结束

 httpMock.flush(); 

我也试过申请

 httpMock.expectGET('scripts/i18n/locale-fr.json'); scope.$apply(function(){ $translate.uses('fr'); }); httpMock.flush(); 

没有任何反应,但这个错误正在让我发疯。

如果您有任何build议

这是一个已知的问题,请按照这里的文档: unit testingangular度

解决scheme

不幸的是,这个问题是由angular度翻译的devise引起的。 为了解决这些错误,我们所能做的就是在我们的testing套件中覆盖我们的模块configuration,它根本不使用asynchronous加载器。 当没有asynchronous加载器时,没有XHR,因此没有错误。

那么我们如何在运行时为我们的testing套件覆盖我们的模块configuration呢? 当实例化一个angular度模块时,我们总是可以应用一个内联函数作为configuration函数来执行。 由于我们可以访问所有提供者,因此可以使用此configurationfunction覆盖模块configuration。

使用$ provide提供程序,我们可以构build一个自定义的加载程序工厂,然后使用它来代替静态文件加载程序。

 beforeEach(module('myApp', function ($provide, $translateProvider) { $provide.factory('customLoader', function () { // loader logic goes here }); $translateProvider.useLoader('customLoader'); })); 

请阅读上面提供的链接。

我们采取了在unit testing中忽略翻译加载器的方法,而不是被迫修改每个spec文件。

一种方法可以通过将加载程序configuration分离到单独的文件,然后在业障中排除它。

因此,例如,您可以创build一个文件app-i18n-loader.js(所有其他模块configuration发生在不同的文件中):

  angular .module('myApp') .config(loaderConfig); loaderConfig.$inject = ['$translateProvider', '$translatePartialLoaderProvider']; function loaderConfig($translateProvider, $translatePartialLoaderProvider) { $translateProvider.useLoader('$translatePartialLoader', { urlTemplate: 'assets/i18n/{part}/{lang}.json' }); $translatePartialLoaderProvider.addPart('myApp'); } 

并在你的karma.conf.js排除文件:

  files: [ 'bower_components/angular/angular.js', 'bower_components/angular-mocks/angular-mocks.js', //... 'bower_components/angular-translate/angular-translate.js', 'bower_components/angular-translate-loader-partial/angular-translate-loader-partial.js', 'app/**/*.mdl.js', 'app/**/*.js' ], exclude: [ 'app/app-i18n-loader.js' ], 

(注意:编辑答案不需要咕噜/咕嘟咕嘟的解决scheme)。

我想要一个解决scheme,

  1. 这不是太hacky
  2. 这并不要求我改变我的实际应用程序代码,
  3. 这不会干扰加载附加模块的能力
  4. 最重要的是不需要我改变每一个testing。

这是我结束了:

 // you need to load the 3rd party module first beforeEach(module('pascalprecht.translate')); // overwrite useStaticFilesLoader to get rid of request to translation file beforeEach(module(function ($translateProvider) { $translateProvider.useStaticFilesLoader = function () { }; })); 

假设你不需要unit testing的实际翻译,这很好。 只需将beforeEach放在全局级别上,最好在testing文件夹内的自己的文件中。 它会在每隔一个testing之前执行。

尝试把testing方法:

 it('should ...', function() { httpMock.when('GET', 'scripts/i18n/locale-en.json').respond({}); httpMock.expectGET('scripts/i18n/locale-en.json'); scope.resetForm(); // Action which fires a http request httpMock.flush(); // Flush must be called after the http request } 

查看来自Angular文档的示例

请参考PascalPrecht/angular-translate/blob/master/test/unit/service/loader-static-files.spec.html

一般来说,我build议使用一个标准的翻译加载程序进行unit testing(没有http加载的麻烦),这意味着您可以使用$translateProvider.translations()提供标签。 为什么? 因为您不必testing作为angular度转换项目一部分的远程加载function。

我用量angular器testing遇到了这个问题。 我的解决scheme是嘲笑这样的翻译:

 angular.module('app') .config(function ($translateProvider) { $translateProvider.translations('en', {}); $translateProvider.preferredLanguage('en'); }) 

现在没有下载语言文件,没有string被翻译,我只是在规格的string键testing:

 expect(element(by.css('#title')).getText()).toEqual('TITLE_TEXT'); 

没有解决scheme为我工作,但我带着这些解决scheme:

1)如果你需要使用scope.$apply() ,或者应该在你的testing中处理状态(在$apply()第二种方法不起作用),用$translateProvider.translations()覆盖你的应用程序的翻译。方法,使用插件来加载JSON文件

 beforeEach(module(function ($translateProvider) { $translateProvider.translations('en', readJSON('scripts/i18n/locale-en.json')); })); 

2)如果你testing过的控制器依赖于$translate服务,你可以使用一个插件来加载JSON文件 ,并且在$httpBackend和angular-translate请求它时加载你的语言环境文件。

 beforeEach(inject(function (_$httpBackend_) { $httpBackend = _$httpBackend_; $httpBackend.whenGET('scripts/i18n/locale-en.json').respond(readJSON('scripts/i18n/locale-en.json')); $httpBackend.flush(); }))); 

注意这应该在beforeEach(module('myApp'));之下beforeEach(module('myApp')); 否则你会得到$injector错误。

我为$ translate做了一个简单的模拟服务

 $translate=function (translation) { return { then: function (callback) { var translated={}; translation.map(function (transl) { translated[transl]=transl; }); return callback(translated); } } }; 

用法示例: https : //gist.github.com/dam1/5858bdcabb89effca457

我使用这种模式。

  • ApplicationModule设置了常规的angular-translateconfiguration。
  • testing代码加载'testModule'而不是'applicationModule'
 // application module .js (function() { 'use strict'; angular .module('applicationModule', [ 'ngAnimate', 'ngResource', 'ui.router', 'pascalprecht.translate' ]) .config(['$stateProvider', '$urlRouterProvider', '$translateProvider', '$translatePartialLoaderProvider', config]); function config($stateProvider, $urlRouterProvider, $translateProvider, $translatePartialLoaderProvider) { // set routing ... $translateProvider.useStaticFilesLoader({ prefix: 'i18n/locale-', suffix: '.json' }); $translateProvider.useMessageFormatInterpolation(); $translateProvider.fallbackLanguage(['en']); $translateProvider .registerAvailableLanguageKeys(['en', 'ko'], { 'en_US': 'en', 'ko_KR': 'ko' }) .determinePreferredLanguage(navigator.browserLanguage); $translateProvider.addInterpolation('$translateMessageFormatInterpolation'); $translateProvider.useSanitizeValueStrategy('escaped'); } })(); 

在这个桌子的karma.conf.js ,但是我通过指定Karma只是按照karma.conf.js这个条目来提供文件来解决这个karma.conf.js

 files: [ ... {pattern: 'scripts/i18n/*.json', included: false, served: true}, ... ] 

2016年的答案是预处理你的JSON到你的testing中,并正确地testing你的指令翻译工作。

我使用karma-ng-json2js-preprocessor。 按照所有步骤设置你的karma.conf,然后在你的testing文件中,将相关文件作为模块添加,然后在$ translateProvider中设置这些信息。

 beforeEach(module('myApp', '/l10n/english-translation.json')); // Mock translations for this template beforeEach(module(function($translateProvider, englishTranslation) { $translateProvider.translations('en_us', englishTranslation); $translateProvider.useSanitizeValueStrategy(null); $translateProvider.preferredLanguage('en_us'); })); 

注意根据插件,它使用你的文件名来生成camelcased模块名称。 你可以使用模块的/ lib中的函数,但基本上它会删除所有的破折号,但KEEPS在camelCase中强调。 所以en_us变成了En_us。

您还需要告诉您的testing,它正在期待该文件为GEt。

  $httpBackend.expect('GET', '/l10n/english-translation.json').respond(200); 
Interesting Posts