2016-08-19 2 views
0

Я представляю модульные тесты javascript для приложения моей компании. Я работал преимущественно с AngularJS, но их каркасом выбора является Knockout. Кодекс относительно модульный по дизайну (благодаря Knockout), поэтому я предположил, что будет легко добавить модульные тесты вокруг кода (как и Angular).Разнообразные зависимости от нокаута в модульных тестах Жасмина

Однако есть еще одно осложнение: система использует require.js в качестве контейнера IoC. Кроме того, мой тестовый бегун - Chutzpah, который безголовый/в Visual Studio Test Explorer. Я попытался издеваться над зависимостями, используя SquireJS, но я столкнулся с проблемой при попытке создать экземпляр ViewModel: он хочет определенные зависимости, которые установлены в компоненте и унаследованы. Я пытаюсь загрузить компонент, который имеет дополнительные зависимости и т. Д. И т. Д. Ниже у меня есть ошеломительная версия настройки, которая описывает точку. Каков наилучший способ создания экземпляра этой модели представления, чтобы я мог издеваться над зависимостями с Squire и запускать мои тесты?

Компонент

define(function (require) { 

    var Boiler = require('Boiler'), 
     BaseViewModel = require('../../../../core/baseClasses/BaseViewModel'), 
     viewTemplate = require('text!./view.html'), 
     viewModel = require('./viewModel'), 
     nls = require('i18n!./nls/resources'); 

    var Component = function (initializingParameters) { 
     //...blah blah blah setup things 
    }; 

    return Component; 
}); 

ViewModel

define(function (require) { 
    var Constants = require('../../../../core/constants'); 
    var momDate = moment().format('MMM DD, YYYY'); 
    var Utils = require("../../../../model/utils"); 
    var utils = new Utils(); 
    var otherComponentUtils = require("../../../otherModule/otherComponent/OtherComponentUtils"); 
    var otherComponentUtils = new OtherComponentUtils(); 

    var ViewModel = function (globalContext, moduleContext, dataContext, domElement) { 

     var Self = this; 
     Self.super(moduleContext, dataContext, resPickerContext); 
     var constants = new Constants(); 
     var utils = require("../../../../model/utils"); 
     var Utils = new utils(); 

     Self.Items = ko.observableArray().extend({ throttle: 500 }); 
     //a bunch more Knockout object setup 

     Self.GetAuthorizationTypesArray = function (itemId) { 
      dataContext.dataRequestHandler(dataContext.serviceConstants.GetTransactionTypes, { ItemId: itemId }, 
       function (data) { 
        if (data != null && data.length !== 0) { 
         Self.TransactionTypeArray(data); 

         var transactionTypeArray = Self.TransactionTypeArray(); 
         if (transactionTypeArray.length) { 
          var paymentInfo = Self.PaymentInfo(); 
          if (paymentInfo !== null && paymentInfo !== undefined && paymentInfo.IsSpecial) { 
           var childThing = Self.ChildThing(); 
           dataContext.dataRequestHandler(dataContext.serviceConstants.GetChild, { ChildId: childThing.ChildId, SpecialId: childThing.SpecialID }, function (data) { 

            var child = data[0]; 
            var specialTypeId = child.ListId; 

            if (specialTypeId === 13) 
             Self.BigThing.Type(1); 
            else 
             Self.BigThing.Type(2); 

           }, Self.ShowError); 
          } 
         } 
        } 
       }, 
       Self.ShowError); 
     } 

    return ViewModel; 
}); 

chutzpah.json

{ 
    "Framework": "jasmine", 
    "TestHarnessReferenceMode": "AMD", 
    "TestHarnessLocationMode": "SettingsFileAdjacent", 
    "RootReferencePathMode": "SettingsFileDirectory", 
    "References": [ 
    { "Path": "../../myWebApp/Scripts/libs/assets/plugins/jquery-1.10.2.min.js" }, 
    { "Path": "../../myWebApp/scripts/libs/moment/moment.min.js" }, 
    { "Path": "../../myWebApp/Scripts/libs/require/require.js" }, 
    { "Path": "unittest.main.js" } 
    ], 
    "Tests": [ 
    { 
     "Path": "app", 
     "Includes": [ "*.tests.js" ] 
    } 
    ] 
} 

unittest.main.js

"use strict"; 

require.config({ 
    paths: { 
     'jasmine': ['jasmine/jasmine'], 
     'jasmine-html': ['jasmine/jasmine-html'], 
     'jasmine-boot': ['jasmine/boot'], 
     squire: 'Squire' 
    }, 
    shim: { 
     'jasmine-html': { 
      deps : ['jasmine'] 
     }, 
     'jasmine-boot': { 
      deps : ['jasmine', 'jasmine-html'] 
     }, 
     'squire': { 
      exports: 'squire' 
     } 
    }, 
    config: { 
     text: { 
      useXhr: function (url, protocol, hostname, port) { return true }, 
      //Valid values are 'node', 'xhr', or 'rhino' 
      env: 'xhr' 
     } 
    }, 
    waitSeconds: 0 
}); 

viewModel.tests.js

define(function (require) { 
    var testTargetPath = '../../myWebApp/Scripts/app/modules/thisModule/myViewModel'; 

    describe('My View Model', function() { 
     var mockDataContext; 
     var mockResponseData; 
     var injector; 
     var viewModel; 

     beforeEach(function() { 
      var Squire = require('Squire'); 
      injector = new Squire(); 
     }); 

     beforeEach(function() { 
      mockResponseData = {}; 

      mockDataContext = { 
       dataRequestHandler: function (url, data, onSuccess) { 
        onSuccess(mockResponseData[url]); 
       }, 
       serviceConstants: { 
        GetTransactionTypes: 'getTransactionTypes', 
        GetChild: 'getNewPolicy' 
       } 
      }; 

      injector.mock("dataContext", mockDataContext); 
     }); 

     beforeEach(function (done) { 
      injector.require([testTargetPath], function (ViewModel) { 
       viewModel = new ViewModel(); 
       done(); 
      }); 
     }); 

     it('gets authorization type array', function() { 
      spyOn(mockDataContext, 'dataRequestHandler').and.callThrough(); 
      mockResponseData = { 
       'getTransactionTypes': [ 
        { name: 'auth type 1', TransactionTypeId: 90210 }, 
        { name: 'auth type 2', TransactionTypeId: 42 }, 
       ] 
      }; 

      viewModel.GetAuthorizationTypesArray(9266); 

      expect(mockDataContext.dataRequestHandler).toHaveBeenCalledWith('getTransactionTypes', { ItemId: 9266 }); 
      expect(viewModel.TransactionTypeArray()).toBe(mockResponseData); 
     }); 
    }); 
}); 

Конкретно, в ViewModel, когда испытания бежать, он жалуется, что super не определено.

ответ

0

Хорошо, оказывается, есть целый ряд вопросов, которые я имел дело с:

  1. Сначала я думал, что отказавший на super был из-за проблемы совместимости ES6 (с PhantomJS поддерживает только ES5). Однако получается, что проект не использует ES6, но inheritance.js, который вручную строит супер зависимости. Эта настройка выполняется в разделе component нокаута в нашем решении , поэтому я воспроизвел его в рамках модульных тестов.
  2. Я не правильно настраивал Squire, чтобы вводить мои зависимости, и исправил это.

Я не внес никаких изменений в свою модель компонентов или моделей, и моя конфигурация Chutzpah осталась прежней. Однако unittest.main.js был обновлен, как и мои тесты:

unittest.main.js

"use strict"; 

require.config({ 
    paths: { 
     'jasmine': ['jasmine/jasmine'], 
     'jasmine-html': ['jasmine/jasmine-html'], 
     'jasmine-boot': ['jasmine/boot'], 
     squire: 'Squire', 
     "baseViewModel": '../../myWebApp/Scripts/app/core/baseClasses/BaseViewModel' 
    }, 
    shim: { 
     'jasmine-html': { 
      deps : ['jasmine'] 
     }, 
     'jasmine-boot': { 
      deps : ['jasmine', 'jasmine-html'] 
     }, 
     'squire': { 
      exports: 'squire' 
     } 
    }, 
    config: { 
     text: { 
      useXhr: function (url, protocol, hostname, port) { return true }, 
      //Valid values are 'node', 'xhr', or 'rhino' 
      env: 'xhr' 
     } 
    }, 
    waitSeconds: 0 
}); 

viewModel.tests.JS

define(function (require) { 
    var testTargetPath = '../../myWebApp/Scripts/app/modules/thisModule/myViewModel'; 

    describe('View Model', function() { 
     var mockGlobalContext; 
     var mockModuleContext; 
     var mockDataContext; 
     var mockResponseData; 
     var injector; 
     var viewModel; 
     var mockUtils; 

     beforeEach(function() { 
      var Squire = require('Squire'); 
      injector = new Squire(); 
     }); 

     beforeEach(function() { 
      mockResponseData = {}; 
      mockGlobalContext = {}; 
      mockUtils = {}; 
      mockModuleContext = {}; 

      mockDataContext = { 
       dataRequestHandler: function (url, data, onSuccess) { 
        onSuccess(mockResponseData[url]); 
       }, 
       serviceConstants: { 
        GetTransactionTypes: 'getTransactionTypes', 
        GetChild: 'getNewPolicy' 
       } 
      }; 

      injector.mock("../../../../model/utils", function() { return mockUtils; }); 

      spyOn(mockDataContext, 'dataRequestHandler').and.callThrough(); 
     }); 

     beforeEach(function (done) { 
      injector.require([testTargetPath], function (ViewModel) { 
       var BaseViewModel = require('baseViewModel'); 
       BaseObject.Create(ViewModel, BaseViewModel, [mockGlobalContext, mockModuleContext, mockDataContext]); 

       viewModel = new ViewModel(mockGlobalContext, mockModuleContext, mockDataContext); 
       done(); 
      }); 
     }); 

     it('gets authorization type array', function() { 
      mockResponseData = { 
       'getGatewayTransactionTypes': [ 
        { name: 'auth type 1', TransactionTypeId: 90210 }, 
        { name: 'auth type 2', TransactionTypeId: 42 }, 
       ] 
      }; 

      viewModel.GetAuthorizationTypesArray(9266); 

      expect(mockDataContext.dataRequestHandler).toHaveBeenCalledWith('getGatewayTransactionTypes', { ItemId: 9266 }, jasmine.any(Function), viewModel.ShowError); 
      expect(viewModel.TransactionTypeArray()).toEqual(mockResponseData['getGatewayTransactionTypes']); 
     }); 
    }); 
}); 

С учетом этих изменений, тест проходит успешно и проходит.

Смежные вопросы