programing

Angular JS + Jasmine : 객체 비교

minimums 2023. 3. 9. 21:57
반응형

Angular JS + Jasmine : 객체 비교

이제 막 앵귤러 작문시험을 시작했어JS앱과 Jasmine에서 하고 있습니다.

다음은 관련 코드 스니펫입니다.

클라이언트 컨트롤러:

'use strict';

adminConsoleApp.controller('ClientController',
    function ClientController($scope, Client) {

        //Get list of clients
        $scope.clients = Client.query(function () {
            //preselect first client in array
            $scope.selected.client = $scope.clients[0];
        });

        //necessary for data-binding so that it is accessible in child scopes.
        $scope.selected = {};

        //Current page
        $scope.currentPage = 'start.html';

        //For Client nav bar
        $scope.clientNavItems = [
            {destination: 'features.html', title: 'Features'},
        ];

        //Set current page
        $scope.setCurrent = function (title, destination) {
            if (destination !== '') {
                $scope.currentPage = destination;
            }

        };

        //Return path to current page
        $scope.getCurrent = function () {
            return 'partials/clients/' + $scope.currentPage;
        };

        //For nav bar highlighting of active page
        $scope.isActive = function (destination) {
            return $scope.currentPage === destination ? true : false;
        };

        //Reset current page on client change
        $scope.clientChange = function () {
            $scope.currentPage = 'start.html';
        };
    });

Client Controller Spec:

'use strict';

var RESPONSE = [
    {
        "id": 10,
        "name": "Client Plus",
        "ref": "client-plus"
    },
    {
        "id": 13,
        "name": "Client Minus",
        "ref": "client-minus"
    },
    {
        "id": 23805,
        "name": "Shaun QA",
        "ref": "saqa"
    }
];

describe('ClientController', function() {

    var scope;

    beforeEach(inject(function($controller, $httpBackend, $rootScope) {
        scope = $rootScope;
        $httpBackend.whenGET('http://localhost:3001/clients').respond(RESPONSE);
        $controller('ClientController', {$scope: scope});
        $httpBackend.flush();
    }));

    it('should preselect first client in array', function() {
        //this fails.
        expect(scope.selected.client).toEqual(RESPONSE[0]);
    });

    it('should set current page to start.html', function() {
        expect(scope.currentPage).toEqual('start.html');
    });
});

테스트 실패:

Chrome 25.0 (Mac) ClientController should preselect first client in array FAILED
    Expected { id : 10, name : 'Client Plus', ref : 'client-plus' } to equal { id : 10, name : 'Client Plus', ref : 'client-plus' }.
    Error: Expected { id : 10, name : 'Client Plus', ref : 'client-plus' } to equal { id : 10, name : 'Client Plus', ref : 'client-plus' }.
        at null.<anonymous> (/Users/shaun/sandbox/zong-admin-console-app/test/unit/controllers/ClientControllerSpec.js:43:39) 

왜 이런 일이 일어나는지 아는 사람 있나요?

또한 Angular는 처음 써보니까JS 테스트, 테스트 설정을 잘못했는지, 개선할 수 있는지에 대한 코멘트는 모두 환영합니다.

업데이트:

Client Service 포함:

'use strict';

AdminConsoleApp.services.factory('Client', function ($resource) {
    //API is set up such that if clientId is passed in, will retrieve client by clientId, else retrieve all.
    return $resource('http://localhost:port/clients/:clientId', {port: ':3001', clientId: '@clientId'}, {

    });
});

또한 ID를 비교하여 문제를 해결했습니다.

it('should preselect first client in array', function () {
    expect(scope.selected.client.id).toEqual(RESPONSE[0].id);
});

toEqual깊이 있는 평등을 비교합니다.즉, 오브젝트 값의 속성이 모두 같으면 오브젝트는 동일한 것으로 간주됩니다.

말씀하신 대로 어레이 내의 개체에 몇 가지 속성을 추가하는 리소스를 사용하고 있습니다.

그래서 이게{id:12}이 상태가 되다{id:12, $then: function, $resolved: true}동등하지 않습니다.값을 올바르게 설정했는지 테스트만 하는 경우 ID 확인은 문제 없습니다.

간단한 답변:

기존 답변에서는 모두 개체를 문자열화하거나 사용자 지정 매처/비교 함수를 만들 것을 권장합니다.단, 더 쉬운 방법이 있습니다.angular.equals()재스민으로expectJasmine의 빌트인을 사용하는 대신 전화하다toEqual매처

angular.equals()는 Angular에 의해 객체에 추가된 추가 속성을 무시합니다.toEqual예를 들어, 비교에 실패한다.$promise그 물건들 중 하나에 있는 것 같아요.


자세한 설명:

내 Angular에서 같은 문제를 발견했어JS 어플리케이션시나리오를 설정합니다.

테스트에서는 로컬오브젝트와 로컬어레이를 생성하여 2개의 GET 요구에 대한 응답으로 상정했습니다.그 후 GET의 결과와 원래의 오브젝트 및 어레이를 비교했습니다.4가지 방법으로 테스트했는데 1가지 방법밖에 없었습니다.

다음은 foobar-controller-spec.js의 일부입니다.

var myFooObject = {id: 1, name: "Steve"};
var myBarsArray = [{id: 1, color: "blue"}, {id: 2, color: "green"}, {id: 3, color: "red"}];

...

beforeEach(function () {
    httpBackend.expectGET('/foos/1').respond(myFooObject);
    httpBackend.expectGET('/bars').respond(myBarsArray);
    
    httpBackend.flush();
});

it('should put foo on the scope', function () {
    expect(scope.foo).toEqual(myFooObject);
    //Fails with the error: "Expected { id : 1, name : 'Steve', $promise : { then : Function, catch : Function, finally : Function }, $resolved : true } to equal { id : 1, name : 'Steve' }."
    //Notice that the first object has extra properties...
    
    expect(scope.foo.toString()).toEqual(myFooObject.toString());
    //Passes, but invalid (see below)
    
    expect(JSON.stringify(scope.foo)).toEqual(JSON.stringify(myFooObject));
    //Fails with the error: "Expected '{"id":1,"name":"Steve","$promise":{},"$resolved":true}' to equal '{"id":1,"name":"Steve"}'."
    
    expect(angular.equals(scope.foo, myFooObject)).toBe(true);
    //Works as expected
});

it('should put bars on the scope', function () {
    expect(scope.bars).toEqual(myBarsArray);
    //Fails with the error: "Expected [ { id : 1, color : 'blue' }, { id : 2, color : 'green' }, { id : 3, color : 'red' } ] to equal [ { id : 1, color : 'blue' }, { id : 2, color : 'green' }, { id : 3, color : 'red' } ]."
    //Notice, however, that both arrays seem identical, which was the OP's problem as well.
    
    expect(scope.bars.toString()).toEqual(myBarsArray.toString());
    //Passes, but invalid (see below)
    
    expect(JSON.stringify(scope.bars)).toEqual(JSON.stringify(myBarsArray));
    //Works as expected
    
    expect(angular.equals(scope.bars, myBarsArray)).toBe(true);
    //Works as expected
});

참고로 다음 출력은console.log사용.JSON.stringify()그리고..toString():

LOG: '***** myFooObject *****'
LOG: 'Stringified:{"id":1,"name":"Steve"}'
LOG: 'ToStringed:[object Object]'

LOG: '***** scope.foo *****'
LOG: 'Stringified:{"id":1,"name":"Steve","$promise":{},"$resolved":true}'
LOG: 'ToStringed:[object Object]'



LOG: '***** myBarsArray *****'
LOG: 'Stringified:[{"id":1,"color":"blue"},{"id":2,"color":"green"},{"id":3,"color":"red"}]'
LOG: 'ToStringed:[object Object],[object Object],[object Object]'

LOG: '***** scope.bars *****'
LOG: 'Stringified:[{"id":1,"color":"blue"},{"id":2,"color":"green"},{"id":3,"color":"red"}]'
LOG: 'ToStringed:[object Object],[object Object],[object Object]'

문자열화된 객체에 추가 속성이 있는 방법과toString잘못된 양의 데이터를 생성합니다.

위의 내용을 참조하여 다양한 방법을 요약합니다.

  1. expect(scope.foobar).toEqual(foobar): 이 동작은 양쪽 모두 실패합니다.객체를 비교할 때 toString은 Angular가 추가 속성을 추가했음을 나타냅니다.배열을 비교할 때 내용은 같아 보이지만 이 방법에서는 여전히 서로 다르다고 주장합니다.
  2. expect(scope.foo.toString()).toEqual(myFooObject.toString()): : : : : : : : : : : : : : 。그러나 오브젝트가 완전히 변환되지 않았기 때문에 이는 잘못된 긍정입니다.이 주장은 두 개의 인수가 동일한 개체 수를 가지고 있다는 것입니다.
  3. expect(JSON.stringify(scope.foo)).toEqual(JSON.stringify(myFooObject)): 이 메서드는 어레이를 비교할 때 적절한 응답을 제공하지만 오브젝트 비교는 raw 비교와 유사한 장애가 있습니다.
  4. expect(angular.equals(scope.foo, myFooObject)).toBe(true): 이것이 주장을 하는 올바른 방법입니다.Angular가 비교를 수행하도록 함으로써 백엔드에 추가된 속성을 무시하도록 인식하고 적절한 결과를 얻을 수 있습니다.

혹시라도 AngularJS 1.2.14와 Karma 0.10.10을 사용하여 팬텀에서 테스트하고 있습니다.JS 1.9.7

요약하면: 추가angular.equals재스민 매처로서.

beforeEach(function(){
  this.addMatchers({
    toEqualData: function(expected) {
      return angular.equals(this.actual, expected);
    }
  });
});

따라서 다음과 같이 사용할 수 있습니다.

it('should preselect first client in array', function() {
    //this passes:
    expect(scope.selected.client).toEqualData(RESPONSE[0]);

    //this fails:
    expect(scope.selected.client).toEqual(RESPONSE[0]);
});

비슷한 문제가 발생하여 다음과 같은 다양한 접근방식을 사용하여 커스텀 매처를 구현했습니다.

beforeEach(function() {
  this.addMatchers({
    toBeSimilarTo: function(expected) {
      function buildObject(object) {
        var built = {};
        for (var name in object) {
          if (object.hasOwnProperty(name)) {
            built[name] = object[name];
          }
        }
        return built;
      }

      var actualObject = buildObject(this.actual);
      var expectedObject = buildObject(expected);
      var notText = this.isNot ? " not" : "";

      this.message = function () {
        return "Expected " + actualObject + notText + " to be similar to " + expectedObject;
      }

      return jasmine.getEnv().equals_(actualObject, expectedObject);

    }
  });
});

다음 방법으로 사용:

it("gets the right data", function() {
  expect(scope.jobs[0]).toBeSimilarTo(myJob);
});

물론 매우 단순한 매치이기 때문에 많은 사례를 지원하지 않지만, 그보다 더 복잡한 것은 필요하지 않았습니다.구성 파일로 매처를 랩할 수 있습니다.

같은 실장에 대해서는, 회답에 체크해 주세요.

도 같은 그냥 요.JSON.stringify()이치

expect( JSON.stringify( $scope.angularResource ) == JSON.stringify( expectedValue )).toBe( true );

조금 상세하게 설명하지만 예상에 실패할 경우 도움이 되는 메시지가 나타납니다.

expect(JSON.parse(angular.toJson(resource))).toEqual({ id: 1 });

설명:

angular.toJson다음과 같은 특정 각도의 특성을 모두 제거할 수 있습니다.$promise

JSON.parse는 JSON 문자열을 일반 오브젝트(또는 어레이)로 변환하여 다른 오브젝트(또는 어레이)와 비교할 수 있게 됩니다.

언급URL : https://stackoverflow.com/questions/15487510/angularjs-jasmine-comparing-objects

반응형