programing

보다 높은 수준의 지시의 단위 테스트를 가능하게 하기 위해 지시사항을 어떻게 시뮬레이션합니까?

oldcodes 2023. 2. 28. 23:45
반응형

보다 높은 수준의 지시의 단위 테스트를 가능하게 하기 위해 지시사항을 어떻게 시뮬레이션합니까?

앱에는 중첩된 지시문이 여러 개 레이어 있습니다.최상위 지시사항을 위한 단위 테스트를 작성하려고 합니다.지시문 자체에 필요한 것들을 조롱해 왔지만, 이제는 하위 수준의 지시문으로부터의 오류에 부딪히고 있습니다.최상위 지령을 위한 유닛 테스트에서는 하위 지령에서 무슨 일이 일어나고 있는지 걱정할 필요가 없습니다.나는 단지 하위 수준의 지시를 비웃고 기본적으로 아무것도 하지 않게 하고 싶기 때문에 나는 격리된 상위 수준의 지시를 테스트할 수 있다.

다음과 같이 지시 정의를 덮어쓰려고 했습니다.

angular.module("myModule").directive("myLowerLevelDirective", function() {
    return {
        link: function(scope, element, attrs) {
            //do nothing
        }
    }
});

단, 이 명령어는 덮어쓰지 않고 실제 명령어와 함께 실행됩니다.이러한 하위 수준의 지시어가 상위 수준의 지시어에 대한 단위 테스트에서 아무 것도 수행하지 않도록 하려면 어떻게 해야 합니까?

공장에 에 이를 를 비웃는 입니다.module은 「」, 「」에 .beforeEach '때 'block. do-something-else'라는가 있을 때 . do-something-else'라는 지시가 예요.

beforeEach(module('yourapp/test', function($provide){
  $provide.factory('doSomethingDirective', function(){ return {}; });
}));

// Or using the shorthand sytax
beforeEach(module('yourapp/test', { doSomethingDirective: {} ));

그런 다음 테스트에서 템플릿이 컴파일될 때 명령이 재정의됩니다.

inject(function($compile, $rootScope){
  $compile('<do-something-else></do-something-else>', $rootScope.$new());
});

컴파일러는 내부적으로 이 작업을 수행하므로 이름에 'Directive' 서픽스를 추가해야 합니다.https://github.com/angular/angular.js/blob/821ed310a75719765448e8b15e3a56f0389107a5/src/ng/compile.js#L530

은 '지시'를 사용하는 입니다.$compileProvider

beforeEach(module('plunker', function($compileProvider){
  $compileProvider.directive('d1', function(){ 
    var def = {
      priority: 100,
      terminal: true,
      restrict:'EAC',
      template:'<div class="mock">this is a mock</div>',
    };
    return def;
  });
}));

모크가 조롱하고 있는 디렉티브보다 우선도가 높고, 모크가 터미널이므로 원래 디렉티브가 컴파일되지 않도록 해야 합니다.

priority: 100,
terminal: true,

결과는 다음과 같습니다.

이 지시가 주어진 경우:

var app = angular.module('plunker', []);
app.directive('d1', function(){
  var def =  {
    restrict: 'E',
    template:'<div class="d1"> d1 </div>'
  }
  return def;
});

이렇게 조롱할 수 있습니다.

describe('testing with a mock', function() {
var $scope = null;
var el = null;

beforeEach(module('plunker', function($compileProvider){
  $compileProvider.directive('d1', function(){ 
    var def = {
      priority: 9999,
      terminal: true,
      restrict:'EAC',
      template:'<div class="mock">this is a mock</div>',
    };
    return def;
  });
}));

beforeEach(inject(function($rootScope, $compile) {
  $scope = $rootScope.$new();
  el = $compile('<div><d1></div>')($scope);
}));

it('should contain mocked element', function() {
  expect(el.find('.mock').length).toBe(1);
});
});

몇 가지 추가 사항:

  • 때 꼭 .replace:true "/"template놀리다ng-src 「」는 없습니다replace:true '아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아template하지만 시각적인 것을 조롱한다면, 여러분은 그렇게 하고 싶을지도 모릅니다.

  • priority를 100보다 높게 설정하면 mock의 속성은 보간되지 않습니다.$compile 소스 코드를 참조하십시오.예를 들어, 당신이 조롱한다면ng-src를 설정합니다.priority:101 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , .ng-src="{{variable}}"ng-src="interpolated-value"네 조롱으로.

여기 모든 것이 있는 플런커가 있다.@trodriges 님이 저를 올바른 방향으로 인도해 주셔서 감사합니다.

상세한 것에 대하여는, 「설정 블록」섹션을 참조해 주세요.@ebelanger님 덕분입니다!

디렉티브 등록의 실장으로 인해 기존 디렉티브를 조롱된 디렉티브로 대체하는 것은 불가능할 것으로 보입니다.

단, 하위 수준의 지시어의 간섭 없이 상위 수준의 지시어를 유닛으로 테스트하는 방법은 여러 가지가 있습니다.

1) 유닛 테스트템플릿에 하위 레벨 지시어를 사용하지 마십시오.

하위 수준의 지시어가 상위 수준의 지시어에 의해 추가되지 않은 경우 장치 테스트에서는 상위 수준의 지시문만 있는 템플릿을 사용합니다.

var html = "<div my-higher-level-directive></div>";
$compile(html)(scope);

따라서 하위 수준의 지시는 간섭하지 않습니다.

2) 지시적인 구현에서 서비스를 사용합니다.

하위 레벨의 다이렉트링크 기능을 서비스에 의해 제공할 수 있습니다.

angular.module("myModule").directive("myLowerLevelDirective", function(myService) {
    return {
        link: myService.lowerLevelDirectiveLinkingFunction
    }
});

그런 다음 장치 테스트에서 이 서비스를 조롱하여 상위 수준 지시문에 대한 간섭을 방지할 수 있습니다.이 서비스는 필요에 따라 지시 객체 전체를 제공할 수도 있습니다.

3) 하위 수준의 디렉티브를 terminal 디렉티브로 덮어쓸 수 있습니다.

angular.module("myModule").directive("myLowerLevelDirective", function(myService) {
    return {
        priority: 100000,
        terminal: true,
        link: function() {
            // do nothing
        }
    }
});

terminal 옵션과 priority가 높을 경우 실제 하위 수준 디렉티브는 실행되지 않습니다.지시 문서에 더 많은 정보가 있습니다.

플런커에서 어떻게 작동하는지 보세요.

합니다.$templateCache「 」 「 」 、 「 」

beforeEach(angular.mock.inject(function ($templateCache) {
  $templateCache.put('path/to/template.html', '<div></div>');
}));

Sylvain의 대답이 너무 마음에 들어서 도우미 기능으로 만들어야 했다.대부분의 경우 종속성이 없는 부모 컨테이너 디렉티브를 컴파일하고 테스트할 수 있도록 하위 디렉티브를 삭제하는 것이 필요합니다.이 도우미를 통해 다음과 같은 작업을 수행할 수 있습니다.

function killDirective(directiveName) {
  angular.mock.module(function($compileProvider) {
    $compileProvider.directive(directiveName, function() {
      return {
        priority: 9999999,
        terminal: true
      }
    });
  });
}

그러면 인젝터가 생성되기 전에 다음 명령을 실행하여 지시문을 완전히 비활성화할 수 있습니다.

killDirective('myLowerLevelDirective');

스스로 고민하지 않을 수 없게 되어, 우리의 요구를 만족시킬 수 있는 해결책을 생각해 냈습니다.에, 나는 「아트리뷰트를 했습니다.attributeRemover★★★★★★★★★★★★★★★★★」음음음같 뭇매하다

angular.module("myModule").directive("attributeRemover", function() {
    return {
        priority: -1, //make sure this runs last
        compile: function(element, attrs) {
            var attributesToRemove = attrs.attributeRemover.split(",");
            angular.forEach(attributesToRemove, function(currAttributeToRemove) {
                element.find("div[" + currAttributeToRemove + "]").removeAttr(currAttributeToRemove);
            });
        }
    }
});

테스트하는 디렉티브의 html은 다음과 같습니다.

<div my-higher-level-directive attribute-remover="my-lower-level-directive,another-loweler-level-directive"></div>

그래서 언제?my-higher-level-directive컴파일되다attribute-remover하위 레벨의 지시어는 이미 삭제되어 있기 때문에 무엇을 하고 있는지 걱정할 필요가 없습니다.

모든 종류의 디렉티브(아트리뷰트 1 뿐만이 아니라)에 대해 보다 견고한 방법이 있을 수 있습니다.또, 짜넣기 JQLite만을 사용하는 경우, 이 방법이 기능하는지는 잘 모르겠습니다만, 우리가 필요로 하는 것에는 대응할 수 있습니다.

여기 또 다른 작은 아이디어가 있다.이 코드를 재스민 도우미(커피 스크립트)에 넣기만 하면 됩니다.

window.mockDirective = (name, factoryFunction) ->
  mockModule = angular.module('mocks.directives', ['ng'])
  mockModule.directive(name, factoryFunction)

  module ($provide) ->
    factoryObject = angular.injector([mockModule.name]).get("#{name}Directive")
    $provide.factory "#{name}Directive", -> factoryObject
    null

사용방법:

beforeEach mockDirective, "myLowerLevelDirective", ->
  link: (scope, element) ->

그러면 지정된 디렉티브의 다른 모든 구현이 완전히 제거되고 디렉티브에 대한 테스트 통과 인수에 대한 완전한 액세스가 제공됩니다.FOr의 예에서는 mm.foundation alert 디렉티브를 다음과 같이 조롱할 수 있습니다.

beforeEach mockDirective 'alert', ->
  scope:
    type: '='

다음 테스트를 실시합니다.

expect(element.find('alert').data('$isolateScopeNoTemplate').type).toEqual 

언급URL : https://stackoverflow.com/questions/17533052/how-do-you-mock-directives-to-enable-unit-testing-of-higher-level-directive

반응형