использование контроллера angularjs, который использует обещание обслуживания внутри представления

#angularjs #jasmine #angularjs-controller #angular-services #angular-promise

#angularjs #jasmine #angularjs-controller #angular-services #angular-обещание

Вопрос:

У меня есть контроллер, который использует обещание обслуживания angularjs. Я написал модульные тесты jasmine для контроллера, и поэтому функция контроллера выглядит так:

 this.getTodos = function () {
    TodoService.getTodos().then(function (todos) {
        $scope.Todos = todos;
      },
        function (error) {
            // TODO: display the error pop up
            console.log(error);
        });
};
 

Похоже, это не работает с представлением? Если я изменю функцию на:

  TodoService.getTodos().then(function (todos) {
        $scope.Todos = todos;
      },
        function (error) {
            // TODO: display the error pop up
            console.log(error);
        });
 

тогда это работает, но тогда я не могу протестировать свою функцию контроллера. Моим предпочтительным способом было бы использовать его как this.getTodos, this.saveTodo, this .DeleteTodo и т. Д….

какие-либо предложения, пожалуйста?

большое спасибо

====>> Обновить

Как уже упоминалось, все тесты работают, но в представлении не отображаются данные; похоже, контроллер this.getTodos вообще не вызывается. …. Я не уверен, как заставить angular view использовать controller getTodos… Тесты приведены ниже:

Следующие тесты jasmine работают нормально:

     it("Reading todos...", inject(function ($q) {

        var deferredRead = $q.defer();
        spyOn(todoServiceMock, "getTodos").and.returnValue(deferredRead.promise);
        deferredRead.resolve([{ TodoId: 10, Description: "Test", Completed: false },
        { TodoId: 11, Description: "Test", Completed: false }]);
        todoController.getTodos();
        scope.$apply();

        expect(scope.Todos.length).toBe(2);
    }));

    it("Reading todos, error...", inject(function ($q) {

        var deferredRead = $q.defer();
        spyOn(todoServiceMock, "getTodos").and.returnValue(deferredRead.promise);
        deferredRead.reject("There are no todos available!");
        todoController.getTodos();
        scope.$apply();

        expect(scope.Todos.length).toBe([]);
    }));
 

Однако представление не заполняет строки…

Представление имеет код, подобный:

 <tr class="animate" ng-repeat="Todo in Todos | orderBy:'TodoId' | filter: filterTodo">
                    <td class="col-sm-1">{{Todo.TodoId}}</td>
                    <td class="col-sm-3">{{Todo.Description}}</td>
                    <td class="col-sm-1">
                        <span class="glyphicon glyphicon-check" ng-show="   {{Todo.Completed}}==true"></span>
                        <span class="glyphicon glyphicon-unchecked" ng-show="{{Todo.Completed}}==false"></span>
                    </td>
                    <td class="col-sm-2">
                        <a href="" ng-click="selectTodo(Todo)"><span class="glyphicon glyphicon-edit"></span></a>
                    </td>
                </tr>
 

Комментарии:

1. Не могли бы вы добавить тест и ошибку, которую вы получаете в тесте. jsfiddle тоже было бы неплохо

2. Привет, спасибо за ответ. Я думаю, что я недостаточно четко сформулировал свой вопрос. Все тесты работают нормально. Но представление не работает, например, представление не вызывает функцию контроллера this.getTodos. Я обновлю исходный пост.

3. Я не эксперт, но вы могли бы попробовать добавить $scope.apply(). Но способ, которым я делаю что-то подобное, заключается в том, чтобы фабрика загружала данные самостоятельно, передавала объект factory в контроллер и отправляла заводу сообщение, когда он загружал данные, а контроллер следил за этим

Ответ №1:

Angular не будет вызывать функцию из вашей области видимости, если вы не укажете ей вызвать ее. Итак, у вас в основном есть 3 варианта:

  1. Сделайте так, как вы делали во второй попытке
  2. Вызовите функцию в вашем контроллере, когда она будет создана:
     this.getTodos = function () { ... }; // define the method
    this.getTodos(); // call it
     
  3. Используйте ng-init в представлении для вызова getTodos() функции.

Обратите внимание, что использование первого или второго метода не должно препятствовать модульному тестированию контроллера. Единственное отличие заключается в том, что ваш тест должен ожидать, что вызов службы выполняется при создании экземпляра контроллера (т. Е. При $controller('TodoController') вызове), а не ожидать, что это произойдет после его создания, когда getTodos() вызывается функция.

Комментарии:

1. Привет, Джей Би, спасибо за ответ. Переход к варианту 2 решает проблему, однако теперь все мои тесты будут провалены. Ошибка: «Сообщение о результате: TypeError: ‘undefined’ не является объектом (оценивающим ‘promise.then’) в file:///d:/rahman/angularjsandunittesting/angularjsandunittesting/scripts/app/controllers.js (строка 21)» … а строка 21 — это TodoService.getTodos().then(функция (todos) { … Комментируя строку this.getTodos();, все тесты снова будут выполняться нормально. Не знаете, почему это должно произойти???

2. Как я уже сказал, потому что теперь создание экземпляра контроллера вызывает службу. Таким образом, вы должны изменить beforeEach() вашего теста.