AngularJs에서 개인 메소드로 테스트 가능한 컨트롤러를 작성하는 방법은 무엇입니까?
좋습니다. 그래서 저는 오랫동안 어떤 문제에 넘어져 왔으며 나머지 커뮤니티의 의견을 듣고 싶습니다.
먼저 추상을 살펴 보겠습니다.
function Ctrl($scope, anyService) {
$scope.field = "field";
$scope.whenClicked = function() {
util();
};
function util() {
anyService.doSmth();
}
}
분명히 우리는 여기에 있습니다 :
- 컨트롤러 와 일부
$scope
서비스가 제공 된 일반 스캐 폴드 - 범위에 사용할 일부 필드 및 기능
- 개인 방법
util()
이제 단위 테스트 (Jasmine) 에서이 클래스를 다루고 싶습니다. 문제는 그러나 whenClicked()
일부 항목을 클릭 (호출 ) 때 할 util()
메서드가 호출되는지 확인하고 싶다는 을 구석으로입니다. Jasmine 테스트에서 항상 mock util()
이 정의되지 않은 사건거나 호출되지 않은 오류가 발생하기 때문에 어떻게하는지 모르겠습니다 .
참고 :이 특정 예제를 수정하려는 것이 일반적으로 일반적으로 코드 패턴을 테스트하는 것에 대해 묻습니다. 그러니 "정확한 오류가 무엇인지"말하지 마세요. 이 문제를 해결하는 방법이 아니라 방법을 설치하는 것입니다.
이 문제를 해결하기 위해 여러 가지 방법을 시도해 왔습니다.
$scope
이 함수에 연결되어 있지 않기 때문에 내 단위 테스트에서 사용할 수 없습니다 (보통 메시지Expected spy but got undefined
또는 이와 유사 하지 않습니다 )- 이 기능을 호출하지 못했지만 실패한
Ctrl.util = util;
다음 모의 확인 을 시도Ctrl.util = jasmine.createSpy()
했지만Ctrl.util
실패하지 않았습니다. - 나는 물건에
util()
부착하고 다시this
조롱 하기 위해 변화 를 시도했지만Ctrl.util
운이 없었습니다.
글쎄, 나는 이것에 대한 나의 길을 사용할 수 없다. 나는 JS 닌자로부터 약간의 도움을 기대할 것입니다. 작동하는 바이올린은 완벽 할 것이다.
범위에 이름을 붙이는 것은 오염입니다. 원하는 것은 해당되는 것을 별도의 함수로 추출한 다음 컨트롤러에 삽입하는 것입니다. 즉
function Ctrl($scope, util) {
$scope.field = "field";
$scope.whenClicked = function() {
util();
};
}
angular.module("foo", [])
.service("anyService", function(...){...})
.factory("util", function(anyService) {
return function() {
anyService.doSmth();
};
});
이제 Ctrl 과 "util" 을 모의하여 단위 테스트를 수행 할 수 있습니다 .
제공 한 컨트롤러 함수는 Angular에서 생성자로 사용됩니다. 어느 시점 new
에서 실제 컨트롤러 인스턴스를 만들기 위해 호출 됩니다. $ scope에 노출되지는 않지만 감시 / 스터 빙 / 모킹에 사용할 수있는 기능이 컨트롤러 개체에 필요하다면 this
.
function Ctrl($scope, anyService) {
$scope.field = "field";
$scope.whenClicked = function() {
util();
};
this.util = function() {
anyService.doSmth();
}
}
이제 var ctrl = new Ctrl(...)
Angular $controller
서비스를 호출 하거나 사용 하여 Ctrl
인스턴스 를 검색하면 반환 된 개체에 util
함수 가 포함 됩니다.
이 접근 방식은 http://jsfiddle.net/yianisn/8P9Mv/ 에서 볼 수 있습니다.
나는 다른 접근 방식으로 차임 할 것입니다. 비공개 메서드를 테스트해서는 안됩니다. 그것이 그들이 사적인 이유입니다-사용과 관련이없는 구현 세부 사항입니다.
예를 들어 util이 여러 곳에서 사용되었지만 지금은 다른 코드 리팩토링을 기반으로 한 곳에서만 호출된다는 사실을 알고 있다면 어떨까요? 추가 함수 호출이 필요한 이유는 무엇입니까? 그냥 포함 anyService.doSmith()
당신 안에 $scope.whenClicked()
당신이 테스트중인 가정, 위의 제안으로 util()
당신의 검사 결과가이 프로그램의 기능을 변경하지 않은 경우에도 중단됩니다,라고합니다. 단위 테스트의 주요 가치 중 하나는 문제를 해결하지 않고 리팩토링을 단순화하는 것이므로 문제를 해결하지 않았다면 테스트가 실패해서는 안됩니다.
당신이해야 할 일은 언제 $scope.whenClicked
호출 되었는지 anyService.doSmth()
도 호출 되는지 확인하는 것 입니다. 다음이 필요합니다.
spyOn(anyService,'doSmith')
scope.whenClicked();
expect(anyService.doSmith).toHaveBeenCalled();
나는 현재 접근 방식을 포함하는 답변을 추가하고 있으며, 이것이 좋은 해결책인지 아닌지에 대한 의견을 얻고 아마도 토론을 번쩍이기를 희망합니다.
우리는 컨트롤러 기능에 개인 기능을 추가하고 있습니다 (따라서 공개적으로 만들어 조롱을 가능하게합니다). 컨트롤러 이름을 항상 반복하지 않고 구문을 더 매력적으로 만들기 self
위해 컨트롤러 기능에 대한 참조를 보유 하는 객체를 생성 합니다. 따라서 다음과 같이됩니다.
function Ctrl($scope, anyService) {
$scope.field = "field";
$scope.whenClicked = function() {
self.util();
};
var self = Ctrl; // For the sake of syntax simplicity only
self.util = function() {
anyService.doSmth();
};
}
이제 단위 테스트에서 다음을 사용할 수 있습니다.
Ctrl.util = jasmine.createSpy("util()");
expect(Ctrl.util).toHaveBeenCalled();
나는 여전히 이것을별로 좋아하지 않지만 이것이 가장 간단한 방법이라고 생각합니다. 나는 누군가가 더 나은 접근 방식을 찾을 수 있기를 바랍니다.
'ProgramingTip' 카테고리의 다른 글
autoreleasepool이란 무엇입니까? (0) | 2020.12.25 |
---|---|
AWK를 사용하여 여러 파일의 입력 처리 (0) | 2020.12.25 |
node.js에서 하나의 "npm test"명령으로 mocha 및 mocha-phantomjs 테스트를 실행하는 방법은 무엇입니까? (0) | 2020.12.25 |
Java 8 메서드 참조 처리되지 않은 예외 (0) | 2020.12.25 |
content_main.xml과 activity_main.xml의 차이점은 무엇입니까? (0) | 2020.12.25 |